diff --git a/NuGet.Config b/NuGet.Config index 08027d47f..1ef7e445d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,6 +1,16 @@  + + + + + + + + + + \ No newline at end of file diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index f9be2f979..d6f586903 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -718,6 +718,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TaskManagement.HttpApi.Client", "modules\task-management\LINGYUN.Abp.TaskManagement.HttpApi.Client\LINGYUN.Abp.TaskManagement.HttpApi.Client.csproj", "{72D54834-7ADF-4B18-A745-FCBBC255073B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "data-protection", "data-protection", "{F6A9D966-0022-440B-AE27-564A74CDED48}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.DataProtectionManagement.Domain.Shared", "modules\data-protection\LINGYUN.Abp.DataProtectionManagement.Domain.Shared\LINGYUN.Abp.DataProtectionManagement.Domain.Shared.csproj", "{8C99C96A-AE0C-489B-A1A0-AD8442A3B6A3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.DataProtectionManagement.Domain", "modules\data-protection\LINGYUN.Abp.DataProtectionManagement.Domain\LINGYUN.Abp.DataProtectionManagement.Domain.csproj", "{6C0DB8F2-FB0A-4922-B8FE-177DCF37A918}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore", "modules\data-protection\LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore\LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore.csproj", "{D73200F6-CBB3-4BA8-B9BF-7110AAF05596}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Wrapper", "framework\common\LINGYUN.Abp.AspNetCore.Wrapper\LINGYUN.Abp.AspNetCore.Wrapper.csproj", "{30FB6AD7-3CC5-4A8D-B170-BDA772E6BA3C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.DataProtectionManagement.Application.Contracts", "modules\data-protection\LINGYUN.Abp.DataProtectionManagement.Application.Contracts\LINGYUN.Abp.DataProtectionManagement.Application.Contracts.csproj", "{40D7A0A3-68BD-431E-A67A-E2A35508D55D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.DataProtectionManagement.Application", "modules\data-protection\LINGYUN.Abp.DataProtectionManagement.Application\LINGYUN.Abp.DataProtectionManagement.Application.csproj", "{8EA8C998-F81A-46E9-8C7E-C944D2503A0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.DataProtection.Abstractions", "framework\data-protection\LINGYUN.Abp.DataProtection.Abstractions\LINGYUN.Abp.DataProtection.Abstractions.csproj", "{47550AB9-FA06-42D6-A4B8-7DD12FE66563}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.DataProtectionManagement.HttpApi", "modules\data-protection\LINGYUN.Abp.DataProtectionManagement.HttpApi\LINGYUN.Abp.DataProtectionManagement.HttpApi.csproj", "{835E51CE-1E6B-4C8C-9736-8C5B61F5E08E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1824,6 +1842,38 @@ Global {72D54834-7ADF-4B18-A745-FCBBC255073B}.Debug|Any CPU.Build.0 = Debug|Any CPU {72D54834-7ADF-4B18-A745-FCBBC255073B}.Release|Any CPU.ActiveCfg = Release|Any CPU {72D54834-7ADF-4B18-A745-FCBBC255073B}.Release|Any CPU.Build.0 = Release|Any CPU + {8C99C96A-AE0C-489B-A1A0-AD8442A3B6A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C99C96A-AE0C-489B-A1A0-AD8442A3B6A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C99C96A-AE0C-489B-A1A0-AD8442A3B6A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C99C96A-AE0C-489B-A1A0-AD8442A3B6A3}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0DB8F2-FB0A-4922-B8FE-177DCF37A918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0DB8F2-FB0A-4922-B8FE-177DCF37A918}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0DB8F2-FB0A-4922-B8FE-177DCF37A918}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0DB8F2-FB0A-4922-B8FE-177DCF37A918}.Release|Any CPU.Build.0 = Release|Any CPU + {D73200F6-CBB3-4BA8-B9BF-7110AAF05596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D73200F6-CBB3-4BA8-B9BF-7110AAF05596}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D73200F6-CBB3-4BA8-B9BF-7110AAF05596}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D73200F6-CBB3-4BA8-B9BF-7110AAF05596}.Release|Any CPU.Build.0 = Release|Any CPU + {30FB6AD7-3CC5-4A8D-B170-BDA772E6BA3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30FB6AD7-3CC5-4A8D-B170-BDA772E6BA3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30FB6AD7-3CC5-4A8D-B170-BDA772E6BA3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30FB6AD7-3CC5-4A8D-B170-BDA772E6BA3C}.Release|Any CPU.Build.0 = Release|Any CPU + {40D7A0A3-68BD-431E-A67A-E2A35508D55D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40D7A0A3-68BD-431E-A67A-E2A35508D55D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40D7A0A3-68BD-431E-A67A-E2A35508D55D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40D7A0A3-68BD-431E-A67A-E2A35508D55D}.Release|Any CPU.Build.0 = Release|Any CPU + {8EA8C998-F81A-46E9-8C7E-C944D2503A0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EA8C998-F81A-46E9-8C7E-C944D2503A0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EA8C998-F81A-46E9-8C7E-C944D2503A0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EA8C998-F81A-46E9-8C7E-C944D2503A0A}.Release|Any CPU.Build.0 = Release|Any CPU + {47550AB9-FA06-42D6-A4B8-7DD12FE66563}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47550AB9-FA06-42D6-A4B8-7DD12FE66563}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47550AB9-FA06-42D6-A4B8-7DD12FE66563}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47550AB9-FA06-42D6-A4B8-7DD12FE66563}.Release|Any CPU.Build.0 = Release|Any CPU + {835E51CE-1E6B-4C8C-9736-8C5B61F5E08E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {835E51CE-1E6B-4C8C-9736-8C5B61F5E08E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {835E51CE-1E6B-4C8C-9736-8C5B61F5E08E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {835E51CE-1E6B-4C8C-9736-8C5B61F5E08E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2170,6 +2220,15 @@ Global {1E00BE51-A1AE-447D-B6E0-F28EC12B259A} = {77ED7922-BF30-4436-8A85-78F812583913} {61F0EEB2-5ED0-4809-8EF9-0676C7A680CE} = {77ED7922-BF30-4436-8A85-78F812583913} {72D54834-7ADF-4B18-A745-FCBBC255073B} = {77ED7922-BF30-4436-8A85-78F812583913} + {F6A9D966-0022-440B-AE27-564A74CDED48} = {D52D5A11-78EF-4154-8298-267738A6715B} + {8C99C96A-AE0C-489B-A1A0-AD8442A3B6A3} = {F6A9D966-0022-440B-AE27-564A74CDED48} + {6C0DB8F2-FB0A-4922-B8FE-177DCF37A918} = {F6A9D966-0022-440B-AE27-564A74CDED48} + {D73200F6-CBB3-4BA8-B9BF-7110AAF05596} = {F6A9D966-0022-440B-AE27-564A74CDED48} + {30FB6AD7-3CC5-4A8D-B170-BDA772E6BA3C} = {848F6760-9B11-4C9A-9843-9D71DD66D9DA} + {40D7A0A3-68BD-431E-A67A-E2A35508D55D} = {F6A9D966-0022-440B-AE27-564A74CDED48} + {8EA8C998-F81A-46E9-8C7E-C944D2503A0A} = {F6A9D966-0022-440B-AE27-564A74CDED48} + {47550AB9-FA06-42D6-A4B8-7DD12FE66563} = {529DF802-97C4-4BF2-BE7C-39663B3D9EA3} + {835E51CE-1E6B-4C8C-9736-8C5B61F5E08E} = {F6A9D966-0022-440B-AE27-564A74CDED48} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln index 326be95d8..0c9439676 100644 --- a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln +++ b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln @@ -24,6 +24,12 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C99728F6-FB3C-4D26-8917-1D30725209B9}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + ..\common.props = ..\common.props + ..\common.secrets.props = ..\common.secrets.props + ..\configureawait.props = ..\configureawait.props + ..\Directory.Build.props = ..\Directory.Build.props + ..\Directory.Packages.props = ..\Directory.Packages.props + ..\NuGet.Config = ..\NuGet.Config EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "provider", "provider", "{385578CC-C0F1-4377-A7A2-682B8F416234}" @@ -144,6 +150,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OssManagement.A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OssManagement.HttpApi.Client", "modules\oss-management\LINGYUN.Abp.OssManagement.HttpApi.Client\LINGYUN.Abp.OssManagement.HttpApi.Client.csproj", "{44778F3C-7610-4F1C-A2B6-DF8925B1CBE0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.BackgroundTasks.Tests", "tests\LINGYUN.Abp.BackgroundTasks.Tests\LINGYUN.Abp.BackgroundTasks.Tests.csproj", "{A8EFC95D-6700-4840-A7FD-1F5BF4D0C71C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TestsBase", "tests\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj", "{6CC06BD8-FA30-45E0-BD3A-25FF39906EF5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BackgroundTasks.Activities.Tests", "tests\LINGYUN.Abp.BackgroundTasks.Activities.Tests\LINGYUN.Abp.BackgroundTasks.Activities.Tests.csproj", "{3EBB4CA4-82C2-41C6-94C5-CB0D4D2B6D07}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -374,6 +386,18 @@ Global {44778F3C-7610-4F1C-A2B6-DF8925B1CBE0}.Debug|Any CPU.Build.0 = Debug|Any CPU {44778F3C-7610-4F1C-A2B6-DF8925B1CBE0}.Release|Any CPU.ActiveCfg = Release|Any CPU {44778F3C-7610-4F1C-A2B6-DF8925B1CBE0}.Release|Any CPU.Build.0 = Release|Any CPU + {A8EFC95D-6700-4840-A7FD-1F5BF4D0C71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8EFC95D-6700-4840-A7FD-1F5BF4D0C71C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8EFC95D-6700-4840-A7FD-1F5BF4D0C71C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8EFC95D-6700-4840-A7FD-1F5BF4D0C71C}.Release|Any CPU.Build.0 = Release|Any CPU + {6CC06BD8-FA30-45E0-BD3A-25FF39906EF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CC06BD8-FA30-45E0-BD3A-25FF39906EF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CC06BD8-FA30-45E0-BD3A-25FF39906EF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CC06BD8-FA30-45E0-BD3A-25FF39906EF5}.Release|Any CPU.Build.0 = Release|Any CPU + {3EBB4CA4-82C2-41C6-94C5-CB0D4D2B6D07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EBB4CA4-82C2-41C6-94C5-CB0D4D2B6D07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EBB4CA4-82C2-41C6-94C5-CB0D4D2B6D07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3EBB4CA4-82C2-41C6-94C5-CB0D4D2B6D07}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -435,6 +459,9 @@ Global {94D1C512-09E4-4A68-8989-6DB49FEABA67} = {F36E71F7-B05F-4513-A923-81E2A7474EAE} {96B4D255-BB21-4BAF-902A-ADE3F25A44C2} = {F36E71F7-B05F-4513-A923-81E2A7474EAE} {44778F3C-7610-4F1C-A2B6-DF8925B1CBE0} = {F36E71F7-B05F-4513-A923-81E2A7474EAE} + {A8EFC95D-6700-4840-A7FD-1F5BF4D0C71C} = {77341F31-F54C-436A-AF8D-F78D91303C45} + {6CC06BD8-FA30-45E0-BD3A-25FF39906EF5} = {77341F31-F54C-436A-AF8D-F78D91303C45} + {3EBB4CA4-82C2-41C6-94C5-CB0D4D2B6D07} = {77341F31-F54C-436A-AF8D-F78D91303C45} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E1FD1F4C-D344-408B-97CF-B6F1F6D7D293} diff --git a/aspnet-core/NuGet.Config b/aspnet-core/NuGet.Config index ec54fa98b..3f0e00340 100644 --- a/aspnet-core/NuGet.Config +++ b/aspnet-core/NuGet.Config @@ -1,7 +1,6 @@  - - - - + + + \ No newline at end of file diff --git a/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/LINGYUN/Abp/Authorization/OrganizationUnits/AbpOrganizationUnitClaimTypes.cs b/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/LINGYUN/Abp/Authorization/OrganizationUnits/AbpOrganizationUnitClaimTypes.cs index 2287adbbe..5802bd095 100644 --- a/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/LINGYUN/Abp/Authorization/OrganizationUnits/AbpOrganizationUnitClaimTypes.cs +++ b/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/LINGYUN/Abp/Authorization/OrganizationUnits/AbpOrganizationUnitClaimTypes.cs @@ -2,5 +2,5 @@ public static class AbpOrganizationUnitClaimTypes { - public static string OrganizationUnit { get; set; } = "organization_unit"; + public static string OrganizationUnit { get; set; } = "ou_code"; } diff --git a/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/System/Security/Principal/AbpClaimOrganizationUnitsExtensions.cs b/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/System/Security/Principal/AbpClaimOrganizationUnitsExtensions.cs index 72cf691d9..0106f7873 100644 --- a/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/System/Security/Principal/AbpClaimOrganizationUnitsExtensions.cs +++ b/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/System/Security/Principal/AbpClaimOrganizationUnitsExtensions.cs @@ -1,6 +1,5 @@ using JetBrains.Annotations; using LINGYUN.Abp.Authorization.OrganizationUnits; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; using Volo.Abp; @@ -9,26 +8,16 @@ namespace System.Security.Principal; public static class AbpClaimOrganizationUnitsExtensions { - public static Guid[] FindOrganizationUnits([NotNull] this ClaimsPrincipal principal) + public static string[] FindOrganizationUnits([NotNull] this ClaimsPrincipal principal) { Check.NotNull(principal, nameof(principal)); var userOusOrNull = principal.Claims?.Where(c => c.Type == AbpOrganizationUnitClaimTypes.OrganizationUnit); if (userOusOrNull == null || !userOusOrNull.Any()) { - return new Guid[0]; + return new string[0]; } - var userOus = new List(); - - foreach (var userOusClaim in userOusOrNull) - { - if (Guid.TryParse(userOusClaim.Value, out var guid)) - { - userOus.Add(guid); - } - } - - return userOus.ToArray(); + return userOusOrNull.Select(x => x.Value).ToArray(); } } diff --git a/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/Volo/Abp/Users/CurrentUserOrganizationUnitsExtensions.cs b/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/Volo/Abp/Users/CurrentUserOrganizationUnitsExtensions.cs index 4711f9ec7..838bca322 100644 --- a/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/Volo/Abp/Users/CurrentUserOrganizationUnitsExtensions.cs +++ b/aspnet-core/framework/authorization/LINGYUN.Abp.Authorization.OrganizationUnits/Volo/Abp/Users/CurrentUserOrganizationUnitsExtensions.cs @@ -2,29 +2,20 @@ using LINGYUN.Abp.Authorization.OrganizationUnits; using System; using System.Collections.Generic; +using System.Linq; namespace Volo.Abp.Users; public static class CurrentUserOrganizationUnitsExtensions { - public static Guid[] FindOrganizationUnits([NotNull] this ICurrentUser currentUser) + public static string[] FindOrganizationUnits([NotNull] this ICurrentUser currentUser) { var organizationUnits = currentUser.FindClaims(AbpOrganizationUnitClaimTypes.OrganizationUnit); if (organizationUnits.IsNullOrEmpty()) { - return new Guid[0]; + return new string[0]; } - var userOus = new List(); - - foreach (var userOusClaim in organizationUnits) - { - if (Guid.TryParse(userOusClaim.Value, out var guid)) - { - userOus.Add(guid); - } - } - - return userOus.ToArray(); + return organizationUnits.Select(x => x.Value).ToArray(); } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/FodyWeavers.xml b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/FodyWeavers.xml new file mode 100644 index 000000000..00e1d9a1c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/FodyWeavers.xsd b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/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/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj new file mode 100644 index 000000000..41542b6b4 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj @@ -0,0 +1,15 @@ + + + + + + + netstandard2.0 + + + + + + + + diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs new file mode 100644 index 000000000..dad08b9da --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; + +namespace LINGYUN.Abp.DataProtection; + +[DependsOn(typeof(AbpObjectExtendingModule))] +public class AbpDataProtectionAbstractionsModule : AbpModule +{ +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterGroup.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterGroup.cs new file mode 100644 index 000000000..31cbecc58 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterGroup.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace LINGYUN.Abp.DataProtection; + +[Serializable] +public class DataAccessFilterGroup +{ + public List Groups { get; set; } + public List Rules { get; set; } + public DataAccessFilterLogic Logic { get; set; } + + public DataAccessFilterGroup() : this(DataAccessFilterLogic.And) + { + } + + public DataAccessFilterGroup(DataAccessFilterLogic logic = DataAccessFilterLogic.And) + { + Logic = logic; + Rules = new List(); + Groups = new List(); + } + + public DataAccessFilterGroup AddRule(DataAccessFilterRule rule) + { + if (Rules.All(m => !m.Equals(rule))) + { + Rules.Add(rule); + } + + return this; + } + + public DataAccessFilterGroup AddRule(string field, object value, DataAccessFilterOperate operate = DataAccessFilterOperate.Equal) + { + return AddRule(new DataAccessFilterRule(field, value, operate)); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterLogic.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterLogic.cs new file mode 100644 index 000000000..f3bd98ae8 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterLogic.cs @@ -0,0 +1,19 @@ +using System.ComponentModel; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据过滤连接方式 +/// +public enum DataAccessFilterLogic +{ + /// + /// 且 + /// + [Description("且")] + And, + /// + /// 或 + /// + [Description("或")] + Or +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterOperate.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterOperate.cs new file mode 100644 index 000000000..844f4e424 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterOperate.cs @@ -0,0 +1,69 @@ +using System.ComponentModel; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据过滤操作 +/// +public enum DataAccessFilterOperate +{ + /// + /// 且 + /// + [Description("且")] + And = 1, + /// + /// 或 + /// + [Description("或")] + Or = 2, + /// + /// 等于 + /// + [Description("等于")] + Equal = 3, + /// + /// 不等于 + /// + [Description("不等于")] + NotEqual = 4, + /// + /// 小于 + /// + [Description("小于")] + Less = 5, + /// + /// 小于或等于 + /// + [Description("小于等于")] + LessOrEqual = 6, + /// + /// 大于 + /// + [Description("大于")] + Greater = 7, + /// + /// 大于或等于 + /// + [Description("大于等于")] + GreaterOrEqual = 8, + /// + /// 左包含 + /// + [Description("左包含")] + StartsWith = 9, + /// + /// 右包含 + /// + [Description("右包含")] + EndsWith = 10, + /// + /// 包含 + /// + [Description("包含")] + Contains = 11, + /// + /// 不包含 + /// + [Description("不包含")] + NotContains = 12, +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterRule.cs new file mode 100644 index 000000000..868e72bb1 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessFilterRule.cs @@ -0,0 +1,37 @@ +using System; + +namespace LINGYUN.Abp.DataProtection; + +[Serializable] +public class DataAccessFilterRule +{ + /// + /// 字段名称 + /// + public string Field { get; set; } + /// + /// 字段值 + /// + public object Value { get; set; } + /// + /// 操作类型 + /// + public DataAccessFilterOperate Operate { get; set; } + /// + /// 左侧条件 + /// + public bool IsLeft { get; set; } + + public DataAccessFilterRule() + { + + } + + public DataAccessFilterRule(string field, object value, DataAccessFilterOperate operate = DataAccessFilterOperate.Equal, bool isLeft = false) + { + Field = field; + Value = value; + Operate = operate; + IsLeft = isLeft; + } +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessKeywords.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessKeywords.cs new file mode 100644 index 000000000..8cb58adcc --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessKeywords.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.DataProtection; +/// +/// 系统保留关键字列表 +/// +public static class DataAccessKeywords +{ + /// + /// 授权角色 + /// + public const string AUTH_ROLES = "AR"; + /// + /// 授权组织机构 + /// + public const string AUTH_ORGS = "AO"; +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessOperation.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessOperation.cs new file mode 100644 index 000000000..9fdfcc500 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessOperation.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据操作 +/// +public enum DataAccessOperation +{ + /// + /// 查询 + /// + [Description("查询")] + Read, + /// + /// 更新 + /// + [Description("更新")] + Write, + /// + /// 删除 + /// + [Description("删除")] + Delete +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs new file mode 100644 index 000000000..27959a51b --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtection; + +[Serializable] +public class DataAccessResource +{ + /// + /// 权限主体 + /// + public string SubjectName { get; set; } + + /// + /// 权限主体标识 + /// + public string SubjectId { get; set; } + + /// + /// 实体类型全名 + /// + public string EntityTypeFullName { get; set; } + + /// + /// 数据权限操作 + /// + public DataAccessOperation Operation { get; set; } + + /// + /// 获取或设置 数据过滤规则 + /// + public DataAccessFilterGroup FilterGroup { get; set; } + + /// + /// 允许操作的属性列表 + /// + public List AllowProperties { get; set; } + + public DataAccessResource() + { + + } + + public DataAccessResource( + string subjectName, + string subjectId, + string entityTypeFullName, + DataAccessOperation operation, + DataAccessFilterGroup filterGroup = null) + { + SubjectName = subjectName; + SubjectId = subjectId; + EntityTypeFullName = entityTypeFullName; + Operation = operation; + FilterGroup = filterGroup; + AllowProperties = new List(); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs new file mode 100644 index 000000000..6de026f74 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace LINGYUN.Abp.DataProtection; + +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public class DataProtectedAttribute : Attribute +{ + public DataAccessOperation Operation { get; } + public DataProtectedAttribute() : this(DataAccessOperation.Read) + { + } + + public DataProtectedAttribute(DataAccessOperation operation) + { + Operation = operation; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs new file mode 100644 index 000000000..9c8731596 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace LINGYUN.Abp.DataProtection; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)] +public class DisableDataProtectedAttribute : Attribute +{ +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs new file mode 100644 index 000000000..2b3829e2c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Data; + +namespace LINGYUN.Abp.DataProtection; + +public interface IDataProtected : IHasExtraProperties +{ + +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtectedEnabled.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtectedEnabled.cs new file mode 100644 index 000000000..dc4942f0e --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtectedEnabled.cs @@ -0,0 +1,4 @@ +namespace LINGYUN.Abp.DataProtection; +public interface IDataProtectedEnabled +{ +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/DataProtectionResource.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/DataProtectionResource.cs new file mode 100644 index 000000000..fff292666 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/DataProtectionResource.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.DataProtection.Localization; + +[LocalizationResourceName("DataProtection")] +public class DataProtectionResource +{ +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedReadEntityInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedReadEntityInterceptor.cs new file mode 100644 index 000000000..b1f3e5b5f --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedReadEntityInterceptor.cs @@ -0,0 +1,64 @@ +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; +public class AbpDataProtectedReadEntityInterceptor : IQueryExpressionInterceptor, ITransientDependency +{ + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; + public IOptions DataProtectionOptions => LazyServiceProvider.LazyGetRequiredService>(); + public ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService(); + public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService(); + public IEntityTypeFilterBuilder EntityTypeFilterBuilder => LazyServiceProvider.LazyGetRequiredService(); + + private static readonly MethodInfo WhereMethodInfo = typeof(Queryable).GetMethods().First(m => m.Name == nameof(Queryable.Where)); + + public Expression QueryCompilationStarting(Expression queryExpression, QueryExpressionEventData eventData) + { + if (DataFilter.IsEnabled() && queryExpression.Type.GenericTypeArguments.Length > 0) + { + var entityType = queryExpression.Type.GenericTypeArguments[0]; + var exp = EntityTypeFilterBuilder.Build(entityType, DataAccessOperation.Read); + + return Expression.Call( + method: WhereMethodInfo.MakeGenericMethod(entityType), + arg0: queryExpression, + arg1: exp); + } + + return queryExpression; + } + + public class DataProtectedExpressionVisitor : ExpressionVisitor + { + private readonly Type _entityType; + private readonly IEntityTypeFilterBuilder _entityTypeFilterBuilder; + + public DataProtectedExpressionVisitor(Type entityType, IEntityTypeFilterBuilder entityTypeFilterBuilder) + { + _entityType = entityType; + _entityTypeFilterBuilder = entityTypeFilterBuilder; + } + + private static readonly MethodInfo WhereMethodInfo = typeof(Queryable).GetMethods().First(m => m.Name == nameof(Queryable.Where)); + + protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) + { + var method = WhereMethodInfo.MakeGenericMethod(_entityType); + var args0 = base.VisitMethodCall(methodCallExpression); + var args1 = _entityTypeFilterBuilder.Build(_entityType, DataAccessOperation.Read); + + return Expression.Call( + method: method, + arg0: args0, + arg1: args1); + } + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWriteEntityInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWriteEntityInterceptor.cs new file mode 100644 index 000000000..59b497734 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWriteEntityInterceptor.cs @@ -0,0 +1,66 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Authorization; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; +public class AbpDataProtectedWriteEntityInterceptor : SaveChangesInterceptor, ITransientDependency +{ + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; + public IOptions DataProtectionOptions => LazyServiceProvider.LazyGetRequiredService>(); + public ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService(); + public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService(); + public IDataAuthorizationService DataAuthorizationService => LazyServiceProvider.LazyGetRequiredService(); + + public async override ValueTask> SavingChangesAsync( + DbContextEventData eventData, + InterceptionResult result, + CancellationToken cancellationToken = default) + { + if (DataFilter.IsEnabled() && eventData.Context != null) + { + var updateEntites = eventData.Context.ChangeTracker.Entries() + .Where(entry => entry.State.IsIn(EntityState.Modified) && (entry.Entity is not ISoftDelete || entry.Entity is ISoftDelete delete && delete.IsDeleted == false)) + .Select(entry => entry.Entity as IEntity); + if (updateEntites.Any()) + { + var updateGrant = await DataAuthorizationService.AuthorizeAsync(DataAccessOperation.Write, updateEntites); + if (!updateGrant.Succeeded) + { + var entityKeys = updateEntites + .Select(entity => (entity is IEntity abpEntity ? abpEntity.GetKeys() : new string[1] { entity.ToString() }).ToString()) + .JoinAsString(";"); + throw new AbpAuthorizationException( + $"Delete data permission not granted to entity {updateEntites.First().GetType()} for data {entityKeys}!"); + } + } + + var deleteEntites = eventData.Context.ChangeTracker.Entries() + .Where(entry => entry.State.IsIn(EntityState.Deleted) || entry.Entity is ISoftDelete delete && delete.IsDeleted == true) + .Select(entry => entry.Entity as IEntity); + if (deleteEntites.Any()) + { + var deleteGrant = await DataAuthorizationService.AuthorizeAsync(DataAccessOperation.Delete, deleteEntites); + if (!deleteGrant.Succeeded) + { + var entityKeys = deleteEntites + .Select(entity => (entity is IEntity abpEntity ? abpEntity.GetKeys() : new string[1] { entity.ToString() }).ToString()) + .JoinAsString(";"); + throw new AbpAuthorizationException( + $"Delete data permission not granted to entity {deleteEntites.First().GetType()} for data {entityKeys}!"); + } + } + } + return await base.SavingChangesAsync(eventData, result, cancellationToken); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs new file mode 100644 index 000000000..fd64ab0c5 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs @@ -0,0 +1,52 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; +public class AbpDataProtectedWritePropertiesInterceptor : SaveChangesInterceptor, ITransientDependency +{ + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!; + public IOptions DataProtectionOptions => LazyServiceProvider.LazyGetRequiredService>(); + public ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService(); + public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService(); + + public async override ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) + { + if (DataFilter.IsEnabled() && eventData.Context != null) + { + foreach (var entry in eventData.Context.ChangeTracker.Entries().ToList()) + { + if (entry.State.IsIn(EntityState.Modified)) + { + var allowProperties = new List(); + var entity = entry.Entity; + var subjectContext = new DataAccessSubjectContributorContext(entity.GetType().FullName, DataAccessOperation.Write, LazyServiceProvider); + foreach (var contributor in DataProtectionOptions.Value.SubjectContributors) + { + var properties = contributor.GetAllowProperties(subjectContext); + allowProperties.AddIfNotContains(properties); + } + + allowProperties.AddIfNotContains(DataProtectionOptions.Value.IgnoreAuditedProperties); + + foreach (var property in entry.Properties) + { + if (!allowProperties.Contains(property.Metadata.Name)) + { + property.IsModified = false; + } + } + } + } + } + return await base.SavingChangesAsync(eventData, result, cancellationToken); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs index 1c8e0b466..09b24b506 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs @@ -1,145 +1,55 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; -using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using Volo.Abp.Domain.Entities; +using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; using Volo.Abp.Users; -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore -{ - public class AbpDataProtectionDbContext : AbpDbContext - { - protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService(); - - protected virtual bool IsDataAccessFilterEnabled => DataFilter?.IsEnabled() ?? false; - - public AbpDataProtectionDbContext( - DbContextOptions options) : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - foreach (var entityType in modelBuilder.Model.GetEntityTypes()) - { - if (typeof(IHasDataAccess).IsAssignableFrom(entityType.ClrType)) - { - modelBuilder.Entity(entityType.ClrType) - .OwnsOne(entityType.ClrType.FullName, nameof(IHasDataAccess.Owner), ownedNavigationBuilder => - { - ownedNavigationBuilder.ToJson(); - }); - } - } - } - - protected override void ApplyAbpConceptsForAddedEntity(EntityEntry entry) - { - base.ApplyAbpConceptsForAddedEntity(entry); - if (CurrentUser.IsAuthenticated) - { - if (entry is IHasDataAccess entity) - { - ProtectedEntityHelper.TrySetOwner( - entity, - () => new DataAccessOwner( - CurrentUser.Id, - CurrentUser.Roles, - CurrentUser.FindOrganizationUnits().Select(ou => ou.ToString()).ToArray())); - } - } - } +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; - protected virtual DataAccessRuleInfo AccessRuleInfo => UnitOfWorkManager.Current.GetAccessRuleInfo(); - - protected override void HandlePropertiesBeforeSave() - { - foreach (var item in ChangeTracker.Entries().ToList()) - { - HandleExtraPropertiesOnSave(item); - HandleCheckPropertiesOnSave(item); - if (item.State.IsIn(EntityState.Modified, EntityState.Deleted)) - { - UpdateConcurrencyStamp(item); - } - } - } +public abstract class AbpDataProtectionDbContext : AbpDbContext + where TDbContext : DbContext +{ + public IOptions DataProtectionOptions => LazyServiceProvider.LazyGetRequiredService>(); + public ICurrentUser CurrentUser => LazyServiceProvider.LazyGetRequiredService(); - protected virtual void HandleCheckPropertiesOnSave(EntityEntry entry) - { - // 仅当启用过滤器时检查 - if (IsDataAccessFilterEnabled) - { - var entityAccessRules = AccessRuleInfo?.Rules.Where(r => r.EntityTypeFullName == entry.Metadata.ClrType.FullName); - if (entityAccessRules != null) - { - if (entry.State.IsIn(EntityState.Modified, EntityState.Added, EntityState.Deleted)) - { - var entityAccessRule = entityAccessRules.FirstOrDefault(r => r.Operation.IsIn(DataAccessOperation.Write, DataAccessOperation.Delete)); - if (entityAccessRule != null) - { - if (entityAccessRule.Fileds.Count != 0) - { - var notAccessProps = entry.Properties.Where(p => !entityAccessRule.Fileds.Any(f => f.Field == p.Metadata.Name)); - if (notAccessProps != null) - { - foreach (var property in notAccessProps) - { - // 无字段权限不做变更 - property.CurrentValue = property.OriginalValue; - } - } - } - } - else - { - // 无实体变更权限不做修改 - entry.State = EntityState.Unchanged; - } - } - } - } - } + public AbpDataProtectionDbContext( + DbContextOptions options) : base(options) + { + } - protected override Expression> CreateFilterExpression() - { - var expression = base.CreateFilterExpression(); + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); - if (typeof(IHasDataAccess).IsAssignableFrom(typeof(TEntity))) - { - Expression> expression2 = (TEntity e) => !IsDataAccessFilterEnabled || CreateFilterExpression(e, AccessRuleInfo); - expression = (Expression>)((expression == null) ? ((LambdaExpression)expression2) : ((LambdaExpression)QueryFilterExpressionHelper.CombineExpressions(expression, expression2))); - } + // TODO: 需要优化表达式树 + // optionsBuilder.AddInterceptors(LazyServiceProvider.GetRequiredService()); + //optionsBuilder.AddInterceptors(LazyServiceProvider.GetRequiredService()); + optionsBuilder.AddInterceptors(LazyServiceProvider.GetRequiredService()); + } - return expression; - } + protected override void ApplyAbpConceptsForAddedEntity(EntityEntry entry) + { + base.ApplyAbpConceptsForAddedEntity(entry); + SetAuthorizationDataProperties(entry); + } - protected static bool CreateFilterExpression(TEntity entity, DataAccessRuleInfo accessRuleInfo) + protected virtual void SetAuthorizationDataProperties(EntityEntry entry) + { + if (entry.Entity is IDataProtected data) { - if (accessRuleInfo == null) + // TODO: 埋点, 以后可用EF.Functions查询 + if (data.GetProperty(DataAccessKeywords.AUTH_ROLES) == null) { - return true; + data.SetProperty(DataAccessKeywords.AUTH_ROLES, CurrentUser.Roles.Select(role => $"[{role}]").JoinAsString(",")); } - - if (!accessRuleInfo.Rules.Any(r => r.EntityTypeFullName == typeof(TEntity).FullName)) + if (data.GetProperty(DataAccessKeywords.AUTH_ORGS) == null) { - return false; + data.SetProperty(DataAccessKeywords.AUTH_ORGS, CurrentUser.FindOrganizationUnits().Select(ou => $"[{ou}]").JoinAsString(",")); } - - if (entity is not IHasDataAccess accessEntity) - { - return true; - } - - // TODO: 需要完成详细的过滤条件 - return false; } } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs new file mode 100644 index 000000000..1db3a21b1 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; +using System; +using Volo.Abp; + +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore +{ + public static class AbpDataProtectionDbContextModelBuilderExtensions + { + public static void ConfigureLocalization( + this ModelBuilder builder, + Action optionsAction = null) + { + Check.NotNull(builder, nameof(builder)); + } + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs index dfcc97027..46ac1c20f 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs @@ -1,12 +1,11 @@ using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Modularity; -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; + +[DependsOn( + typeof(AbpDataProtectionModule), + typeof(AbpEntityFrameworkCoreModule))] +public class AbpDataProtectionEntityFrameworkCoreModule : AbpModule { - [DependsOn( - typeof(AbpDataProtectionModule), - typeof(AbpEntityFrameworkCoreModule))] - public class AbpDataProtectionEntityFrameworkCoreModule : AbpModule - { - } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionModelBuilderConfigurationOptions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionModelBuilderConfigurationOptions.cs new file mode 100644 index 000000000..54400dd7f --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionModelBuilderConfigurationOptions.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore +{ + public class AbpDataProtectionModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions + { + public AbpDataProtectionModelBuilderConfigurationOptions( + [NotNull] string tablePrefix = "", + [CanBeNull] string schema = null) + : base( + tablePrefix, + schema) + { + + } + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionAsyncQueryableProvider.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionAsyncQueryableProvider.cs deleted file mode 100644 index 65a957292..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionAsyncQueryableProvider.cs +++ /dev/null @@ -1,358 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Query.Internal; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Linq; - -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore -{ - /// - /// TODO: 需要实现动态数据权限规则 - /// - [Dependency(ReplaceServices = true)] - public class DataProtectionAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonDependency - { - public bool CanExecute(IQueryable queryable) - { - return queryable.Provider is EntityQueryProvider; - } - - public Task ContainsAsync(IQueryable queryable, T item, CancellationToken cancellationToken = default) - { - return queryable.ContainsAsync(item, cancellationToken); - } - - public Task AnyAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AnyAsync(cancellationToken); - } - - public Task AnyAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.AnyAsync(predicate, cancellationToken); - } - - public Task AllAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.AllAsync(predicate, cancellationToken); - } - - public Task CountAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.CountAsync(cancellationToken); - } - - public Task CountAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.CountAsync(predicate, cancellationToken); - } - - public Task LongCountAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.LongCountAsync(cancellationToken); - } - - public Task LongCountAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.LongCountAsync(predicate, cancellationToken); - } - - public Task FirstAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.FirstAsync(cancellationToken); - } - - public Task FirstAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.FirstAsync(predicate, cancellationToken); - } - - public Task FirstOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.FirstOrDefaultAsync(cancellationToken); - } - - public Task FirstOrDefaultAsync(IQueryable queryable, Expression> predicate, - CancellationToken cancellationToken = default) - { - return queryable.FirstOrDefaultAsync(predicate, cancellationToken); - } - - public Task LastAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.LastAsync(cancellationToken); - } - - public Task LastAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.LastAsync(predicate, cancellationToken); - } - - public Task LastOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.LastOrDefaultAsync(cancellationToken); - } - - public Task LastOrDefaultAsync(IQueryable queryable, Expression> predicate, - CancellationToken cancellationToken = default) - { - return queryable.LastOrDefaultAsync(predicate, cancellationToken); - } - - public Task SingleAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SingleAsync(cancellationToken); - } - - public Task SingleAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - return queryable.SingleAsync(predicate, cancellationToken); - } - - public Task SingleOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SingleOrDefaultAsync(cancellationToken); - } - - public Task SingleOrDefaultAsync(IQueryable queryable, Expression> predicate, - CancellationToken cancellationToken = default) - { - return queryable.SingleOrDefaultAsync(predicate, cancellationToken); - } - - public Task MinAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.MinAsync(cancellationToken); - } - - public Task MinAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.MinAsync(selector, cancellationToken); - } - - public Task MaxAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.MaxAsync(cancellationToken); - } - - public Task MaxAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.MaxAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.SumAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - return queryable.AverageAsync(selector, cancellationToken); - } - - public Task> ToListAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.ToListAsync(cancellationToken); - } - - public Task ToArrayAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - return queryable.ToArrayAsync(cancellationToken); - } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs deleted file mode 100644 index f5bf7664d..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Infrastructure; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Metadata; -using System.Text; -using System.Threading.Tasks; -using Volo.Abp.Data; -using Volo.Abp.Domain.Entities; -using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.Users; - -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; -public class DataProtectionQueryExpressionInterceptor : IQueryExpressionInterceptor -{ - public Expression QueryCompilationStarting(Expression queryExpression, QueryExpressionEventData eventData) - { - var dataFilter = eventData.Context.GetService(); - var dbContextProvider = eventData.Context.GetService>(); - return new DataProtectionExpressionVisitor(dataFilter, dbContextProvider).Visit(queryExpression); - } - - public class DataProtectionExpressionVisitor : ExpressionVisitor - { - private readonly static MethodInfo WhereMethodInfo = typeof(Queryable).GetMethod(nameof(Queryable.Where)); - - - private readonly IDataFilter _dataFilter; - private readonly ICurrentUser _currentUser; - private readonly IDbContextProvider _dbContextProvider; - - public DataProtectionExpressionVisitor( - IDataFilter dataFilter, - IDbContextProvider dbContextProvider) - { - _dataFilter = dataFilter; - _dbContextProvider = dbContextProvider; - } - - protected override Expression VisitMethodCall(MethodCallExpression node) - { - if (_dataFilter.IsEnabled()) - { - var methodInfo = node!.Method; - if (methodInfo.DeclaringType == typeof(Queryable) - && methodInfo.Name == nameof(Queryable.Select) - && methodInfo.GetParameters().Length == 2) - { - var sourceType = node.Type.GetGenericArguments()[0]; - var lambdaExpression = (LambdaExpression)((UnaryExpression)node.Arguments[1]).Operand; - var entityParameterExpression = lambdaExpression.Parameters[0]; - - var rules = _currentUser.Roles; - var ous = _currentUser.FindOrganizationUnits(); - - var ownerParamter = Expression.PropertyOrField(entityParameterExpression, nameof(IHasDataAccess.Owner)); - - - if (typeof(IEntity).IsAssignableFrom(sourceType)) - { - // Join params[0] - // node - - - - - var test = Expression.Call( - method: WhereMethodInfo.MakeGenericMethod(sourceType, typeof(bool)), - arg0: base.VisitMethodCall(node), - arg1: Expression.Lambda( - typeof(Func<,>).MakeGenericType(entityParameterExpression.Type, typeof(bool)), - Expression.Property(entityParameterExpression, nameof(IHasDataAccess.Owner)), - true)); - return test; - } - - } - } - return base.VisitMethodCall(node); - } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionSaveChangesInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionSaveChangesInterceptor.cs deleted file mode 100644 index 28f47085d..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionSaveChangesInterceptor.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Auditing; -using Volo.Abp.Domain.Entities; -using Volo.Abp.EntityFrameworkCore; - -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; -public class DataProtectionSaveChangesInterceptor : SaveChangesInterceptor -{ - private readonly static EntityState[] _protectedStates = - [ - EntityState.Modified, - EntityState.Detached, - ]; - public async override ValueTask> SavingChangesAsync( - DbContextEventData eventData, - InterceptionResult result, - CancellationToken cancellationToken = default) - { - if (eventData.Context != null && eventData.Context is IAbpEfCoreDbContext) - { - // 存在资源所属者的实体将被检查访问权限 - var changeEntires = eventData.Context.ChangeTracker.Entries() - .Where(e => _protectedStates.Contains(e.State)) - .Where(e => e.Entity.CreatorId.HasValue); - - foreach (var changeEntity in changeEntires) - { - - } - } - // return InterceptionResult.SuppressWithResult(0); - return await base.SavingChangesAsync(eventData, result, cancellationToken); - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs new file mode 100644 index 000000000..b8617070c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs @@ -0,0 +1,156 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; + +public abstract class EfCoreDataProtectionRepository : + EfCoreRepository, + IDataProtectionRepository + where TDbContext : IEfCoreDbContext + where TEntity : class, IEntity +{ + private readonly IDataAuthorizationService _dataAuthorizationService; + private readonly IEntityTypeFilterBuilder _entityTypeFilterBuilder; + + protected EfCoreDataProtectionRepository( + [NotNull] IDbContextProvider dbContextProvider, + [NotNull] IDataAuthorizationService dataAuthorizationService, + [NotNull] IEntityTypeFilterBuilder entityTypeFilterBuilder) + : base(dbContextProvider) + { + _dataAuthorizationService = dataAuthorizationService; + _entityTypeFilterBuilder = entityTypeFilterBuilder; + } + + public async override Task> GetQueryableAsync() + { + var queryable = await base.GetQueryableAsync(); + + var dataAccessFilterExp = _entityTypeFilterBuilder.Build(DataAccessOperation.Read); + queryable = queryable.Where(dataAccessFilterExp); + + return queryable; + } + + public async override Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var dbSet = dbContext.Set(); + var entities = await dbSet.Where(predicate).ToListAsync(); + + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Delete, entities); + + await dbSet.Where(predicate).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + } + + public async override Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Delete, new TEntity[1] { entity }); + + await base.DeleteAsync(entity, autoSave, cancellationToken); + } + + public async override Task DeleteManyAsync(IEnumerable entities, bool autoSave = false, + CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Delete, entities); + + await base.DeleteManyAsync(entities, autoSave, cancellationToken); + } + + public async override Task UpdateAsync(TEntity entity, bool autoSave = false, + CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Write, new TEntity[1] { entity }); + + return await base.UpdateAsync(entity, autoSave, cancellationToken); + } + + public async override Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, + CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Write, entities); + + await base.UpdateManyAsync(entities, autoSave, cancellationToken); + } +} + +public abstract class EfCoreDataProtectionRepository : EfCoreRepository + where TDbContext : IEfCoreDbContext + where TEntity : class, IEntity +{ + private readonly IDataAuthorizationService _dataAuthorizationService; + private readonly IEntityTypeFilterBuilder _entityTypeFilterBuilder; + + protected EfCoreDataProtectionRepository( + [NotNull] IDbContextProvider dbContextProvider, + [NotNull] IDataAuthorizationService dataAuthorizationService, + [NotNull] IEntityTypeFilterBuilder entityTypeFilterBuilder) + : base(dbContextProvider) + { + _dataAuthorizationService = dataAuthorizationService; + _entityTypeFilterBuilder = entityTypeFilterBuilder; + } + + public async override Task> GetQueryableAsync() + { + var queryable = await base.GetQueryableAsync(); + + var dataAccessFilterExp = _entityTypeFilterBuilder.Build(DataAccessOperation.Read); + queryable = queryable.Where(dataAccessFilterExp); + + return queryable; + } + + public async override Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var dbSet = dbContext.Set(); + var entities = await dbSet.Where(predicate).ToListAsync(); + + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Delete, entities); + + await dbSet.Where(predicate).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + } + + public async override Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Delete, new TEntity[1] { entity }); + + await base.DeleteAsync(entity, autoSave, cancellationToken); + } + + public async override Task DeleteManyAsync(IEnumerable entities, bool autoSave = false, + CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Delete, entities); + + await base.DeleteManyAsync(entities, autoSave, cancellationToken); + } + + public async override Task UpdateAsync(TEntity entity, bool autoSave = false, + CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Write, new TEntity[1] { entity }); + + return await base.UpdateAsync(entity, autoSave, cancellationToken); + } + + public async override Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, + CancellationToken cancellationToken = default) + { + await _dataAuthorizationService.CheckAsync(DataAccessOperation.Write, entities); + + await base.UpdateManyAsync(entities, autoSave, cancellationToken); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs deleted file mode 100644 index ef6e8ed94..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using Volo.Abp; - -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore -{ - public static class ProtectedEntityHelper - { - public static void TrySetOwner( - IHasDataAccess protectedEntity, - Func ownerFactory) - { - ObjectHelper.TrySetProperty( - protectedEntity, - x => x.Owner, - ownerFactory, - new Type[] { }); - } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/README.md b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/README.md new file mode 100644 index 000000000..5297e2f52 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/README.md @@ -0,0 +1,104 @@ +# LINGYUN.Abp.DataProtection.EntityFrameworkCore + +数据权限EF实现模块 + +## 接口描述 + +* DisableDataProtectedAttribute: 通过拦截器自动实现DataFilter.Disable(),数据过滤器在当前范围将被禁用 + +## 注意事项 + +* 使用仓储接口尽量避免直接使用 *await GetDbSetAsync()*, 而是使用 *await GetQueryableAsync()*, 因为 **DbSet** 设计模式原因,暂无法对其进行处理 +* 您的仓库接口应继承自 **EfCoreDataProtectionRepository**, 您的 *DbContext* 应继承自 **AbpDataProtectionDbContext** + +## 配置使用 + +```csharp + +[DependsOn( + typeof(AbpDataProtectionEntityFrameworkCoreModule) + )] +public class YouProjectModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + // 受保护的实体列表持久化 + options.AddEntities(typeof(YouResource), new Type[] + { + typeof(YouProtectionObject), + }); + + // 如下格式 + // options.AddEntities(typeof(IdentityResource), new Type[] + // { + // typeof(IdentityUser), + // typeof(IdentityRole), + // typeof(OrganizationUnit), + // }); + }); + } +} + +public class YouDbContext : AbpDataProtectionDbContext +{ + public DbSet ProtectionObjects { get; set; } + public YouDbContext( + DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity(b => + { + // ... + }); + } +} + + +public class EfCoreYouProtectionObjectRepository : + EfCoreDataProtectionRepository, + IYouProtectionObjectRepository +{ + protected IDataFilter DataFilter { get; } + public EfCoreYouProtectionObjectRepository( + [NotNull] IDbContextProvider dbContextProvider, + [NotNull] IDataAuthorizationService dataAuthorizationService, + [NotNull] IEntityTypeFilterBuilder entityTypeFilterBuilder, + IDataFilter dataFilter) + : base(dbContextProvider, dataAuthorizationService, entityTypeFilterBuilder) + { + DataFilter = dataFilter; + } + + // 获取受保护的数据列表 + public async virtual Task> GetProtectedListAsync() + { + return await (await GetQueryableAsync()) + .ToListAsync(); + } + + // 标注 DisableDataProtected 获取全部数据列表, 通过拦截器自动处理 DataFilter.Disable() + [DisableDataProtected] + public async virtual Task> GetUnProtectedListAsync() + { + return await (await GetQueryableAsync()) + .ToListAsync(); + } + + // 禁用 IDataProtected 过滤器获取全部数据列表(可在任意地方使用) + public async virtual Task> GetUnProtectedByFilterListAsync() + { + using (DataFilter.Disable()) + { + return await (await GetQueryableAsync()) + .ToListAsync(); + } + } +} +``` + diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj index a7cb3454c..74a879b50 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj @@ -14,6 +14,7 @@ + diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs index 130460543..a1b59af62 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs @@ -1,10 +1,49 @@ -using Volo.Abp.Domain; +using LINGYUN.Abp.DataProtection.Keywords; +using LINGYUN.Abp.DataProtection.Localization; +using LINGYUN.Abp.DataProtection.Operations; +using LINGYUN.Abp.DataProtection.Subjects; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Domain; +using Volo.Abp.Localization; using Volo.Abp.Modularity; namespace LINGYUN.Abp.DataProtection; [DependsOn( + typeof(AbpDataProtectionAbstractionsModule), typeof(AbpDddDomainModule))] public class AbpDataProtectionModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + context.Services.OnRegistered(DataProtectedInterceptorRegistrar.RegisterIfNeeded); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.KeywordContributors.Add(DataAccessCurrentUserContributor.Name, new DataAccessCurrentUserContributor()); + + options.OperateContributors.Add(DataAccessFilterOperate.Equal, new DataAccessEqualContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.NotEqual, new DataAccessNotEqualContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.Less, new DataAccessLessContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.LessOrEqual, new DataAccessLessOrEqualContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.Greater, new DataAccessGreaterContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.GreaterOrEqual, new DataAccessGreaterOrEqualContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.StartsWith, new DataAccessStartsWithContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.EndsWith, new DataAccessEndsWithContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.Contains, new DataAccessContainsContributor()); + options.OperateContributors.Add(DataAccessFilterOperate.NotContains, new DataAccessNotContainsContributor()); + + options.SubjectContributors.Add(new DataAccessUserIdContributor()); + options.SubjectContributors.Add(new DataAccessRoleNameContributor()); + options.SubjectContributors.Add(new DataAccessOrganizationUnitContributor()); + }); + + Configure(options => + { + options.Resources.Add(); + }); + } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs new file mode 100644 index 000000000..9beede4f8 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Auditing; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.DataProtection; +public class AbpDataProtectionOptions +{ + /// + /// 是否启用数据审计 + /// 默认: true + /// + public bool IsEnabled { get; set; } + /// + /// 权限主体 + /// + public IList SubjectContributors { get; set; } + /// + /// 过滤字段关键字 + /// + public IDictionary KeywordContributors { get; set; } + /// + /// 数据操作 + /// + public IDictionary OperateContributors { get; set; } + /// + /// 忽略审计字段列表 + /// + public IList IgnoreAuditedProperties { get; set; } + public AbpDataProtectionOptions() + { + IsEnabled = true; + SubjectContributors = new List(); + KeywordContributors = new Dictionary(); + OperateContributors = new Dictionary(); + + IgnoreAuditedProperties = new List + { + nameof(IEntity.Id), + nameof(IAuditedObject.LastModifierId), + nameof(IAuditedObject.LastModificationTime), + nameof(IAuditedObject.CreatorId), + nameof(IAuditedObject.CreationTime), + nameof(IDeletionAuditedObject.IsDeleted), + nameof(IDeletionAuditedObject.DeleterId), + nameof(IDeletionAuditedObject.DeletionTime), + nameof(IMultiTenant.TenantId), + nameof(IHasEntityVersion.EntityVersion), + nameof(IHasConcurrencyStamp.ConcurrencyStamp), + nameof(IHasExtraProperties.ExtraProperties), + }; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessCacheItem.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessCacheItem.cs deleted file mode 100644 index 99f43c29c..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessCacheItem.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; - -namespace LINGYUN.Abp.DataProtection; -public class DataAccessCacheItem -{ - /// - /// 实体类型全名 - /// - public string EntityTypeFullName { get; set; } - /// - /// 数据访问操作 - /// - public DataAccessOperation Operation { get; set; } - /// - /// 数据访问角色 - /// - public DataAccessRole Role { get; set; } - /// - /// 资源访问者 - /// - public string Visitor { get; set; } - /// - /// 字段访问控制 - /// - public List Fileds { get; set; } - /// - /// 自定义表达式 - /// - public List Expressions { get; set; } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessEntityRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessEntityRule.cs deleted file mode 100644 index e786386c5..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessEntityRule.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LINGYUN.Abp.DataProtection; -/// -/// 数据访问实体控制 -/// -public class DataAccessEntityRule -{ - -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessExpressionRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessExpressionRule.cs deleted file mode 100644 index e4665ab8c..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessExpressionRule.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace LINGYUN.Abp.DataProtection; -/// -/// 数据访问控制规则:自定义表达式 -/// -public class DataAccessExpressionRule -{ - /// - /// 表达式 - /// - public virtual string Expression { get; protected set; } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessFiledRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessFiledRule.cs deleted file mode 100644 index 5b07d7ad9..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessFiledRule.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace LINGYUN.Abp.DataProtection; -/// -/// 数据访问控制规则:字段 -/// -public class DataAccessFiledRule -{ - /// - /// 字段名称 - /// - public virtual string Field { get; protected set; } - public DataAccessFiledRule() - { - } - - public DataAccessFiledRule(string field) - { - Field = field; - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs new file mode 100644 index 000000000..2cb849833 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs @@ -0,0 +1,11 @@ +using System; + +namespace LINGYUN.Abp.DataProtection; +public class DataAccessKeywordContributorContext +{ + public IServiceProvider ServiceProvider { get; } + public DataAccessKeywordContributorContext(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOperation.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOperation.cs deleted file mode 100644 index b0b2cbec1..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOperation.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace LINGYUN.Abp.DataProtection; -public enum DataAccessOperation -{ - Read, - Write, - Delete -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOwner.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOwner.cs deleted file mode 100644 index 4daad0b06..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOwner.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Linq; -using Volo.Abp.Auditing; - -namespace LINGYUN.Abp.DataProtection; -/// -/// 数据拥有者 -/// -public class DataAccessOwner : IMayHaveCreator -{ - public Guid? CreatorId { get; set; } - public string[] Roles { get; set; } - public string[] OrganizaztionUnits { get; set; } - protected DataAccessOwner() - { - } - - public DataAccessOwner(Guid? creatorId, string[] roles, string[] organizaztionUnits) - { - CreatorId = creatorId; - Roles = roles; - OrganizaztionUnits = organizaztionUnits; - } - - public bool IsInRole(string[] roles) - { - return Roles != null && Roles.Any(r => roles.Contains(r)); - } - - public bool IsInOrganizaztionUnit(string[] organizaztionUnits) - { - return OrganizaztionUnits != null && OrganizaztionUnits.Any(ou => organizaztionUnits.Contains(ou)); - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRole.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRole.cs deleted file mode 100644 index 75dd30252..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRole.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace LINGYUN.Abp.DataProtection; -/// -/// 数据访问角色 -/// -public enum DataAccessRole -{ - /// - /// 所有 - /// - All = 0, - /// - /// 用户 - /// - User = 1, - /// - /// 角色 - /// - Role = 2, - /// - /// 组织机构 - /// - OrganizationUnit = 3, -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRule.cs deleted file mode 100644 index b8255ddd6..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRule.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; - -namespace LINGYUN.Abp.DataProtection; -/// -/// 数据访问控制规则 -/// -public class DataAccessRule -{ - /// - /// 实体类型全名 - /// - public virtual string EntityTypeFullName { get; protected set; } - /// - /// 数据访问操作 - /// - public virtual DataAccessOperation Operation { get; protected set; } - /// - /// 数据访问角色 - /// - public virtual DataAccessRole Role { get; protected set; } - /// - /// 资源访问者 - /// - public virtual string Visitor { get; protected set; } - /// - /// 字段访问控制 - /// - public virtual List Fileds { get; protected set; } - /// - /// 自定义表达式 - /// - public virtual List Expressions { get; protected set; } - protected DataAccessRule() - { - Fileds = []; - Expressions = []; - } - - public DataAccessRule( - string entityTypeFullName, - DataAccessOperation operation = DataAccessOperation.Read, - DataAccessRole role = DataAccessRole.All, - string visitor = null, - List fileds = null, - List expressions = null) - { - EntityTypeFullName = entityTypeFullName; - Operation = operation; - Role = role; - Visitor = visitor; - Fileds = fileds ?? []; - Expressions = expressions ?? []; - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRuleInfo.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRuleInfo.cs deleted file mode 100644 index b62f66d6a..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRuleInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace LINGYUN.Abp.DataProtection; -public class DataAccessRuleInfo -{ - public List Rules { get; } - public DataAccessRuleInfo(List rules) - { - Rules = rules ?? new List(); - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessSubjectContributorContext.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessSubjectContributorContext.cs new file mode 100644 index 000000000..c19dad6f2 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessSubjectContributorContext.cs @@ -0,0 +1,18 @@ +using System; + +namespace LINGYUN.Abp.DataProtection; +public class DataAccessSubjectContributorContext +{ + public string EntityTypeFullName { get; } + public DataAccessOperation Operation { get; } + public IServiceProvider ServiceProvider { get; } + public DataAccessSubjectContributorContext( + string entityTypeFullName, + DataAccessOperation operation, + IServiceProvider serviceProvider) + { + EntityTypeFullName = entityTypeFullName; + Operation = operation; + ServiceProvider = serviceProvider; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthorizationService.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthorizationService.cs new file mode 100644 index 000000000..cda1d8878 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthorizationService.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Authorization; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.DataProtection; + +public class DataAuthorizationService : IDataAuthorizationService, ITransientDependency +{ + private readonly static MethodInfo AllMethod = typeof(Enumerable).GetMethod(nameof(Enumerable.All), BindingFlags.Public | BindingFlags.Static); + private readonly IEntityTypeFilterBuilder _entityTypeFilterBuilder; + + public DataAuthorizationService(IEntityTypeFilterBuilder entityTypeFilterBuilder) + { + _entityTypeFilterBuilder = entityTypeFilterBuilder; + } + + public virtual Task AuthorizeAsync(DataAccessOperation operation, IEnumerable entities) + { + if (!entities.Any()) + { + return Task.FromResult(AuthorizationResult.Success()); + } + + var exp = _entityTypeFilterBuilder.Build(operation); + + return Task.FromResult(entities.All(exp.Compile()) ? AuthorizationResult.Success() : AuthorizationResult.Failed()); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs new file mode 100644 index 000000000..850796ee4 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.Options; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; + +namespace LINGYUN.Abp.DataProtection; +public class DataProtectedInterceptor : AbpInterceptor, ITransientDependency +{ + private readonly IDataFilter _dataFilter; + private readonly AbpDataProtectionOptions _options; + + public DataProtectedInterceptor(IDataFilter dataFilter, IOptions options) + { + _dataFilter = dataFilter; + _options = options.Value; + } + + public async override Task InterceptAsync(IAbpMethodInvocation invocation) + { + if (ShouldDisableDataProtected(invocation, _options)) + { + using (_dataFilter.Disable()) + { + await invocation.ProceedAsync(); + return; + } + } + await invocation.ProceedAsync(); + } + + protected virtual bool ShouldDisableDataProtected( + IAbpMethodInvocation invocation, + AbpDataProtectionOptions options) + { + if (!options.IsEnabled) + { + return true; + } + + if (invocation.Method.IsDefined(typeof(DisableDataProtectedAttribute), true)) + { + return true; + } + + return false; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptorRegistrar.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptorRegistrar.cs new file mode 100644 index 000000000..3004d14f9 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptorRegistrar.cs @@ -0,0 +1,35 @@ +using System; +using System.Linq; +using System.Reflection; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; + +namespace LINGYUN.Abp.DataProtection; +public static class DataProtectedInterceptorRegistrar +{ + public static void RegisterIfNeeded(IOnServiceRegistredContext context) + { + if (ShouldIntercept(context.ImplementationType)) + { + context.Interceptors.TryAdd(); + } + } + + private static bool ShouldIntercept(Type type) + { + return !DynamicProxyIgnoreTypes.Contains(type) && + (typeof(IDataProtectedEnabled).IsAssignableFrom(type) || type.IsDefined(typeof(DataProtectedAttribute), true) || AnyMethodHasAuthorizeAttribute(type)); + } + + private static bool AnyMethodHasAuthorizeAttribute(Type implementationType) + { + return implementationType + .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .Any(HasAuthorizeAttribute); + } + + private static bool HasAuthorizeAttribute(MemberInfo methodInfo) + { + return methodInfo.IsDefined(typeof(DataProtectedAttribute), true); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs new file mode 100644 index 000000000..31fb45cdb --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs @@ -0,0 +1,141 @@ +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Auditing; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.DataProtection; +public class EntityPropertyResultBuilder : IEntityPropertyResultBuilder, ITransientDependency +{ + private readonly IDataFilter _dataFilter; + private readonly IServiceProvider _serviceProvider; + private readonly AbpDataProtectionOptions _options; + + public EntityPropertyResultBuilder( + IDataFilter dataFilter, + IServiceProvider serviceProvider, + IOptions options) + { + _options = options.Value; + _dataFilter = dataFilter; + _serviceProvider = serviceProvider; + } + + public virtual LambdaExpression Build(Type entityType, DataAccessOperation operation) + { + // Func + var func = typeof(Func<,>).MakeGenericType(entityType, entityType); + var param = Expression.Parameter(entityType, "e"); + LambdaExpression selector = Expression.Lambda(param, param); + if (!ShouldApplyFilter(entityType, operation)) + { + return selector; + } + + var typeName = entityType.FullName; + var allowProperties = new List(); + var subjectContext = new DataAccessSubjectContributorContext(typeName, operation, _serviceProvider); + foreach (var contributor in _options.SubjectContributors) + { + var properties = contributor.GetAllowProperties(subjectContext); + allowProperties.AddIfNotContains(properties); + } + + // 默认实体相关标识需要带上, 否则无法返回查询结果 + allowProperties.AddIfNotContains(_options.IgnoreAuditedProperties); + + if (!allowProperties.Any()) + { + return selector; + } + + var memberBindings = new List(); + foreach (var propertyName in allowProperties) + { + var propertyInfo = entityType.GetProperty(propertyName); + if (propertyInfo != null) + { + var propertyExpression = Expression.Property(param, propertyInfo); + memberBindings.Add(Expression.Bind(propertyInfo, propertyExpression)); + } + } + var newExpression = Expression.New(entityType); + var memberInitExpression = Expression.MemberInit(newExpression, memberBindings); + + return Expression.Lambda(func, memberInitExpression, param); + } + + public virtual Expression> Build(DataAccessOperation operation) + { + var entityType = typeof(TEntity); + Expression> selector = e => e; + + if (!ShouldApplyFilter(entityType, operation)) + { + return selector; + } + + var typeName = typeof(TEntity).FullName; + var allowProperties = new List(); + var subjectContext = new DataAccessSubjectContributorContext(typeName, operation, _serviceProvider); + foreach (var contributor in _options.SubjectContributors) + { + var properties = contributor.GetAllowProperties(subjectContext); + allowProperties.AddIfNotContains(properties); + } + + // 默认实体相关标识需要带上, 否则无法返回查询结果 + allowProperties.AddIfNotContains(_options.IgnoreAuditedProperties); + + if (!allowProperties.Any()) + { + return selector; + } + + var param = Expression.Parameter(typeof(TEntity), "e"); + var memberBindings = new List(); + foreach (var propertyName in allowProperties) + { + var propertyInfo = typeof(TEntity).GetProperty(propertyName); + if (propertyInfo != null) + { + var propertyExpression = Expression.Property(param, propertyInfo); + memberBindings.Add(Expression.Bind(propertyInfo, propertyExpression)); + } + } + var newExpression = Expression.New(typeof(TEntity)); + var memberInitExpression = Expression.MemberInit(newExpression, memberBindings); + + return Expression.Lambda>(memberInitExpression, param); + } + + private bool ShouldApplyFilter(Type entityType, DataAccessOperation operation) + { + if (!_dataFilter.IsEnabled()) + { + return false; + } + + if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true)) + { + return false; + } + + var dataProtected = entityType.GetCustomAttribute(); + + if (dataProtected != null && dataProtected.Operation != operation) + { + return false; + } + + return true; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs new file mode 100644 index 000000000..2e17bf9a1 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs @@ -0,0 +1,326 @@ +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Nodes; +using Volo.Abp; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.DataProtection; + +public class EntityTypeFilterBuilder : IEntityTypeFilterBuilder, ITransientDependency +{ + private readonly IDataFilter _dataFilter; + private readonly IServiceProvider _serviceProvider; + private readonly AbpDataProtectionOptions _options; + + public EntityTypeFilterBuilder( + IDataFilter dataFilter, + IServiceProvider serviceProvider, + IOptions options) + { + _options = options.Value; + _dataFilter = dataFilter; + _serviceProvider = serviceProvider; + } + + public virtual LambdaExpression Build(Type entityType, DataAccessOperation operation, DataAccessFilterGroup group = null) + { + // Func + var func = typeof(Func<,>).MakeGenericType(entityType, typeof(bool)); + // e => e + var param = Expression.Parameter(entityType, "e"); + // => true + var trueExp = Expression.Constant(true); + // Expression> exp = e => true; + var exp = Expression.Lambda(func, trueExp, param); + + if (!ShouldApplyFilter(entityType, operation)) + { + return exp; + } + + if (group != null) + { + exp = GetExpression(entityType, group); + } + + var typeName = entityType.FullName; + var subjectFilterGroups = new List(); + var subjectContext = new DataAccessSubjectContributorContext(typeName, operation, _serviceProvider); + foreach (var contributor in _options.SubjectContributors) + { + var subjectFilterGroup = contributor.GetFilterGroups(subjectContext); + subjectFilterGroups.AddRange(subjectFilterGroup); + } + + LambdaExpression subExp = null; + foreach (var subGroup in subjectFilterGroups) + { + subExp = subExp == null ? GetExpression(entityType, subGroup) : subExp.OrElse(func, GetExpression(entityType, subGroup)); + } + + if (subExp == null) + { + return exp; + } + + if (group == null) + { + return subExp; + } + exp = subExp.AndAlso(func, exp); + + return exp; + } + + public virtual Expression> Build(DataAccessOperation operation, DataAccessFilterGroup group = null) + { + var entityType = typeof(TEntity); + Expression> exp = _ => true; + + if (!ShouldApplyFilter(entityType, operation)) + { + return exp; + } + + if (group != null) + { + exp = GetExpression(group); + } + + var typeName = typeof(TEntity).FullName; + var subjectFilterGroups = new List(); + var subjectContext = new DataAccessSubjectContributorContext(typeName, operation, _serviceProvider); + foreach (var contributor in _options.SubjectContributors) + { + var subjectFilterGroup = contributor.GetFilterGroups(subjectContext); + subjectFilterGroups.AddRange(subjectFilterGroup); + } + + Expression> subExp = null; + foreach ( var subGroup in subjectFilterGroups) + { + subExp = subExp == null ? GetExpression(subGroup) : subExp.Or(GetExpression(subGroup)); + } + + if (subExp == null) + { + return exp; + } + + if (group == null) + { + return subExp; + } + exp = subExp.And(exp); + + return exp; + } + + protected virtual Expression> GetExpression(DataAccessFilterGroup group) + { + Check.NotNull(group, nameof(group)); + + var param = Expression.Parameter(typeof(TEntity), "e"); + var body = GetExpressionBody(param, group); + var expression = Expression.Lambda>(body, param); + return expression; + } + + protected virtual LambdaExpression GetExpression(Type entityType, DataAccessFilterGroup group) + { + Check.NotNull(group, nameof(group)); + + var func = typeof(Func<,>).MakeGenericType(entityType, typeof(bool)); + var param = Expression.Parameter(entityType, "e"); + var body = GetExpressionBody(param, group); + var expression = Expression.Lambda(func, body, param); + return expression; + } + + protected virtual Expression> GetExpression(DataAccessFilterRule rule) + { + Check.NotNull(rule, nameof(rule)); + + var param = Expression.Parameter(typeof(TEntity), "e"); + var body = GetExpressionBody(param, rule); + var expression = Expression.Lambda>(body, param); + return expression; + } + + protected virtual LambdaExpression GetExpression(Type entityType, DataAccessFilterRule rule) + { + Check.NotNull(rule, nameof(rule)); + + var func = typeof(Func<,>).MakeGenericType(entityType, typeof(bool)); + var param = Expression.Parameter(entityType, "e"); + var body = GetExpressionBody(param, rule); + + var expression = Expression.Lambda(func, body, param); + return expression; + } + + private Expression GetExpressionBody(ParameterExpression param, DataAccessFilterGroup group) + { + Check.NotNull(param, nameof(param)); + + if (group == null || (!group.Rules.Any() && !group.Groups.Any())) + { + return Expression.Constant(true); + } + var bodies = new List(); + bodies.AddRange(group.Rules.Select(rule => GetExpressionBody(param, rule))); + bodies.AddRange(group.Groups.Select(subGroup => GetExpressionBody(param, subGroup))); + + return group.Logic switch { + DataAccessFilterLogic.And => bodies.Aggregate(Expression.AndAlso), + DataAccessFilterLogic.Or => bodies.Aggregate(Expression.OrElse), + _ => throw new InvalidOperationException($"Not allowed filter logic: {group.Logic}") + }; + } + + private Expression GetExpressionBody(ParameterExpression param, DataAccessFilterRule rule) + { + if (!_options.OperateContributors.TryGetValue(rule.Operate, out var contributor)) + { + throw new InvalidOperationException($"Invalid data permission operator {rule.Operate}"); + } + if (rule == null) + { + return Expression.Constant(true); + } + var expression = GetPropertyLambdaExpression(param, rule); + if (expression == null) + { + return Expression.Constant(true); + } + var constant = ChangeTypeToExpression(rule, expression.Body.Type); + + return rule.IsLeft ? contributor.BuildExpression(constant, expression.Body) : contributor.BuildExpression(expression.Body, constant); + } + + private static LambdaExpression GetPropertyLambdaExpression(ParameterExpression param, DataAccessFilterRule rule) + { + var propertyNames = rule.Field.Split('.'); + Expression propertyAccess = param; + var type = param.Type; + for (var index = 0; index < propertyNames.Length; index++) + { + var propertyName = propertyNames[index]; + + var property = type.GetProperty(propertyName); + if (property == null) + { + throw new InvalidOperationException( + $"The specified property '{rule.Field}' does not exist in type '{type.FullName}'"); + } + + type = property.PropertyType; + if (index == propertyNames.Length - 1) + { + if (!CheckFilterRule(type, rule)) + { + return null; + } + } + + propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); + } + return Expression.Lambda(propertyAccess, param); + } + + private Expression ChangeTypeToExpression(DataAccessFilterRule rule, Type conversionType) + { + if (_options.KeywordContributors.TryGetValue(rule.Value?.ToString() ?? "", out var contributor)) + { + var context = new DataAccessKeywordContributorContext(_serviceProvider); + var keyValue = contributor.Contribute(context); + var value = CastTo(keyValue, conversionType); + return Expression.Constant(value, conversionType); + } + else + { + if (rule.Value is JsonElement element) + { + var valueArray = Array.CreateInstance(conversionType, element.GetArrayLength()); + var index = 0; + foreach (var node in element.EnumerateArray()) + { + var value = CastTo(node.ToString(), conversionType); + valueArray.SetValue(value, index); + index++; + } + var arrayType = typeof(IEnumerable<>).MakeGenericType(conversionType); + + return Expression.Constant(valueArray, arrayType); + } + + var valueType = rule.Value.GetType(); + + if (valueType.IsArrayOrListType()) + { + var arrayType = typeof(IEnumerable<>).MakeGenericType(conversionType); + return Expression.Constant(rule.Value, arrayType); + } + else + { + var value = CastTo(rule.Value, conversionType); + return Expression.Constant(value, conversionType); + } + } + } + + private bool ShouldApplyFilter(Type entityType, DataAccessOperation operation) + { + if (!_dataFilter.IsEnabled()) + { + return false; + } + + if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true)) + { + return false; + } + + var dataProtected = entityType.GetCustomAttribute(); + + if (dataProtected != null && dataProtected.Operation != operation) + { + return false; + } + + return true; + } + + + private static bool CheckFilterRule(Type type, DataAccessFilterRule rule) + { + if (rule.Value == null || rule.Value.ToString() == string.Empty) + { + rule.Value = null; + } + + return rule.Value switch { + null when (type == typeof(string) || type.IsNullableType()) => + rule.Operate == DataAccessFilterOperate.Equal || rule.Operate == DataAccessFilterOperate.NotEqual, + null => !type.IsValueType, + _ => true + }; + } + + private static object CastTo(object value, Type conversionType) + { + if (conversionType == typeof(Guid) || conversionType == typeof(Guid?)) + { + return TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(value.ToString()!)!; + } + return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessCache.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessCache.cs deleted file mode 100644 index 2244fcfda..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessCache.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LINGYUN.Abp.DataProtection; -public interface IDataAccessCache -{ -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs new file mode 100644 index 000000000..be985d265 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.DataProtection; +public interface IDataAccessKeywordContributor +{ + string Keyword { get; } + object Contribute(DataAccessKeywordContributorContext context); +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessOperateContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessOperateContributor.cs new file mode 100644 index 000000000..6c0d326d9 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessOperateContributor.cs @@ -0,0 +1,8 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection; +public interface IDataAccessOperateContributor +{ + DataAccessFilterOperate Operate { get; } + Expression BuildExpression(Expression left, Expression right); +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessSubjectContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessSubjectContributor.cs new file mode 100644 index 000000000..828c71cba --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessSubjectContributor.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtection; +public interface IDataAccessSubjectContributor +{ + string Name { get; } + List GetFilterGroups(DataAccessSubjectContributorContext context); + List GetAllowProperties(DataAccessSubjectContributorContext context); +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAuthorizationService.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAuthorizationService.cs new file mode 100644 index 000000000..5acfa7058 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAuthorizationService.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Authorization; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据权限验证服务 +/// +public interface IDataAuthorizationService +{ + /// + /// 验证操作实体数据权限 + /// + /// 数据权限操作 + /// 检查实体列表 + /// 实体类型 + /// + Task AuthorizeAsync(DataAccessOperation operation, IEnumerable entities); +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAuthorizationServiceExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAuthorizationServiceExtensions.cs new file mode 100644 index 000000000..6c415fec7 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAuthorizationServiceExtensions.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization; +using Volo.Abp.Domain.Entities; + +namespace LINGYUN.Abp.DataProtection; +public static class IDataAuthorizationServiceExtensions +{ + public static async Task CheckAsync(this IDataAuthorizationService dataAuthorizationService, DataAccessOperation operation, IEnumerable entities) + { + var result = await dataAuthorizationService.AuthorizeAsync(operation, entities); + if (!result.Succeeded) + { + var entityKeys = entities.Select(x => x.ToString()).JoinAsString(";"); + throw new AbpAuthorizationException( + $"The {operation} operation with entity type {typeof(Entity)} identified as {entityKeys} is not allowed!"); + } + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs new file mode 100644 index 000000000..b047482e9 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs @@ -0,0 +1,9 @@ +namespace LINGYUN.Abp.DataProtection; +public interface IDataProtectedResourceStore +{ + void Set(DataAccessResource resource); + + void Remove(DataAccessResource resource); + + DataAccessResource Get(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation); +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectionRepository.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectionRepository.cs new file mode 100644 index 000000000..950644037 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectionRepository.cs @@ -0,0 +1,8 @@ +using System.Linq; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.DataProtection; +public interface IDataProtectionRepository : IDataProtectedEnabled +{ + Task> GetQueryableAsync(); +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IEntityPropertyResultBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IEntityPropertyResultBuilder.cs new file mode 100644 index 000000000..f80a72b30 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IEntityPropertyResultBuilder.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 实体属性返回值构造器 +/// +public interface IEntityPropertyResultBuilder +{ + /// + /// 获取实体的属性返回值过滤表达式 + /// + /// 实体类型 + /// 数据操作方式 + /// + Expression> Build(DataAccessOperation operation); + /// + /// 获取实体的属性返回值过滤表达式 + /// + /// 实体类型 + /// 数据操作方式 + /// + LambdaExpression Build(Type entityType, DataAccessOperation operation); +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IEntityTypeFilterBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IEntityTypeFilterBuilder.cs new file mode 100644 index 000000000..01b54a625 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IEntityTypeFilterBuilder.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 实体过滤条件构造器 +/// +public interface IEntityTypeFilterBuilder +{ + /// + /// 获取实体的查询过滤表达式 + /// + /// 数据权限操作 + /// 查询条件组 + /// 实体类型 + /// + Expression> Build(DataAccessOperation operation, DataAccessFilterGroup group = null); + + LambdaExpression Build(Type entityType, DataAccessOperation operation, DataAccessFilterGroup group = null); +} \ No newline at end of file diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IHasDataAccess.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IHasDataAccess.cs deleted file mode 100644 index 1bbd73f8f..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IHasDataAccess.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace LINGYUN.Abp.DataProtection; -public interface IHasDataAccess -{ - public DataAccessOwner Owner { get; } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs new file mode 100644 index 000000000..91ad394dc --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Concurrent; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.DataProtection; + +[Dependency(ServiceLifetime.Singleton, TryRegister = true)] +public class InMemoryDataProtectedResourceStore : IDataProtectedResourceStore +{ + private readonly static ConcurrentDictionary _cache = new ConcurrentDictionary(); + public DataAccessResource Get(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation) + { + var key = NormalizeKey(subjectName, subjectId, entityTypeFullName, operation); + if (_cache.TryGetValue(key, out var resource)) + { + return resource; + } + return null; + } + + public void Remove(DataAccessResource resource) + { + var key = NormalizeKey(resource.SubjectName, resource.SubjectId, resource.EntityTypeFullName, resource.Operation); + _cache.TryRemove(key, out var _); + } + + public void Set(DataAccessResource resource) + { + var key = NormalizeKey(resource.SubjectName, resource.SubjectId, resource.EntityTypeFullName, resource.Operation); + _cache.TryAdd(key, resource); + } + + private static string NormalizeKey(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation) + { + return $"{subjectName}_{subjectId}_{entityTypeFullName}_{operation}"; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs new file mode 100644 index 000000000..50afda82e --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.Keywords; +public class DataAccessCurrentUserContributor : IDataAccessKeywordContributor +{ + public const string Name = "@CurrentUser"; + public string Keyword => Name; + + public object Contribute(DataAccessKeywordContributorContext context) + { + var currentUser = context.ServiceProvider.GetRequiredService(); + return currentUser.Id; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessContainsContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessContainsContributor.cs new file mode 100644 index 000000000..6460d8f38 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessContainsContributor.cs @@ -0,0 +1,33 @@ +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessContainsContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.Contains; + + public Expression BuildExpression(Expression left, Expression right) + { + if (left.Type == typeof(string)) + { + return Expression.Call(left, + typeof(string).GetMethod("Contains", new[] { typeof(string) }) + ?? throw new InvalidOperationException("The method named \"Contains\" does not exist"), + right); + } + + if (left.Type.IsArrayOrListType()) + { + var method = typeof(Enumerable).GetMethods().Where(x => x.Name == "Contains").FirstOrDefault(); + var methodType = method?.MakeGenericMethod(left.Type.GetGenericArguments()[0]); + return Expression.Call( + null, + methodType ?? throw new InvalidOperationException("The method named \"Contains\" does not exist"), + left, + right); + } + + throw new NotSupportedException("\"Contains\" only supports data of string or array type!"); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessEndsWithContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessEndsWithContributor.cs new file mode 100644 index 000000000..eb98b3262 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessEndsWithContributor.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessEndsWithContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.EndsWith; + + public Expression BuildExpression(Expression left, Expression right) + { + if (left.Type != typeof(string)) + { + throw new NotSupportedException("\"EndsWith\" only supports data of string type!"); + } + return Expression.Call(left, + typeof(string).GetMethod("EndsWith", new[] { typeof(string) }) + ?? throw new InvalidOperationException("The method named \"EndsWith\" does not exist!"), + right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessEqualContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessEqualContributor.cs new file mode 100644 index 000000000..39c9b182d --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessEqualContributor.cs @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessEqualContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.Equal; + + public Expression BuildExpression(Expression left, Expression right) + { + return Expression.Equal(left, right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessGreaterContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessGreaterContributor.cs new file mode 100644 index 000000000..1fa783ec2 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessGreaterContributor.cs @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessGreaterContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.Greater; + + public Expression BuildExpression(Expression left, Expression right) + { + return Expression.GreaterThan(left, right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessGreaterOrEqualContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessGreaterOrEqualContributor.cs new file mode 100644 index 000000000..589f4e493 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessGreaterOrEqualContributor.cs @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessGreaterOrEqualContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.GreaterOrEqual; + + public Expression BuildExpression(Expression left, Expression right) + { + return Expression.GreaterThanOrEqual(left, right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessLessContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessLessContributor.cs new file mode 100644 index 000000000..ecc85b7dd --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessLessContributor.cs @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessLessContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.Less; + + public Expression BuildExpression(Expression left, Expression right) + { + return Expression.LessThan(left, right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessLessOrEqualContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessLessOrEqualContributor.cs new file mode 100644 index 000000000..8df1e488c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessLessOrEqualContributor.cs @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessLessOrEqualContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.LessOrEqual; + + public Expression BuildExpression(Expression left, Expression right) + { + return Expression.LessThanOrEqual(left, right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessNotContainsContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessNotContainsContributor.cs new file mode 100644 index 000000000..0a1aee0ce --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessNotContainsContributor.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessNotContainsContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.NotContains; + + public Expression BuildExpression(Expression left, Expression right) + { + + if (left.Type == typeof(string)) + { + // string.Contains(string); + return Expression.Not(Expression.Call(left, + typeof(string).GetMethod("Contains", new[] { typeof(string) }) + ?? throw new InvalidOperationException("The method named \"NotContains\" does not exist"), + right)); + } + + if (left.Type.IsArrayOrListType()) + { + // IEnumerable.Contains(T); + var method = typeof(Enumerable).GetMethods().Where(x => x.Name == "Contains").FirstOrDefault(); + var methodType = method?.MakeGenericMethod(left.Type.GetGenericArguments()[0]); + return Expression.Not(Expression.Call( + null, + methodType ?? throw new InvalidOperationException("The method named \"NotContains\" does not exist"), + left, + right)); + } + + throw new NotSupportedException("\"NotContains\" only supports data of string or array type!"); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessNotEqualContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessNotEqualContributor.cs new file mode 100644 index 000000000..75afb2286 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessNotEqualContributor.cs @@ -0,0 +1,12 @@ +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessNotEqualContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.NotEqual; + + public Expression BuildExpression(Expression left, Expression right) + { + return Expression.NotEqual(left, right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessStartsWithContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessStartsWithContributor.cs new file mode 100644 index 000000000..042e5368c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Operations/DataAccessStartsWithContributor.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq.Expressions; + +namespace LINGYUN.Abp.DataProtection.Operations; +public class DataAccessStartsWithContributor : IDataAccessOperateContributor +{ + public DataAccessFilterOperate Operate => DataAccessFilterOperate.StartsWith; + + public Expression BuildExpression(Expression left, Expression right) + { + if (left.Type != typeof(string)) + { + throw new NotSupportedException("\"StartsWith\" only supports data of string type!"); + } + return Expression.Call(left, + typeof(string).GetMethod("StartsWith", new[] { typeof(string) }) + ?? throw new InvalidOperationException("The method named \"StartsWith\" does not exist!"), + right); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs new file mode 100644 index 000000000..202012f76 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs @@ -0,0 +1,52 @@ +using LINGYUN.Abp.Authorization.Permissions; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.Subjects; + +public class DataAccessOrganizationUnitContributor : IDataAccessSubjectContributor +{ + public string Name => OrganizationUnitPermissionValueProvider.ProviderName; + + public virtual List GetFilterGroups(DataAccessSubjectContributorContext context) + { + var groups = new List(); + var currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.IsAuthenticated) + { + var resourceStore = context.ServiceProvider.GetRequiredService(); + var orgCodes = currentUser.FindOrganizationUnits(); + foreach (var orgCode in orgCodes) + { + var resource = resourceStore.Get(Name, orgCode, context.EntityTypeFullName, context.Operation); + if (resource?.FilterGroup != null) + { + groups.Add(resource.FilterGroup); + } + } + } + return groups; + } + + public virtual List GetAllowProperties(DataAccessSubjectContributorContext context) + { + var allowProperties = new List(); + var currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.IsAuthenticated) + { + var resourceStore = context.ServiceProvider.GetRequiredService(); + var orgCodes = currentUser.FindOrganizationUnits(); + foreach (var orgCode in orgCodes) + { + var resource = resourceStore.Get(Name, orgCode, context.EntityTypeFullName, context.Operation); + if (resource?.AllowProperties.Any() == true) + { + allowProperties.AddIfNotContains(resource.AllowProperties); + } + } + } + return allowProperties; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs new file mode 100644 index 000000000..e2ab6e523 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.Subjects; + +public class DataAccessRoleNameContributor : IDataAccessSubjectContributor +{ + public string Name => RolePermissionValueProvider.ProviderName; + + public virtual List GetFilterGroups(DataAccessSubjectContributorContext context) + { + var groups = new List(); + var currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.IsAuthenticated) + { + var resourceStore = context.ServiceProvider.GetRequiredService(); + var roles = currentUser.Roles; + foreach (var role in roles) + { + var resource = resourceStore.Get(Name, role, context.EntityTypeFullName, context.Operation); + if (resource?.FilterGroup != null) + { + groups.Add(resource.FilterGroup); + } + } + } + return groups; + } + + public virtual List GetAllowProperties(DataAccessSubjectContributorContext context) + { + var allowProperties = new List(); + var currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.IsAuthenticated) + { + var resourceStore = context.ServiceProvider.GetRequiredService(); + var roles = currentUser.Roles; + foreach (var role in roles) + { + var resource = resourceStore.Get(Name, role, context.EntityTypeFullName, context.Operation); + if (resource?.AllowProperties.Any() == true) + { + allowProperties.AddIfNotContains(resource.AllowProperties); + } + } + } + return allowProperties; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs new file mode 100644 index 000000000..ff0219f53 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.DataProtection.Subjects; + +public class DataAccessUserIdContributor : IDataAccessSubjectContributor +{ + public string Name => UserPermissionValueProvider.ProviderName; + + public virtual List GetFilterGroups(DataAccessSubjectContributorContext context) + { + var groups = new List(); + var currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.IsAuthenticated) + { + var resourceStore = context.ServiceProvider.GetRequiredService(); + var resource = resourceStore.Get(Name, currentUser.Id.ToString(), context.EntityTypeFullName, context.Operation); + if (resource?.FilterGroup != null) + { + groups.Add(resource.FilterGroup); + } + } + return groups; + } + + public virtual List GetAllowProperties(DataAccessSubjectContributorContext context) + { + var allowProperties = new List(); + var currentUser = context.ServiceProvider.GetRequiredService(); + if (currentUser.IsAuthenticated) + { + var resourceStore = context.ServiceProvider.GetRequiredService(); + var resource = resourceStore.Get(Name, currentUser.Id.ToString(), context.EntityTypeFullName, context.Operation); + if (resource?.AllowProperties.Any() == true) + { + allowProperties.AddIfNotContains(resource.AllowProperties); + } + } + return allowProperties; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtender.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtender.cs new file mode 100644 index 000000000..d0cafb9db --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtender.cs @@ -0,0 +1,73 @@ +namespace System.Linq.Expressions; +internal static class ExpressionFuncExtender +{ + internal static Expression Compose(this Expression first, Expression second, + Func merge) + { + // build parameter map (from parameters of second to parameters of first) + var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }) + .ToDictionary(p => p.s, p => p.f); + + // replace parameters in the second lambda expression with parameters from the first + var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); + + // apply composition of lambda expression bodies to parameters from the first expression + return Expression.Lambda(merge(first.Body, secondBody), first.Parameters); + } + + internal static LambdaExpression Compose(this LambdaExpression first, + Type delegateType, + LambdaExpression second, + Func merge) + { + // build parameter map (from parameters of second to parameters of first) + var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }) + .ToDictionary(p => p.s, p => p.f); + + // replace parameters in the second lambda expression with parameters from the first + var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); + + // apply composition of lambda expression bodies to parameters from the first expression + return Expression.Lambda(delegateType, merge(first.Body, secondBody), first.Parameters); + } + + /// + /// Combines two given expressions by using the AND semantics. + /// + /// The type of the object. + /// The first part of the expression. + /// The second part of the expression. + /// The combined expression. + public static LambdaExpression AndAlso(this LambdaExpression first, + Type delegateType, + LambdaExpression second) + { + return first.Compose(delegateType, second, Expression.AndAlso); + } + + public static Expression> AndAlso(this Expression> first, + Expression> second) + { + return first.Compose(second, Expression.AndAlso); + } + + /// + /// Combines two given expressions by using the OR semantics. + /// + /// The type of the object. + /// The first part of the expression. + /// The second part of the expression. + /// The combined expression. + public static LambdaExpression OrElse(this LambdaExpression first, + Type delegateType, + LambdaExpression second) + { + return first.Compose(delegateType, second, Expression.OrElse); + } + + public static Expression> OrElse(this Expression> first, + Expression> second) + { + return first.Compose(second, Expression.OrElse); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtensions.cs new file mode 100644 index 000000000..5e34863ef --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtensions.cs @@ -0,0 +1,30 @@ +namespace System.Linq.Expressions; + +public static class ExpressionFuncExtensions +{ + public static Expression> AndIf( + this Expression> first, + bool condition, + Expression> second) + { + if (condition) + { + return ExpressionFuncExtender.AndAlso(first, second); + } + + return first; + } + + public static Expression> OrIf( + this Expression> first, + bool condition, + Expression> second) + { + if (condition) + { + return ExpressionFuncExtender.OrElse(first, second); + } + + return first; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ParameterRebinder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ParameterRebinder.cs new file mode 100644 index 000000000..a3588c947 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ParameterRebinder.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace System.Linq.Expressions; +internal class ParameterRebinder : ExpressionVisitor +{ + private readonly Dictionary _map; + + internal ParameterRebinder(Dictionary map) + { + _map = map ?? new Dictionary(); + } + + internal static Expression ReplaceParameters(Dictionary map, + Expression exp) + { + return new ParameterRebinder(map).Visit(exp); + } + + protected override Expression VisitParameter(ParameterExpression p) + { + if (_map.TryGetValue(p, out var replacement)) + { + p = replacement; + } + + return base.VisitParameter(p); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Reflection/NullableTypeExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Reflection/NullableTypeExtensions.cs new file mode 100644 index 000000000..66f89f104 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Reflection/NullableTypeExtensions.cs @@ -0,0 +1,16 @@ +using System; + +namespace System.Reflection; + +internal static class NullableTypeExtensions +{ + public static bool IsNullableType(this Type theType) + { + return theType.IsGenericType(typeof(Nullable<>)); + } + + public static bool IsGenericType(this Type type, Type genericType) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == genericType; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/TypeExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/TypeExtensions.cs new file mode 100644 index 000000000..037e303a8 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/TypeExtensions.cs @@ -0,0 +1,28 @@ +using System.Collections; + +namespace System; +internal static class TypeExtensions +{ + public static bool IsArrayOrListType(this Type type) + { + if (type.IsArray) + { + return true; + } + + if (type.IsGenericType) + { + if (typeof(IList).IsAssignableFrom(type)) + { + return true; + } + + if (typeof(IEnumerable).IsAssignableFrom(type)) + { + return true; + } + } + + return false; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/Volo/Abp/Uow/IUnitOfWorkDataAccessExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/Volo/Abp/Uow/IUnitOfWorkDataAccessExtensions.cs deleted file mode 100644 index 18a6afcba..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/Volo/Abp/Uow/IUnitOfWorkDataAccessExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using LINGYUN.Abp.DataProtection; - -namespace Volo.Abp.Uow; -public static class IUnitOfWorkDataAccessExtensions -{ - private const string DataAccessRuleKey = "LINGYUN.Abp.DataProtection.DataAccess"; - - public static IUnitOfWork SetAccessRuleInfo( - this IUnitOfWork unitOfWork, - DataAccessRuleInfo dataAccessRuleInfo) - { - unitOfWork.RemoveItem(DataAccessRuleKey); - unitOfWork.AddItem(DataAccessRuleKey, dataAccessRuleInfo); - - return unitOfWork; - } - - public static DataAccessRuleInfo GetAccessRuleInfo( - this IUnitOfWork unitOfWork) - { - return unitOfWork.GetItemOrDefault(DataAccessRuleKey) - ?? new DataAccessRuleInfo(null); - } -} diff --git a/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/LanguageAppService.cs b/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/LanguageAppService.cs index d5c1b58af..730736158 100644 --- a/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/LanguageAppService.cs +++ b/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/LanguageAppService.cs @@ -1,17 +1,12 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Localization; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; using System.Threading.Tasks; -using Volo.Abp; -using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Localization; -using Volo.Abp.Localization.External; namespace LINGYUN.Abp.AspNetCore.Mvc.Localization { diff --git a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/BackendAdminMigrationsDbContext.cs b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/BackendAdminMigrationsDbContext.cs index 2b08280f2..88a54cf9c 100644 --- a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/BackendAdminMigrationsDbContext.cs +++ b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/BackendAdminMigrationsDbContext.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.Saas.EntityFrameworkCore; +using LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; +using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.TextTemplating.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Volo.Abp.Data; @@ -27,5 +28,6 @@ public class BackendAdminMigrationsDbContext : AbpDbContext + diff --git a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515073346_Add-Data-Protected-Module.Designer.cs b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515073346_Add-Data-Protected-Module.Designer.cs new file mode 100644 index 000000000..d63a7caf3 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515073346_Add-Data-Protected-Module.Designer.cs @@ -0,0 +1,932 @@ +// +using System; +using LY.MicroService.BackendAdmin.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(BackendAdminMigrationsDbContext))] + [Migration("20240515073346_Add-Data-Protected-Module")] + partial class AddDataProtectedModule + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("char(36)"); + + b.Property("ValueRange") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("ValueRange"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Editions.Edition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.ToTable("AbpEditions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisableTime") + .HasColumnType("datetime(6)"); + + b.Property("EditionId") + .HasColumnType("char(36)"); + + b.Property("EnableTime") + .HasColumnType("datetime(6)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("NormalizedName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("EditionId"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpTenants", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Content") + .HasMaxLength(1048576) + .HasColumnType("longtext") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Culture") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Culture"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("DisplayName"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Name"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name") + .HasDatabaseName("IX_Tenant_Text_Template_Name"); + + b.ToTable("AbpTextTemplates", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplateDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultCultureName") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("DefaultCultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsInlineLocalized") + .HasColumnType("tinyint(1)"); + + b.Property("IsLayout") + .HasColumnType("tinyint(1)"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Layout") + .HasMaxLength(60) + .HasColumnType("varchar(60)") + .HasColumnName("Layout"); + + b.Property("LocalizationResourceName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("LocalizationResourceName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Name"); + + b.Property("RenderEngine") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("RenderEngine"); + + b.HasKey("Id"); + + b.ToTable("AbpTextTemplateDefinitions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("tinyint(1)"); + + b.Property("IsVisibleToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatures", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpFeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint unsigned"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("tinyint(1)"); + + b.Property("IsInherited") + .HasColumnType("tinyint(1)"); + + b.Property("IsVisibleToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "TypeInfo") + .WithMany("Properties") + .HasForeignKey("TypeInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition") + .WithMany() + .HasForeignKey("EditionId"); + + b.Navigation("Edition"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.HasOne("LINGYUN.Abp.Saas.Tenants.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515073346_Add-Data-Protected-Module.cs b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515073346_Add-Data-Protected-Module.cs new file mode 100644 index 000000000..fd5da263a --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515073346_Add-Data-Protected-Module.cs @@ -0,0 +1,179 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations +{ + /// + public partial class AddDataProtectedModule : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpAuthEntitites", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Name = table.Column(type: "varchar(64)", maxLength: 64, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + DisplayName = table.Column(type: "varchar(128)", maxLength: 128, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + TypeFullName = table.Column(type: "varchar(256)", maxLength: 256, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + IsAuditEnabled = table.Column(type: "tinyint(1)", nullable: false), + ExtraProperties = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ConcurrencyStamp = table.Column(type: "varchar(40)", maxLength: 40, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + CreationTime = table.Column(type: "datetime(6)", nullable: false), + CreatorId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + LastModificationTime = table.Column(type: "datetime(6)", nullable: true), + LastModifierId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuthEntitites", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "AbpAuthEntityProperties", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Name = table.Column(type: "varchar(64)", maxLength: 64, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + DisplayName = table.Column(type: "varchar(128)", maxLength: 128, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + TypeFullName = table.Column(type: "varchar(256)", maxLength: 256, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ValueRange = table.Column(type: "varchar(512)", maxLength: 512, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + TypeInfoId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuthEntityProperties", x => x.Id); + table.ForeignKey( + name: "FK_AbpAuthEntityProperties_AbpAuthEntitites_TypeInfoId", + column: x => x.TypeInfoId, + principalTable: "AbpAuthEntitites", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "AbpAuthOrganizationUnitEntityRules", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + OrgId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + OrgCode = table.Column(type: "varchar(128)", maxLength: 128, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ExtraProperties = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ConcurrencyStamp = table.Column(type: "varchar(40)", maxLength: 40, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + CreationTime = table.Column(type: "datetime(6)", nullable: false), + CreatorId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + LastModificationTime = table.Column(type: "datetime(6)", nullable: true), + LastModifierId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + IsEnabled = table.Column(type: "tinyint(1)", nullable: false), + Operation = table.Column(type: "int", nullable: false), + FilterGroup = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + EntityTypeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + EntityTypeFullName = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuthOrganizationUnitEntityRules", x => x.Id); + table.ForeignKey( + name: "FK_AbpAuthOrganizationUnitEntityRules_AbpAuthEntitites_EntityTy~", + column: x => x.EntityTypeId, + principalTable: "AbpAuthEntitites", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "AbpAuthRoleEntityRules", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + RoleId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + RoleName = table.Column(type: "varchar(256)", maxLength: 256, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ExtraProperties = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ConcurrencyStamp = table.Column(type: "varchar(40)", maxLength: 40, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + CreationTime = table.Column(type: "datetime(6)", nullable: false), + CreatorId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + LastModificationTime = table.Column(type: "datetime(6)", nullable: true), + LastModifierId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + IsEnabled = table.Column(type: "tinyint(1)", nullable: false), + Operation = table.Column(type: "int", nullable: false), + FilterGroup = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + EntityTypeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + EntityTypeFullName = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_AbpAuthRoleEntityRules", x => x.Id); + table.ForeignKey( + name: "FK_AbpAuthRoleEntityRules_AbpAuthEntitites_EntityTypeId", + column: x => x.EntityTypeId, + principalTable: "AbpAuthEntitites", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuthEntitites_TypeFullName", + table: "AbpAuthEntitites", + column: "TypeFullName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuthEntityProperties_TypeInfoId_TypeFullName", + table: "AbpAuthEntityProperties", + columns: new[] { "TypeInfoId", "TypeFullName" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuthOrganizationUnitEntityRules_EntityTypeId", + table: "AbpAuthOrganizationUnitEntityRules", + column: "EntityTypeId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpAuthRoleEntityRules_EntityTypeId", + table: "AbpAuthRoleEntityRules", + column: "EntityTypeId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpAuthEntityProperties"); + + migrationBuilder.DropTable( + name: "AbpAuthOrganizationUnitEntityRules"); + + migrationBuilder.DropTable( + name: "AbpAuthRoleEntityRules"); + + migrationBuilder.DropTable( + name: "AbpAuthEntitites"); + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515092715_Add-Allow-Properties.Designer.cs b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515092715_Add-Allow-Properties.Designer.cs new file mode 100644 index 000000000..8beb165c3 --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515092715_Add-Allow-Properties.Designer.cs @@ -0,0 +1,942 @@ +// +using System; +using LY.MicroService.BackendAdmin.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +#nullable disable + +namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(BackendAdminMigrationsDbContext))] + [Migration("20240515092715_Add-Allow-Properties")] + partial class AddAllowProperties + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("char(36)"); + + b.Property("ValueRange") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("ValueRange"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllowProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AllowProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllowProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AllowProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Editions.Edition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.HasIndex("DisplayName"); + + b.ToTable("AbpEditions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("char(36)") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)") + .HasColumnName("DeletionTime"); + + b.Property("DisableTime") + .HasColumnType("datetime(6)"); + + b.Property("EditionId") + .HasColumnType("char(36)"); + + b.Property("EnableTime") + .HasColumnType("datetime(6)"); + + b.Property("EntityVersion") + .HasColumnType("int"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("NormalizedName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("EditionId"); + + b.HasIndex("Name"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpTenants", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Content") + .HasMaxLength(1048576) + .HasColumnType("longtext") + .HasColumnName("Content"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Culture") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("Culture"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("DisplayName"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("Name"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name") + .HasDatabaseName("IX_Tenant_Text_Template_Name"); + + b.ToTable("AbpTextTemplates", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.TextTemplating.TextTemplateDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultCultureName") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("DefaultCultureName"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsInlineLocalized") + .HasColumnType("tinyint(1)"); + + b.Property("IsLayout") + .HasColumnType("tinyint(1)"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Layout") + .HasMaxLength(60) + .HasColumnType("varchar(60)") + .HasColumnName("Layout"); + + b.Property("LocalizationResourceName") + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("LocalizationResourceName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("Name"); + + b.Property("RenderEngine") + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("RenderEngine"); + + b.HasKey("Id"); + + b.ToTable("AbpTextTemplateDefinitions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllowedProviders") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DefaultValue") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsAvailableToHost") + .HasColumnType("tinyint(1)"); + + b.Property("IsVisibleToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ValueType") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatures", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpFeatureGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpFeatureValues", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint unsigned"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpPermissionGrants", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey") + .IsUnique(); + + b.ToTable("AbpSettings", (string)null); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DefaultValue") + .HasMaxLength(2048) + .HasColumnType("varchar(2048)"); + + b.Property("Description") + .HasMaxLength(512) + .HasColumnType("varchar(512)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEncrypted") + .HasColumnType("tinyint(1)"); + + b.Property("IsInherited") + .HasColumnType("tinyint(1)"); + + b.Property("IsVisibleToClients") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)"); + + b.Property("Providers") + .HasMaxLength(1024) + .HasColumnType("varchar(1024)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpSettingDefinitions", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "TypeInfo") + .WithMany("Properties") + .HasForeignKey("TypeInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition") + .WithMany() + .HasForeignKey("EditionId"); + + b.Navigation("Edition"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.TenantConnectionString", b => + { + b.HasOne("LINGYUN.Abp.Saas.Tenants.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Navigation("Properties"); + }); + + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515092715_Add-Allow-Properties.cs b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515092715_Add-Allow-Properties.cs new file mode 100644 index 000000000..89acc7c5a --- /dev/null +++ b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/20240515092715_Add-Allow-Properties.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations +{ + /// + public partial class AddAllowProperties : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AllowProperties", + table: "AbpAuthRoleEntityRules", + type: "varchar(512)", + maxLength: 512, + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddColumn( + name: "AllowProperties", + table: "AbpAuthOrganizationUnitEntityRules", + type: "varchar(512)", + maxLength: 512, + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AllowProperties", + table: "AbpAuthRoleEntityRules"); + + migrationBuilder.DropColumn( + name: "AllowProperties", + table: "AbpAuthOrganizationUnitEntityRules"); + } + } +} diff --git a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/BackendAdminMigrationsDbContextModelSnapshot.cs b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/BackendAdminMigrationsDbContextModelSnapshot.cs index 31ebd2d4d..9b028cb4e 100644 --- a/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/BackendAdminMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/migrations/LY.MicroService.BackendAdmin.EntityFrameworkCore/Migrations/BackendAdminMigrationsDbContextModelSnapshot.cs @@ -21,6 +21,257 @@ namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations .HasAnnotation("ProductVersion", "8.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 64); + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.Property("TypeInfoId") + .HasColumnType("char(36)"); + + b.Property("ValueRange") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("ValueRange"); + + b.HasKey("Id"); + + b.HasIndex("TypeInfoId", "TypeFullName"); + + b.ToTable("AbpAuthEntityProperties", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsAuditEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)") + .HasColumnName("Name"); + + b.Property("TypeFullName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("TypeFullName"); + + b.HasKey("Id"); + + b.HasIndex("TypeFullName"); + + b.ToTable("AbpAuthEntitites", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllowProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AllowProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("OrgCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("varchar(128)") + .HasColumnName("OrgCode"); + + b.Property("OrgId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AllowProperties") + .HasMaxLength(512) + .HasColumnType("varchar(512)") + .HasColumnName("AllowProperties"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("EntityTypeFullName") + .HasColumnType("longtext"); + + b.Property("EntityTypeId") + .HasColumnType("char(36)"); + + b.Property("ExtraProperties") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("FilterGroup") + .HasColumnType("longtext") + .HasColumnName("FilterGroup"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Operation") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)") + .HasColumnName("RoleName"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityTypeId"); + + b.ToTable("AbpAuthRoleEntityRules", (string)null); + }); + modelBuilder.Entity("LINGYUN.Abp.Saas.Editions.Edition", b => { b.Property("Id") @@ -622,6 +873,39 @@ namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations b.ToTable("AbpSettingDefinitions", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "TypeInfo") + .WithMany("Properties") + .HasForeignKey("TypeInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b => + { + b.HasOne("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", "EntityTypeInfo") + .WithMany() + .HasForeignKey("EntityTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EntityTypeInfo"); + }); + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => { b.HasOne("LINGYUN.Abp.Saas.Editions.Edition", "Edition") @@ -640,6 +924,11 @@ namespace LY.MicroService.BackendAdmin.EntityFrameworkCore.Migrations .IsRequired(); }); + modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b => + { + b.Navigation("Properties"); + }); + modelBuilder.Entity("LINGYUN.Abp.Saas.Tenants.Tenant", b => { b.Navigation("ConnectionStrings"); diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/FodyWeavers.xml new file mode 100644 index 000000000..00e1d9a1c --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.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/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN.Abp.DataProtectionManagement.Application.Contracts.csproj b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN.Abp.DataProtectionManagement.Application.Contracts.csproj new file mode 100644 index 000000000..b626759b0 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN.Abp.DataProtectionManagement.Application.Contracts.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementApplicationContractsModule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementApplicationContractsModule.cs new file mode 100644 index 000000000..b88bbc1d3 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementApplicationContractsModule.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Application; +using Volo.Abp.Authorization; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[DependsOn( + typeof(AbpAuthorizationAbstractionsModule), + typeof(AbpDddApplicationContractsModule), + typeof(AbpDataProtectionManagementDomainSharedModule))] +public class AbpDataProtectionManagementApplicationContractsModule : AbpModule +{ + +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementRemoteServiceConsts.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementRemoteServiceConsts.cs new file mode 100644 index 000000000..b2dbae117 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementRemoteServiceConsts.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public static class DataProtectionManagementRemoteServiceConsts +{ + public const string RemoteServiceName = "DataProtectionManagement"; + public const string ModuleName = "data-protection-management"; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityPropertyInfoDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityPropertyInfoDto.cs new file mode 100644 index 000000000..a5c4d7b38 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityPropertyInfoDto.cs @@ -0,0 +1,23 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class EntityPropertyInfoDto : EntityDto +{ + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 显示名称 + /// + public string DisplayName { get; set; } + /// + /// 类型全名 + /// + public string TypeFullName { get; set; } + /// + /// 数据值范围集合(主要针对枚举类型) + /// + public string[] ValueRange { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityRuleCreateOrUpdateDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityRuleCreateOrUpdateDto.cs new file mode 100644 index 000000000..c5c60a281 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityRuleCreateOrUpdateDto.cs @@ -0,0 +1,17 @@ +using LINGYUN.Abp.DataProtection; +using System; +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.DataProtectionManagement; +public abstract class EntityRuleCreateOrUpdateDto +{ + public bool IsEnabled { get; set; } + + [Required] + public DataAccessOperation Operation { get; set; } + + [Required] + public DataAccessFilterGroup FilterGroup { get; set; } + + public string[] AllowProperties { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityRuleDtoBase.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityRuleDtoBase.cs new file mode 100644 index 000000000..ee4262f48 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityRuleDtoBase.cs @@ -0,0 +1,15 @@ +using LINGYUN.Abp.DataProtection; +using System; +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.DataProtectionManagement; +public abstract class EntityRuleDtoBase : AuditedEntityDto +{ + public Guid? TenantId { get; set; } + public bool IsEnabled { get; set; } + public DataAccessOperation Operation { get; set; } + public DataAccessFilterGroup FilterGroup { get; set; } + public Guid EntityTypeId { get; set; } + public string EntityTypeFullName { get; set; } + public string[] AllowProperties { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityTypeInfoDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityTypeInfoDto.cs new file mode 100644 index 000000000..8231a701f --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/EntityTypeInfoDto.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class EntityTypeInfoDto : AuditedEntityDto +{ + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 显示名称 + /// + public string DisplayName { get; set; } + /// + /// 类型全名 + /// + public string TypeFullName { get; set; } + /// + /// 是否启用数据审计 + /// + public bool IsAuditEnabled { get; set; } + /// + /// 实体属性列表 + /// + public virtual List Properties { get; set; } = new List(); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/GetEntityTypeInfoListInput.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/GetEntityTypeInfoListInput.cs new file mode 100644 index 000000000..dbd7701e0 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/GetEntityTypeInfoListInput.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class GetEntityTypeInfoListInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } + + public bool? IsAuditEnabled { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleCreateDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleCreateDto.cs new file mode 100644 index 000000000..ac765b24d --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleCreateDto.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class OrganizationUnitEntityRuleCreateDto : EntityRuleCreateOrUpdateDto +{ + [Required] + public Guid EntityTypeId { get; set; } + + [Required] + public Guid OrgId { get; set; } + + [Required] + [DynamicStringLength(typeof(OrganizationUnitEntityRuleConsts), nameof(OrganizationUnitEntityRuleConsts.MaxCodeLength))] + public string OrgCode { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleDto.cs new file mode 100644 index 000000000..68a041da0 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleDto.cs @@ -0,0 +1,8 @@ +using System; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class OrganizationUnitEntityRuleDto : EntityRuleDtoBase +{ + public Guid OrgId { get; set; } + public string OrgCode { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleGetInput.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleGetInput.cs new file mode 100644 index 000000000..74857c89e --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleGetInput.cs @@ -0,0 +1,19 @@ +using LINGYUN.Abp.DataProtection; +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.DataProtectionManagement; + +public class OrganizationUnitEntityRuleGetInput +{ + [Required] + [DynamicStringLength(typeof(OrganizationUnitEntityRuleConsts), nameof(OrganizationUnitEntityRuleConsts.MaxCodeLength))] + public string OrgCode { get; set; } + + [Required] + public Guid EntityTypeId { get; set; } + + [Required] + public DataAccessOperation Operation { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleUpdateDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleUpdateDto.cs new file mode 100644 index 000000000..a44be40de --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/OrganizationUnitEntityRuleUpdateDto.cs @@ -0,0 +1,4 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public class OrganizationUnitEntityRuleUpdateDto : EntityRuleCreateOrUpdateDto +{ +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleCreateDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleCreateDto.cs new file mode 100644 index 000000000..a1630f921 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleCreateDto.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class RoleEntityRuleCreateDto : EntityRuleCreateOrUpdateDto +{ + [Required] + public Guid EntityTypeId { get; set; } + + [Required] + public Guid RoleId { get; set; } + + [Required] + [DynamicStringLength(typeof(RoleEntityRuleConsts), nameof(RoleEntityRuleConsts.MaxRuletNameLength))] + public string RoleName { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleDto.cs new file mode 100644 index 000000000..aeb983e24 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleDto.cs @@ -0,0 +1,9 @@ +using System; + +namespace LINGYUN.Abp.DataProtectionManagement; + +public class RoleEntityRuleDto : EntityRuleDtoBase +{ + public Guid RoleId { get; set; } + public string RoleName { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleGetInput.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleGetInput.cs new file mode 100644 index 000000000..9f772c31d --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleGetInput.cs @@ -0,0 +1,19 @@ +using LINGYUN.Abp.DataProtection; +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.DataProtectionManagement; + +public class RoleEntityRuleGetInput +{ + [Required] + [DynamicStringLength(typeof(RoleEntityRuleConsts), nameof(RoleEntityRuleConsts.MaxRuletNameLength))] + public string RoleName { get; set; } + + [Required] + public Guid EntityTypeId { get; set; } + + [Required] + public DataAccessOperation Operation { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleInput.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleInput.cs new file mode 100644 index 000000000..fd6c8bd59 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleInput.cs @@ -0,0 +1,14 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class RoleEntityRuleInput : EntityRuleCreateOrUpdateDto +{ + [Required] + public Guid RoleId { get; set; } + + [Required] + [DynamicStringLength(typeof(RoleEntityRuleConsts), nameof(RoleEntityRuleConsts.MaxRuletNameLength))] + public string RoleName { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleUpdateDto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleUpdateDto.cs new file mode 100644 index 000000000..ba5901a30 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/RoleEntityRuleUpdateDto.cs @@ -0,0 +1,4 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public class RoleEntityRuleUpdateDto : EntityRuleCreateOrUpdateDto +{ +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IEntityTypeInfoAppService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IEntityTypeInfoAppService.cs new file mode 100644 index 000000000..cb86960b6 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IEntityTypeInfoAppService.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IEntityTypeInfoAppService : IApplicationService +{ + Task GetAsync(Guid id); + + Task> GetListAsync(GetEntityTypeInfoListInput input); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IOrganizationUnitEntityRuleAppService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IOrganizationUnitEntityRuleAppService.cs new file mode 100644 index 000000000..9b6298cb3 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IOrganizationUnitEntityRuleAppService.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IOrganizationUnitEntityRuleAppService : IApplicationService +{ + Task GetAsync(OrganizationUnitEntityRuleGetInput input); + + Task CreateAsync(OrganizationUnitEntityRuleCreateDto input); + + Task UpdateAsync(Guid id, OrganizationUnitEntityRuleUpdateDto input); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IRoleEntityRuleAppService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IRoleEntityRuleAppService.cs new file mode 100644 index 000000000..bed286135 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/IRoleEntityRuleAppService.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IRoleEntityRuleAppService : IApplicationService +{ + Task GetAsync(RoleEntityRuleGetInput input); + + Task CreateAsync(RoleEntityRuleCreateDto input); + + Task UpdateAsync(Guid id, RoleEntityRuleUpdateDto input); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionDefinitionProvider.cs new file mode 100644 index 000000000..9d725ee03 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionDefinitionProvider.cs @@ -0,0 +1,35 @@ +using LINGYUN.Abp.DataProtection.Localization; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.DataProtectionManagement.Permissions; + +public class DataProtectionManagementPermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup( + DataProtectionManagementPermissionNames.GroupName, + L("Permission:DataProtectionManagement")); + + var entityTypeInfo = group.AddPermission(DataProtectionManagementPermissionNames.EntityTypeInfo.Default, L("Permission:EntityTypeInfo")); + entityTypeInfo.AddChild(DataProtectionManagementPermissionNames.EntityTypeInfo.Create, L("Permission:Create")); + entityTypeInfo.AddChild(DataProtectionManagementPermissionNames.EntityTypeInfo.Update, L("Permission:Update")); + entityTypeInfo.AddChild(DataProtectionManagementPermissionNames.EntityTypeInfo.Delete, L("Permission:Delete")); + + var roleEntityRule = group.AddPermission(DataProtectionManagementPermissionNames.RoleEntityRule.Default, L("Permission:RoleEntityRule")); + roleEntityRule.AddChild(DataProtectionManagementPermissionNames.RoleEntityRule.Create, L("Permission:Create")); + roleEntityRule.AddChild(DataProtectionManagementPermissionNames.RoleEntityRule.Update, L("Permission:Update")); + roleEntityRule.AddChild(DataProtectionManagementPermissionNames.RoleEntityRule.Delete, L("Permission:Delete")); + + var ouEntityRule = group.AddPermission(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Default, L("Permission:OrganizationUnitEntityRule")); + ouEntityRule.AddChild(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Create, L("Permission:Create")); + ouEntityRule.AddChild(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Update, L("Permission:Update")); + ouEntityRule.AddChild(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Delete, L("Permission:Delete")); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionNames.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionNames.cs new file mode 100644 index 000000000..9d212970a --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionNames.cs @@ -0,0 +1,37 @@ +using Volo.Abp.Reflection; + +namespace LINGYUN.Abp.DataProtectionManagement.Permissions; + +public static class DataProtectionManagementPermissionNames +{ + public const string GroupName = "AbpDataProtectionManagement"; + + public static class EntityTypeInfo + { + public const string Default = GroupName + ".EntityTypeInfo"; + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } + + public static class RoleEntityRule + { + public const string Default = GroupName + ".RoleEntityRule"; + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } + + public static class OrganizationUnitEntityRule + { + public const string Default = GroupName + ".OrganizationUnitEntityRule"; + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } + + public static string[] GetAll() + { + return ReflectionHelper.GetPublicConstantsRecursively(typeof(DataProtectionManagementPermissionNames)); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/FodyWeavers.xml b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/FodyWeavers.xml new file mode 100644 index 000000000..00e1d9a1c --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/FodyWeavers.xsd b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.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/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN.Abp.DataProtectionManagement.Application.csproj b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN.Abp.DataProtectionManagement.Application.csproj new file mode 100644 index 000000000..097d686a1 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN.Abp.DataProtectionManagement.Application.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.1 + + + + + + + + + + + + + diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementApplicationModule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementApplicationModule.cs new file mode 100644 index 000000000..58364faf7 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementApplicationModule.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[DependsOn( + typeof(AbpDddApplicationModule), + typeof(AbpDataProtectionManagementApplicationContractsModule), + typeof(AbpDataProtectionManagementDomainModule))] +public class AbpDataProtectionManagementApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + Configure(options => + { + options.AddProfile(validate: true); + }); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationMappingProfile.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationMappingProfile.cs new file mode 100644 index 000000000..0141a1461 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationMappingProfile.cs @@ -0,0 +1,23 @@ +using AutoMapper; +using System; +using System.Linq; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class DataProtectionManagementApplicationMappingProfile :Profile +{ + public DataProtectionManagementApplicationMappingProfile() + { + CreateMap() + .ForMember(dto => dto.ValueRange, map => map.MapFrom(src => MapToArray(src.ValueRange))); + CreateMap(); + } + + private string[] MapToArray(string val) + { + if (val.IsNullOrWhiteSpace()) + { + return Array.Empty(); + } + return val.Split(',').ToArray(); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationServiceBase.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationServiceBase.cs new file mode 100644 index 000000000..7dfcca1a0 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationServiceBase.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.DataProtectionManagement; +public abstract class DataProtectionManagementApplicationServiceBase : ApplicationService +{ + protected DataProtectionManagementApplicationServiceBase() + { + LocalizationResource = typeof(AbpDataProtectionManagementApplicationModule); + ObjectMapperContext = typeof(AbpDataProtectionManagementApplicationModule); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoAppService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoAppService.cs new file mode 100644 index 000000000..6f9d9ed9d --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoAppService.cs @@ -0,0 +1,64 @@ +using LINGYUN.Abp.DataProtectionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Authorize(DataProtectionManagementPermissionNames.EntityTypeInfo.Default)] +public class EntityTypeInfoAppService : DataProtectionManagementApplicationServiceBase, IEntityTypeInfoAppService +{ + private readonly EntityTypeInfoManager _entityTypeInfoManager; + private readonly IEntityTypeInfoRepository _entityTypeInfoRepository; + + public EntityTypeInfoAppService( + EntityTypeInfoManager entityTypeInfoManager, + IEntityTypeInfoRepository entityTypeInfoRepository) + { + _entityTypeInfoManager = entityTypeInfoManager; + _entityTypeInfoRepository = entityTypeInfoRepository; + } + + public async virtual Task GetAsync(Guid id) + { + var entityTypeInfo = await _entityTypeInfoRepository.GetAsync(id); + + return ObjectMapper.Map(entityTypeInfo); + } + + public async virtual Task> GetListAsync(GetEntityTypeInfoListInput input) + { + var specification = new GetEntityTypeInfoListSpecification(input); + + var totalCount = await _entityTypeInfoRepository.GetCountAsync(specification); + var entities = await _entityTypeInfoRepository.GetListAsync(specification, + input.Sorting, input.MaxResultCount, input.SkipCount); + + return new PagedResultDto(totalCount, + ObjectMapper.Map, List>(entities)); + } + + private class GetEntityTypeInfoListSpecification : Specification + { + protected GetEntityTypeInfoListInput Input { get; } + + public GetEntityTypeInfoListSpecification(GetEntityTypeInfoListInput input) + { + Input = input; + } + + public override Expression> ToExpression() + { + Expression> expression = _ => true; + + return expression + .AndIf(Input.IsAuditEnabled.HasValue, x => x.IsAuditEnabled == Input.IsAuditEnabled) + .AndIf(!Input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(Input.Filter) || + x.DisplayName.Contains(Input.Filter) || x.TypeFullName.Contains(Input.Filter)); + } + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleAppService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleAppService.cs new file mode 100644 index 000000000..88f2a6437 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleAppService.cs @@ -0,0 +1,88 @@ +using LINGYUN.Abp.DataProtectionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Authorize(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Default)] +public class OrganizationUnitEntityRuleAppService : DataProtectionManagementApplicationServiceBase, IOrganizationUnitEntityRuleAppService +{ + private readonly IEntityTypeInfoRepository _entityTypeInfoRepository; + private readonly IOrganizationUnitEntityRuleRepository _organizationUnitEntityRuleRepository; + + public OrganizationUnitEntityRuleAppService( + IEntityTypeInfoRepository entityTypeInfoRepository, + IOrganizationUnitEntityRuleRepository organizationUnitEntityRuleRepository) + { + _entityTypeInfoRepository = entityTypeInfoRepository; + _organizationUnitEntityRuleRepository = organizationUnitEntityRuleRepository; + } + + public async virtual Task GetAsync(OrganizationUnitEntityRuleGetInput input) + { + var entityTypeInfo = await _entityTypeInfoRepository.GetAsync(input.EntityTypeId); + var entityRule = await _organizationUnitEntityRuleRepository.FindEntityRuleAsync(input.OrgCode, entityTypeInfo.TypeFullName, input.Operation); + return ObjectMapper.Map(entityRule); + } + + [Authorize(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Create)] + public async virtual Task CreateAsync(OrganizationUnitEntityRuleCreateDto input) + { + var entityTypeInfo = await _entityTypeInfoRepository.GetAsync(input.EntityTypeId); + if (await _organizationUnitEntityRuleRepository.FindEntityRuleAsync(input.OrgCode, entityTypeInfo.TypeFullName, input.Operation) != null) + { + throw new BusinessException(DataProtectionManagementErrorCodes.OrganizationUnitEntityRule.DuplicateEntityRule) + .WithData(nameof(OrganizationUnitEntityRule.OrgCode), input.OrgCode) + .WithData(nameof(EntityTypeInfo.DisplayName), entityTypeInfo.DisplayName) + .WithData(nameof(EntityRuleBase.Operation), input.Operation); + } + + var entityRule = new OrganizationUnitEntityRule( + GuidGenerator.Create(), + input.OrgId, + input.OrgCode, + entityTypeInfo.Id, + entityTypeInfo.TypeFullName, + input.Operation, + input.AllowProperties?.JoinAsString(","), + input.FilterGroup, + CurrentTenant.Id) + { + IsEnabled = input.IsEnabled, + }; + + entityRule = await _organizationUnitEntityRuleRepository.InsertAsync(entityRule); + + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(entityRule); + } + + [Authorize(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Update)] + public async virtual Task UpdateAsync(Guid id, OrganizationUnitEntityRuleUpdateDto input) + { + var entityRule = await _organizationUnitEntityRuleRepository.GetAsync(id); + if (entityRule.IsEnabled != input.IsEnabled) + { + entityRule.IsEnabled = input.IsEnabled; + } + if (entityRule.Operation != input.Operation) + { + entityRule.Operation = input.Operation; + } + var allowPropertites = input.AllowProperties?.JoinAsString(","); + if (!string.Equals(entityRule.AllowProperties, allowPropertites, StringComparison.InvariantCultureIgnoreCase)) + { + entityRule.AllowProperties = allowPropertites; + } + + entityRule = await _organizationUnitEntityRuleRepository.UpdateAsync(entityRule); + + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(entityRule); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleAppService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleAppService.cs new file mode 100644 index 000000000..21a7fedc3 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleAppService.cs @@ -0,0 +1,88 @@ +using LINGYUN.Abp.DataProtectionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Authorize(DataProtectionManagementPermissionNames.RoleEntityRule.Default)] +public class RoleEntityRuleAppService : DataProtectionManagementApplicationServiceBase, IRoleEntityRuleAppService +{ + private readonly IEntityTypeInfoRepository _entityTypeInfoRepository; + private readonly IRoleEntityRuleRepository _roleEntityRuleRepository; + + public RoleEntityRuleAppService( + IEntityTypeInfoRepository entityTypeInfoRepository, + IRoleEntityRuleRepository roleEntityRuleRepository) + { + _entityTypeInfoRepository = entityTypeInfoRepository; + _roleEntityRuleRepository = roleEntityRuleRepository; + } + + public async virtual Task GetAsync(RoleEntityRuleGetInput input) + { + var entityTypeInfo = await _entityTypeInfoRepository.GetAsync(input.EntityTypeId); + var entityRule = await _roleEntityRuleRepository.FindEntityRuleAsync(input.RoleName, entityTypeInfo.TypeFullName, input.Operation); + return ObjectMapper.Map(entityRule); + } + + [Authorize(DataProtectionManagementPermissionNames.RoleEntityRule.Create)] + public async virtual Task CreateAsync(RoleEntityRuleCreateDto input) + { + var entityTypeInfo = await _entityTypeInfoRepository.GetAsync(input.EntityTypeId); + if (await _roleEntityRuleRepository.FindEntityRuleAsync(input.RoleName, entityTypeInfo.TypeFullName, input.Operation) != null) + { + throw new BusinessException(DataProtectionManagementErrorCodes.OrganizationUnitEntityRule.DuplicateEntityRule) + .WithData(nameof(RoleEntityRule.RoleName), input.RoleName) + .WithData(nameof(EntityTypeInfo.DisplayName), entityTypeInfo.DisplayName) + .WithData(nameof(EntityRuleBase.Operation), input.Operation); + } + + var entityRule = new RoleEntityRule( + GuidGenerator.Create(), + input.RoleId, + input.RoleName, + entityTypeInfo.Id, + entityTypeInfo.TypeFullName, + input.Operation, + input.AllowProperties?.JoinAsString(","), + input.FilterGroup, + CurrentTenant.Id) + { + IsEnabled = input.IsEnabled, + }; + + entityRule = await _roleEntityRuleRepository.InsertAsync(entityRule); + + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(entityRule); + } + + [Authorize(DataProtectionManagementPermissionNames.RoleEntityRule.Update)] + public async virtual Task UpdateAsync(Guid id, RoleEntityRuleUpdateDto input) + { + var entityRule = await _roleEntityRuleRepository.GetAsync(id); + if (entityRule.IsEnabled != input.IsEnabled) + { + entityRule.IsEnabled = input.IsEnabled; + } + if (entityRule.Operation != input.Operation) + { + entityRule.Operation = input.Operation; + } + var allowPropertites = input.AllowProperties?.JoinAsString(","); + if (!string.Equals(entityRule.AllowProperties, allowPropertites, StringComparison.InvariantCultureIgnoreCase)) + { + entityRule.AllowProperties = allowPropertites; + } + + entityRule = await _roleEntityRuleRepository.UpdateAsync(entityRule); + + await CurrentUnitOfWork.SaveChangesAsync(); + + return ObjectMapper.Map(entityRule); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/FodyWeavers.xml b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/FodyWeavers.xml new file mode 100644 index 000000000..5d6962159 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/FodyWeavers.xsd b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/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/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN.Abp.DataProtectionManagement.Domain.Shared.csproj b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN.Abp.DataProtectionManagement.Domain.Shared.csproj new file mode 100644 index 000000000..f54d1b24b --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN.Abp.DataProtectionManagement.Domain.Shared.csproj @@ -0,0 +1,19 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementDomainSharedModule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementDomainSharedModule.cs new file mode 100644 index 000000000..59635febc --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementDomainSharedModule.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Domain; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[DependsOn(typeof(AbpDddDomainSharedModule))] +public class AbpDataProtectionManagementDomainSharedModule : AbpModule +{ + +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementErrorCodes.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementErrorCodes.cs new file mode 100644 index 000000000..21177a1ea --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementErrorCodes.cs @@ -0,0 +1,37 @@ +namespace LINGYUN.Abp.DataProtectionManagement; + +public static class DataProtectionManagementErrorCodes +{ + public const string Namespace = "DataProtectionManagement"; + + public static class EntityTypeInfo + { + public const string Prefix = Namespace + ":001"; + /// + /// 已经存在相同的类型 + /// + public const string DuplicateTypeInfo = Prefix + "100"; + /// + /// 已经存在相同的属性 + /// + public const string DuplicateProperty = Prefix + "200"; + } + + public static class RoleEntityRule + { + public const string Prefix = Namespace + ":002"; + /// + /// 已经存在相同的实体数据访问规则 + /// + public const string DuplicateEntityRule = Prefix + "100"; + } + + public static class OrganizationUnitEntityRule + { + public const string Prefix = Namespace + ":003"; + /// + /// 已经存在相同的实体数据访问规则 + /// + public const string DuplicateEntityRule = Prefix + "100"; + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityPropertyInfoConsts.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityPropertyInfoConsts.cs new file mode 100644 index 000000000..43f2a8bcb --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityPropertyInfoConsts.cs @@ -0,0 +1,8 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public static class EntityPropertyInfoConsts +{ + public static int MaxNameLength { get; set; } = EntityTypeInfoConsts.MaxNameLength; + public static int MaxDisplayNameLength { get; set; } = EntityTypeInfoConsts.MaxDisplayNameLength; + public static int MaxTypeFullNameLength { get; set; } = EntityTypeInfoConsts.MaxTypeFullNameLength; + public static int MaxValueRangeLength { get; set; } = 512; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityRuleBaseEto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityRuleBaseEto.cs new file mode 100644 index 000000000..f376ea22f --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityRuleBaseEto.cs @@ -0,0 +1,16 @@ +using LINGYUN.Abp.DataProtection; +using System; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Serializable] +public abstract class EntityRuleBaseEto : EntityEto, IMultiTenant +{ + public Guid? TenantId { get; set; } + public bool IsEnabled { get; set; } + public DataAccessOperation Operation { get; set; } + public Guid EntityTypeId { get; set; } + public string EntityTypeFullName { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityRuleConsts.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityRuleConsts.cs new file mode 100644 index 000000000..4d73ae535 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityRuleConsts.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public static class EntityRuleConsts +{ + public static int MaxEntityTypeFullNameLength { get; set; } = EntityPropertyInfoConsts.MaxTypeFullNameLength; + public static int MaxAllowPropertiesLength { get; set; } = 512; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoConsts.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoConsts.cs new file mode 100644 index 000000000..9cb095eba --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoConsts.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public static class EntityTypeInfoConsts +{ + public static int MaxNameLength { get; set; } = 64; + public static int MaxDisplayNameLength { get; set; } = 128; + public static int MaxTypeFullNameLength { get; set; } = 256; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoEto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoEto.cs new file mode 100644 index 000000000..28c31c5a9 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoEto.cs @@ -0,0 +1,27 @@ +using System; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Serializable] +[EventName("abp.data_protection.entity_type_info")] +public class EntityTypeInfoEto : EntityEto +{ + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 显示名称 + /// + public string DisplayName { get; set; } + /// + /// 类型全名 + /// + public string TypeFullName { get; set; } + /// + /// 是否启用数据审计 + /// + public bool IsAuditEnabled { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleConsts.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleConsts.cs new file mode 100644 index 000000000..cc6f85e25 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleConsts.cs @@ -0,0 +1,5 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public static class OrganizationUnitEntityRuleConsts +{ + public static int MaxCodeLength { get; set; } = 128; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleEto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleEto.cs new file mode 100644 index 000000000..4e1392617 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleEto.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp.EventBus; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Serializable] +[EventName("abp.data_protection.entity_rule.organization_unit")] +public class OrganizationUnitEntityRuleEto : EntityRuleBaseEto +{ + public Guid OrgId { get; set; } + public string OrgCode { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleConsts.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleConsts.cs new file mode 100644 index 000000000..20e8ed3b5 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleConsts.cs @@ -0,0 +1,5 @@ +namespace LINGYUN.Abp.DataProtectionManagement; +public static class RoleEntityRuleConsts +{ + public static int MaxRuletNameLength { get; set; } = 256; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleEto.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleEto.cs new file mode 100644 index 000000000..7a2eea91c --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleEto.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp.EventBus; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Serializable] +[EventName("abp.data_protection.entity_rule.role")] +public class RoleEntityRuleEto : EntityRuleBaseEto +{ + public Guid RoleId { get; set; } + public string RoleName { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/FodyWeavers.xml b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/FodyWeavers.xml new file mode 100644 index 000000000..5d6962159 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/FodyWeavers.xsd b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/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/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN.Abp.DataProtectionManagement.Domain.csproj b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN.Abp.DataProtectionManagement.Domain.csproj new file mode 100644 index 000000000..6278ebd29 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN.Abp.DataProtectionManagement.Domain.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.1 + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementDomainModule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementDomainModule.cs new file mode 100644 index 000000000..1e4967ce1 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementDomainModule.cs @@ -0,0 +1,40 @@ +using LINGYUN.Abp.DataProtection; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AutoMapper; +using Volo.Abp.Domain; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[DependsOn( + typeof(AbpAutoMapperModule), + typeof(AbpDddDomainModule), + typeof(AbpDataProtectionModule), + typeof(AbpDataProtectionManagementDomainSharedModule) + )] +public class AbpDataProtectionManagementDomainModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + + Configure(options => + { + options.EtoMappings.Add(); + options.EtoMappings.Add(); + options.EtoMappings.Add(); + + options.AutoEventSelectors.Add(); + options.AutoEventSelectors.Add(); + options.AutoEventSelectors.Add(); + }); + + context.Services.AddHostedService(); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs new file mode 100644 index 000000000..baf04fd94 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs @@ -0,0 +1,42 @@ +using LINGYUN.Abp.DataProtection; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class DataProtectedResourceCache : IDataProtectedResourceCache, ITransientDependency +{ + private readonly IDistributedCache _cache; + + public DataProtectedResourceCache(IDistributedCache cache) + { + _cache = cache; + } + + public virtual DataProtectedResourceCacheItem GetCache(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation) + { + var cacheKey = DataProtectedResourceCacheItem.CalculateCacheKey(subjectName, subjectId, entityTypeFullName, operation); + var cacheItem = _cache.Get(cacheKey); + return cacheItem; + } + + public virtual void RemoveCache(DataAccessResource resource) + { + var cacheKey = DataProtectedResourceCacheItem.CalculateCacheKey(resource.SubjectName, resource.SubjectId, resource.EntityTypeFullName, resource.Operation); + _cache.Remove(cacheKey); + } + + public virtual void SetCache(DataAccessResource resource) + { + var cacheKey = DataProtectedResourceCacheItem.CalculateCacheKey(resource.SubjectName, resource.SubjectId, resource.EntityTypeFullName, resource.Operation); + var cacheItem = new DataProtectedResourceCacheItem( + resource.SubjectName, + resource.SubjectId, + resource.EntityTypeFullName, + resource.Operation, + resource.FilterGroup) + { + AllowProperties = resource.AllowProperties, + }; + _cache.Set(cacheKey, cacheItem); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs new file mode 100644 index 000000000..78c358951 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs @@ -0,0 +1,60 @@ +using LINGYUN.Abp.DataProtection; +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Serializable] +public class DataProtectedResourceCacheItem +{ + private const string CacheKeyFormat = "sn:{0};si:{1},e:{2},o:{3}"; + /// + /// 权限主体 + /// + public string SubjectName { get; set; } + + /// + /// 权限主体标识 + /// + public string SubjectId { get; set; } + + /// + /// 实体类型全名 + /// + public string EntityTypeFullName { get; set; } + + /// + /// 数据权限操作 + /// + public DataAccessOperation Operation { get; set; } + + /// + /// 获取或设置 数据过滤规则 + /// + public DataAccessFilterGroup FilterGroup { get; set; } + + /// + /// 允许操作的属性列表 + /// + public List AllowProperties { get; set; } + + public DataProtectedResourceCacheItem( + string subjectName, + string subjectId, + string entityTypeFullName, + DataAccessOperation operation, + DataAccessFilterGroup filterGroup = null) + { + SubjectName = subjectName; + SubjectId = subjectId; + EntityTypeFullName = entityTypeFullName; + Operation = operation; + FilterGroup = filterGroup; + AllowProperties = new List(); + } + + public static string CalculateCacheKey(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation = DataAccessOperation.Read) + { + return string.Format(CacheKeyFormat, subjectName, subjectId, entityTypeFullName, operation.ToString()); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItemInvalidator.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItemInvalidator.cs new file mode 100644 index 000000000..bfc205348 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItemInvalidator.cs @@ -0,0 +1,56 @@ +using LINGYUN.Abp.Authorization.Permissions; +using LINGYUN.Abp.DataProtection; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class DataProtectedResourceCacheItemInvalidator : + ILocalEventHandler>, + ILocalEventHandler>, + ITransientDependency +{ + private readonly IDataProtectedResourceCache _resourceCache; + + public DataProtectedResourceCacheItemInvalidator(IDataProtectedResourceCache resourceCache) + { + _resourceCache = resourceCache; + } + + public virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + var dataResource = new DataAccessResource( + RolePermissionValueProvider.ProviderName, + eventData.Entity.RoleName, + eventData.Entity.EntityTypeFullName, + eventData.Entity.Operation, + eventData.Entity.FilterGroup) + { + AllowProperties = eventData.Entity.AllowProperties?.Split(",").ToList(), + }; + + _resourceCache.SetCache(dataResource); + + return Task.CompletedTask; + } + + public virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + var dataResource = new DataAccessResource( + OrganizationUnitPermissionValueProvider.ProviderName, + eventData.Entity.OrgCode, + eventData.Entity.EntityTypeFullName, + eventData.Entity.Operation, + eventData.Entity.FilterGroup) + { + AllowProperties = eventData.Entity.AllowProperties?.Split(",").ToList(), + }; + + _resourceCache.SetCache(dataResource); + + return Task.CompletedTask; + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs new file mode 100644 index 000000000..b688a3a61 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs @@ -0,0 +1,45 @@ +using LINGYUN.Abp.DataProtection; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Dependency(ServiceLifetime.Transient, ReplaceServices = true)] +[ExposeServices(typeof(IDataProtectedResourceStore), typeof(DataProtectedResourceCacheStore))] +public class DataProtectedResourceCacheStore : IDataProtectedResourceStore, ITransientDependency +{ + private readonly IDataProtectedResourceCache _cache; + + public DataProtectedResourceCacheStore(IDataProtectedResourceCache cache) + { + _cache = cache; + } + + public DataAccessResource Get(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation) + { + var cacheItem = _cache.GetCache(subjectName, subjectId, entityTypeFullName, operation); + if (cacheItem == null) + { + return null; + } + return new DataAccessResource( + cacheItem.SubjectName, + cacheItem.SubjectId, + cacheItem.EntityTypeFullName, + cacheItem.Operation, + cacheItem.FilterGroup) + { + AllowProperties = cacheItem.AllowProperties, + }; + } + + public void Remove(DataAccessResource resource) + { + _cache.RemoveCache(resource); + } + + public void Set(DataAccessResource resource) + { + _cache.SetCache(resource); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementDbProterties.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementDbProterties.cs new file mode 100644 index 000000000..ad168fe83 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementDbProterties.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Data; + +namespace LINGYUN.Abp.DataProtectionManagement; + +public static class DataProtectionManagementDbProterties +{ + public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix + "Auth"; + + public static string DbSchema { get; set; } = null; + + + public const string ConnectionStringName = "AbpDataProtectionManagement"; +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementDomainMappingProfile.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementDomainMappingProfile.cs new file mode 100644 index 000000000..b43f3a053 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementDomainMappingProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class DataProtectionManagementDomainMappingProfile : Profile +{ + public DataProtectionManagementDomainMappingProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementOptions.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementOptions.cs new file mode 100644 index 000000000..b5e6bf127 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementOptions.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtectionManagement; + +public class DataProtectionManagementOptions +{ + /// + /// 受保护的实体类型 + /// + public IDictionary> ProtectedEntities { get; } + + public DataProtectionManagementOptions() + { + ProtectedEntities = new Dictionary>(); + } + + public void AddEntity() + { + AddEntity(typeof(TResource), typeof(TEntity)); + } + + public void AddEntity(Type resourceType, Type entityType) + { + if (!ProtectedEntities.TryGetValue(resourceType, out var entityTypes)) + { + entityTypes = new List(); + } + entityTypes.Add(entityType); + ProtectedEntities[resourceType] = entityTypes; + } + + public void AddEntities(Type resourceType, params Type[] entityTypes) + { + if (!ProtectedEntities.TryGetValue(resourceType, out var findTypes)) + { + findTypes = new List(); + } + findTypes.AddIfNotContains(entityTypes); + ProtectedEntities[resourceType] = findTypes; + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityPropertyInfo.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityPropertyInfo.cs new file mode 100644 index 000000000..d8f1f6c9a --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityPropertyInfo.cs @@ -0,0 +1,53 @@ +using System; +using Volo.Abp; +using Volo.Abp.Domain.Entities; + +namespace LINGYUN.Abp.DataProtectionManagement; + +public class EntityPropertyInfo : Entity +{ + /// + /// 名称 + /// + public virtual string Name { get; protected set; } + /// + /// 显示名称 + /// + public virtual string DisplayName { get; protected set; } + /// + /// 类型全名 + /// + public virtual string TypeFullName { get; protected set; } + /// + /// 数据值范围集合(主要针对枚举类型) + /// + public virtual string ValueRange { get; protected set; } + /// + /// 所属类型 + /// + public virtual EntityTypeInfo TypeInfo { get; protected set; } + /// + /// 所属类型标识 + /// + public virtual Guid TypeInfoId { get; protected set; } + + protected EntityPropertyInfo() + { + } + + public EntityPropertyInfo( + Guid id, + Guid typeInfoId, + string name, + string displayName, + string typeFullName, + string valueRange = null) + : base(id) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), EntityPropertyInfoConsts.MaxNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), EntityPropertyInfoConsts.MaxDisplayNameLength); + TypeFullName = Check.NotNullOrWhiteSpace(typeFullName, nameof(typeFullName), EntityPropertyInfoConsts.MaxTypeFullNameLength); + ValueRange = Check.Length(valueRange, nameof(valueRange), EntityPropertyInfoConsts.MaxValueRangeLength); + TypeInfoId = typeInfoId; + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityRuleBase.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityRuleBase.cs new file mode 100644 index 000000000..bd22f09cb --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityRuleBase.cs @@ -0,0 +1,42 @@ +using LINGYUN.Abp.DataProtection; +using System; +using Volo.Abp; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.DataProtectionManagement; +public abstract class EntityRuleBase : AuditedAggregateRoot, IMultiTenant +{ + public virtual Guid? TenantId { get; protected set; } + public virtual bool IsEnabled { get; set; } + public virtual DataAccessOperation Operation { get; set; } + public virtual DataAccessFilterGroup FilterGroup { get; set; } + public virtual Guid EntityTypeId { get; protected set; } + public virtual string EntityTypeFullName { get; protected set; } + public virtual EntityTypeInfo EntityTypeInfo { get; protected set; } + public virtual string AllowProperties { get; set; } + protected EntityRuleBase() + { + } + + protected EntityRuleBase( + Guid id, + Guid entityTypeId, + string enetityTypeFullName, + DataAccessOperation operation, + string allowProperties = null, + DataAccessFilterGroup filterGroup = null, + Guid? tenantId = null) + : base(id) + { + Operation = operation; + FilterGroup = filterGroup; + TenantId = tenantId; + + EntityTypeId = entityTypeId; + EntityTypeFullName = Check.NotNullOrWhiteSpace(enetityTypeFullName, nameof(enetityTypeFullName), EntityRuleConsts.MaxEntityTypeFullNameLength); + AllowProperties = Check.Length(allowProperties, nameof(allowProperties), EntityRuleConsts.MaxAllowPropertiesLength); + } + + +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfo.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfo.cs new file mode 100644 index 000000000..18d38c3bc --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfo.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Volo.Abp; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.Guids; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class EntityTypeInfo : AuditedAggregateRoot +{ + /// + /// 名称 + /// + public virtual string Name { get; protected set; } + /// + /// 显示名称 + /// + public virtual string DisplayName { get; protected set; } + /// + /// 类型全名 + /// + public virtual string TypeFullName { get; protected set; } + /// + /// 是否启用数据审计 + /// + public virtual bool IsAuditEnabled { get; protected set; } + /// + /// 实体属性列表 + /// + public virtual ICollection Properties { get; protected set; } + protected EntityTypeInfo() + { + Properties = new Collection(); + } + + public EntityTypeInfo( + Guid id, + string name, + string displayName, + string typeFullName, + bool isAuditEnabled = true) + :base(id) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), EntityTypeInfoConsts.MaxNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), EntityTypeInfoConsts.MaxDisplayNameLength); + TypeFullName = Check.NotNullOrWhiteSpace(typeFullName, nameof(typeFullName), EntityTypeInfoConsts.MaxTypeFullNameLength); + IsAuditEnabled = isAuditEnabled; + Properties = new Collection(); + } + + public EntityPropertyInfo FindProperty(string name) + { + return Properties.FirstOrDefault(x => x.Name == name); + } + + public void RemoveProperty(string name) + { + Properties.RemoveAll(x => x.Name == name); + } + + public EntityPropertyInfo AddProperty( + IGuidGenerator guidGenerator, + string name, + string displayName, + string typeFullName, + string valueRange = null) + { + if (HasExistsProperty(name)) + { + throw new BusinessException(DataProtectionManagementErrorCodes.EntityTypeInfo.DuplicateProperty) + .WithData(nameof(EntityPropertyInfo.Name), name); + } + + var propertyInfo = new EntityPropertyInfo( + guidGenerator.Create(), + Id, + name, + displayName, + typeFullName, + valueRange); + + Properties.Add(propertyInfo); + + return propertyInfo; + } + + public bool HasExistsProperty(string name) + { + return Properties.Any(x => x.Name == name); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoManager.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoManager.cs new file mode 100644 index 000000000..15993c3a4 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoManager.cs @@ -0,0 +1,58 @@ +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Domain.Services; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class EntityTypeInfoManager : DomainService +{ + protected IEntityTypeInfoRepository EntityTypeInfoRepository { get; } + protected IRoleEntityRuleRepository RoleEntityRuleRepository { get; } + protected IOrganizationUnitEntityRuleRepository OrganizationUnitEntityRuleRepository { get; } + + public EntityTypeInfoManager( + IEntityTypeInfoRepository entityTypeInfoRepository, + IRoleEntityRuleRepository roleEntityRuleRepository, + IOrganizationUnitEntityRuleRepository organizationUnitEntityRuleRepository) + { + EntityTypeInfoRepository = entityTypeInfoRepository; + RoleEntityRuleRepository = roleEntityRuleRepository; + OrganizationUnitEntityRuleRepository = organizationUnitEntityRuleRepository; + } + + [UnitOfWork] + public async virtual Task CreateAsync(EntityTypeInfo entityTypeInfo) + { + await ValidateEntityTypeInfoAsync(entityTypeInfo); + + return await EntityTypeInfoRepository.InsertAsync(entityTypeInfo); + } + + [UnitOfWork] + public async virtual Task UpdateAsync(EntityTypeInfo entityTypeInfo) + { + await ValidateEntityTypeInfoAsync(entityTypeInfo); + + return await EntityTypeInfoRepository.UpdateAsync(entityTypeInfo); + } + + public async virtual Task DeleteAsync(EntityTypeInfo entityTypeInfo) + { + await EntityTypeInfoRepository.DeleteAsync(entityTypeInfo); + + var roleEntityRules = await RoleEntityRuleRepository.GetListByEntityAsync(entityTypeInfo.TypeFullName); + await RoleEntityRuleRepository.DeleteManyAsync(roleEntityRules); + + var orgEntityRules = await OrganizationUnitEntityRuleRepository.GetListByEntityAsync(entityTypeInfo.TypeFullName); + await OrganizationUnitEntityRuleRepository.DeleteManyAsync(orgEntityRules); + } + + protected async virtual Task ValidateEntityTypeInfoAsync(EntityTypeInfo entityTypeInfo) + { + if (await EntityTypeInfoRepository.FindByTypeAsync(entityTypeInfo.TypeFullName) != null) + { + throw new BusinessException(DataProtectionManagementErrorCodes.EntityTypeInfo.DuplicateTypeInfo) + .WithData("Name", entityTypeInfo.TypeFullName); + } + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs new file mode 100644 index 000000000..3469ceadd --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.DataProtection; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IDataProtectedResourceCache +{ + /// + /// 设置指定数据权限的缓存 + /// + /// 要更新的数据权限缓存项 + void SetCache(DataAccessResource resource); + /// + /// 移除指定主体与实体类型的缓存项 + /// + /// 要移除的数据权限缓存项信息 + void RemoveCache(DataAccessResource resource); + /// + /// 获取指定主体与实体类型的数据权限过滤规则 + /// + /// 权限主体 + /// 权限主体标识 + /// 实体类型名称 + /// 数据权限操作 + /// 数据过滤条件组 + DataProtectedResourceCacheItem GetCache(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IEntityTypeInfoRepository.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IEntityTypeInfoRepository.cs new file mode 100644 index 000000000..cc4e55046 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IEntityTypeInfoRepository.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IEntityTypeInfoRepository : IBasicRepository +{ + Task FindByTypeAsync( + string typeFullName, + CancellationToken cancellationToken = default); + + Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default); + + Task> GetListAsync( + ISpecification specification, + string sorting = nameof(EntityTypeInfo.Id), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IOrganizationUnitEntityRuleRepository.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IOrganizationUnitEntityRuleRepository.cs new file mode 100644 index 000000000..89a032dd6 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IOrganizationUnitEntityRuleRepository.cs @@ -0,0 +1,32 @@ +using LINGYUN.Abp.DataProtection; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IOrganizationUnitEntityRuleRepository : IBasicRepository +{ + Task FindEntityRuleAsync( + string orgCode, + string entityTypeFullName, + DataAccessOperation operation = DataAccessOperation.Read, + CancellationToken cancellationToken = default); + + Task> GetListByEntityAsync( + string entityTypeFullName, + CancellationToken cancellationToken = default); + + Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default); + + Task> GetCountAsync( + ISpecification specification, + string sorting = nameof(OrganizationUnitEntityRule.EntityTypeFullName), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IProtectedEntitiesSaver.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IProtectedEntitiesSaver.cs new file mode 100644 index 000000000..325bc08b0 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IProtectedEntitiesSaver.cs @@ -0,0 +1,8 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IProtectedEntitiesSaver +{ + Task SaveAsync(CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IRoleEntityRuleRepository.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IRoleEntityRuleRepository.cs new file mode 100644 index 000000000..30f9eaafb --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IRoleEntityRuleRepository.cs @@ -0,0 +1,32 @@ +using LINGYUN.Abp.DataProtection; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement; +public interface IRoleEntityRuleRepository : IBasicRepository +{ + Task FindEntityRuleAsync( + string roleName, + string entityTypeFullName, + DataAccessOperation operation = DataAccessOperation.Read, + CancellationToken cancellationToken = default); + + Task> GetListByEntityAsync( + string entityTypeFullName, + CancellationToken cancellationToken = default); + + Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default); + + Task> GetCountAsync( + ISpecification specification, + string sorting = nameof(RoleEntityRule.EntityTypeFullName), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRule.cs new file mode 100644 index 000000000..aa578415a --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRule.cs @@ -0,0 +1,30 @@ +using LINGYUN.Abp.DataProtection; +using System; +using Volo.Abp; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class OrganizationUnitEntityRule : EntityRuleBase +{ + public virtual Guid OrgId { get; protected set; } + public virtual string OrgCode { get; protected set; } + + protected OrganizationUnitEntityRule() + { + } + + public OrganizationUnitEntityRule( + Guid id, + Guid orgId, + string orgCode, + Guid entityTypeId, + string entityTypeFullName, + DataAccessOperation operation, + string allowProperties = null, + DataAccessFilterGroup filterGroup = null, + Guid? tenantId = null) + : base(id, entityTypeId, entityTypeFullName, operation, allowProperties, filterGroup, tenantId) + { + OrgId = orgId; + OrgCode = Check.NotNullOrWhiteSpace(orgCode, nameof(orgCode), OrganizationUnitEntityRuleConsts.MaxCodeLength); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ProtectedEntitiesSaver.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ProtectedEntitiesSaver.cs new file mode 100644 index 000000000..b905f4b16 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ProtectedEntitiesSaver.cs @@ -0,0 +1,185 @@ +using LINGYUN.Abp.DataProtection; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; +using Volo.Abp.Guids; +using Volo.Abp.Localization; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class ProtectedEntitiesSaver : IProtectedEntitiesSaver, ITransientDependency +{ + protected IApplicationInfoAccessor ApplicationInfoAccessor { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + protected AbpDataProtectionOptions Options { get; } + protected DataProtectionManagementOptions ManagementOptions { get; } + protected IGuidGenerator GuidGenerator { get; } + protected IAbpDistributedLock DistributedLock { get; } + protected IEntityTypeInfoRepository EntityTypeInfoRepository { get; } + protected ILocalizableStringSerializer LocalizableStringSerializer { get; } + + public ProtectedEntitiesSaver( + IApplicationInfoAccessor applicationInfoAccessor, + IOptions cacheOptions, + IOptions options, + IOptions managementOptions, + IGuidGenerator guidGenerator, + IAbpDistributedLock distributedLock, + IEntityTypeInfoRepository entityTypeInfoRepository, + ILocalizableStringSerializer localizableStringSerializer) + { + ApplicationInfoAccessor = applicationInfoAccessor; + CacheOptions = cacheOptions.Value; + Options = options.Value; + ManagementOptions = managementOptions.Value; + GuidGenerator = guidGenerator; + DistributedLock = distributedLock; + EntityTypeInfoRepository = entityTypeInfoRepository; + LocalizableStringSerializer = localizableStringSerializer; + } + + [UnitOfWork] + public async virtual Task SaveAsync(CancellationToken cancellationToken = default) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + GetApplicationDistributedLockKey() + ); + + if (applicationLockHandle == null) + { + return; + } + + var newRecords = new List(); + var changeRecords = new List(); + + var entityTypeList = await EntityTypeInfoRepository.GetListAsync(); + foreach (var protectedEntityMap in ManagementOptions.ProtectedEntities) + { + var resourceType = protectedEntityMap.Key; + var resourceName = LocalizationResourceNameAttribute.GetName(resourceType); + foreach (var entityType in protectedEntityMap.Value) + { + var entityTypeInfo = entityTypeList.FirstOrDefault(x => x.TypeFullName == entityType.FullName); + if (entityTypeInfo == null) + { + // TODO: support localization + var typeDisplayName = entityType.GetCustomAttribute()?.DisplayName; + if (typeDisplayName.IsNullOrWhiteSpace()) + { + var typeDisplayNameString = LocalizableString.Create($"DisplayName:{entityType.Name}", resourceName); + typeDisplayName = LocalizableStringSerializer.Serialize(typeDisplayNameString); + } + var isDataAudited = entityType.GetCustomAttribute() == null; + entityTypeInfo = new EntityTypeInfo( + GuidGenerator.Create(), + entityType.Name, + typeDisplayName ?? entityType.Name, + entityType.FullName, + isDataAudited); + + var typeProperties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) + .Where(x => !Options.IgnoreAuditedProperties.Contains(x.Name)); + foreach (var typeProperty in typeProperties) + { + var propDisplayName = typeProperty.GetCustomAttribute()?.DisplayName; + if (propDisplayName.IsNullOrWhiteSpace()) + { + var propDisplayNameString = LocalizableString.Create($"DisplayName:{entityType.Name}", resourceName); + propDisplayName = LocalizableStringSerializer.Serialize(propDisplayNameString); + } + var propTypeFullName = typeProperty.PropertyType.FullName; + string valueRange = null; + if (typeProperty.PropertyType.IsEnum) + { + propTypeFullName = typeof(int).FullName; + var enumType = typeProperty.PropertyType; + var enumValues = enumType.GetEnumValues().Cast(); + valueRange = enumValues.JoinAsString(","); + } + entityTypeInfo.AddProperty( + GuidGenerator, + typeProperty.Name, + propDisplayName ?? typeProperty.Name, + typeProperty.PropertyType.FullName, + valueRange); + } + newRecords.Add(entityTypeInfo); + } + else + { + var hasChanged = false; + var typeProperties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) + .Where(x => !Options.IgnoreAuditedProperties.Contains(x.Name)); + entityTypeInfo.Properties.RemoveAll(x => !typeProperties.Any(p => p.Name == x.Name)); + foreach (var typeProperty in typeProperties) + { + if (!entityTypeInfo.HasExistsProperty(typeProperty.Name)) + { + hasChanged = true; + var propDisplayName = typeProperty.GetCustomAttribute()?.DisplayName; + if (propDisplayName.IsNullOrWhiteSpace()) + { + var propDisplayNameString = LocalizableString.Create($"DisplayName:{typeProperty.Name}", resourceName); + propDisplayName = LocalizableStringSerializer.Serialize(propDisplayNameString); + } + var propTypeFullName = typeProperty.PropertyType.FullName; + string valueRange = null; + if (typeProperty.PropertyType.IsEnum) + { + propTypeFullName = typeof(int).FullName; + var enumType = typeProperty.PropertyType; + var enumValues = enumType.GetEnumValues().Cast(); + valueRange = enumValues.JoinAsString(","); + } + entityTypeInfo.AddProperty( + GuidGenerator, + typeProperty.Name, + propDisplayName ?? typeProperty.Name, + typeProperty.PropertyType.FullName, + valueRange); + } + } + if (hasChanged) + { + changeRecords.Add(entityTypeInfo); + } + } + } + } + + if (cancellationToken.IsCancellationRequested) + { + return; + } + + if (newRecords.Any()) + { + await EntityTypeInfoRepository.InsertManyAsync(newRecords); + } + + if (changeRecords.Any()) + { + await EntityTypeInfoRepository.UpdateManyAsync(changeRecords); + } + } + + private string GetApplicationDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_AbpDataProtectionUpdateLock"; + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ProtectedEntitiesSaverService.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ProtectedEntitiesSaverService.cs new file mode 100644 index 000000000..11f63a931 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ProtectedEntitiesSaverService.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Hosting; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class ProtectedEntitiesSaverService : BackgroundService +{ + private readonly IProtectedEntitiesSaver _protectedEntitiesSaver; + + public ProtectedEntitiesSaverService(IProtectedEntitiesSaver protectedEntitiesSaver) + { + _protectedEntitiesSaver = protectedEntitiesSaver; + } + + protected async override Task ExecuteAsync(CancellationToken stoppingToken) + { + await _protectedEntitiesSaver.SaveAsync(stoppingToken); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/RoleEntityRule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/RoleEntityRule.cs new file mode 100644 index 000000000..9467d535c --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/RoleEntityRule.cs @@ -0,0 +1,29 @@ +using LINGYUN.Abp.DataProtection; +using System; +using Volo.Abp; + +namespace LINGYUN.Abp.DataProtectionManagement; +public class RoleEntityRule : EntityRuleBase +{ + public virtual Guid RoleId { get; protected set; } + public virtual string RoleName { get; protected set; } + protected RoleEntityRule() + { + } + + public RoleEntityRule( + Guid id, + Guid roleId, + string roleName, + Guid entityTypeId, + string entityTypeFullName, + DataAccessOperation operation, + string allowProperties = null, + DataAccessFilterGroup filterGroup = null, + Guid? tenantId = null) + : base(id, entityTypeId, entityTypeFullName, operation, allowProperties, filterGroup, tenantId) + { + RoleId = roleId; + RoleName = Check.NotNullOrWhiteSpace(roleName, nameof(roleName), RoleEntityRuleConsts.MaxRuletNameLength); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/FodyWeavers.xml b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/FodyWeavers.xml new file mode 100644 index 000000000..5d6962159 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/FodyWeavers.xsd b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/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/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore.csproj b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore.csproj new file mode 100644 index 000000000..f5dfad05b --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore.csproj @@ -0,0 +1,16 @@ + + + + + + + net8.0 + + + + + + + + + diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContext.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContext.cs new file mode 100644 index 000000000..e8c8bcdcc --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContext.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; +public class AbpDataProtectionManagementDbContext : AbpDbContext, IAbpDataProtectionManagementDbContext +{ + public virtual DbSet EntityTypeInfos { get; set; } + + public AbpDataProtectionManagementDbContext( + DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureDataProtectionManagement(); ; + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContextModelCreatingExtensions.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContextModelCreatingExtensions.cs new file mode 100644 index 000000000..1fd7f4bda --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContextModelCreatingExtensions.cs @@ -0,0 +1,126 @@ +using LINGYUN.Abp.DataProtection; +using Microsoft.EntityFrameworkCore; +using System; +using Volo.Abp; +using Volo.Abp.EntityFrameworkCore.Modeling; +using Volo.Abp.EntityFrameworkCore.ValueConverters; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore +{ + public static class AbpDataProtectionManagementDbContextModelCreatingExtensions + { + public static void ConfigureDataProtectionManagement( + this ModelBuilder builder, + Action optionsAction = null) + { + Check.NotNull(builder, nameof(builder)); + + var options = new AbpDataProtectionManagementModelBuilderConfigurationOptions( + DataProtectionManagementDbProterties.DbTablePrefix, + DataProtectionManagementDbProterties.DbSchema + ); + optionsAction?.Invoke(options); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "Entitites", options.Schema); + + b.Property(p => p.Name) + .HasColumnName(nameof(EntityPropertyInfo.Name)) + .HasMaxLength(EntityTypeInfoConsts.MaxNameLength) + .IsRequired(); + b.Property(p => p.DisplayName) + .HasColumnName(nameof(EntityPropertyInfo.DisplayName)) + .HasMaxLength(EntityTypeInfoConsts.MaxDisplayNameLength) + .IsRequired(); + b.Property(p => p.TypeFullName) + .HasColumnName(nameof(EntityPropertyInfo.TypeFullName)) + .HasMaxLength(EntityTypeInfoConsts.MaxTypeFullNameLength) + .IsRequired(); + + b.HasMany(p => p.Properties) + .WithOne(p => p.TypeInfo) + .HasForeignKey(f => f.TypeInfoId) + .IsRequired(); + + b.ConfigureByConvention(); + + b.HasIndex(p => p.TypeFullName); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "EntityProperties", options.Schema); + + b.Property(p => p.Name) + .HasColumnName(nameof(EntityPropertyInfo.Name)) + .HasMaxLength(EntityPropertyInfoConsts.MaxNameLength) + .IsRequired(); + b.Property(p => p.DisplayName) + .HasColumnName(nameof(EntityPropertyInfo.DisplayName)) + .HasMaxLength(EntityPropertyInfoConsts.MaxDisplayNameLength) + .IsRequired(); + b.Property(p => p.TypeFullName) + .HasColumnName(nameof(EntityPropertyInfo.TypeFullName)) + .HasMaxLength(EntityPropertyInfoConsts.MaxTypeFullNameLength) + .IsRequired(); + + b.ConfigureByConvention(); + + b.Property(p => p.ValueRange) + .HasColumnName(nameof(EntityPropertyInfo.ValueRange)) + .HasMaxLength(EntityPropertyInfoConsts.MaxValueRangeLength); + + b.HasIndex(p => new { p.TypeInfoId, p.TypeFullName }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "RoleEntityRules", options.Schema); + + b.Property(p => p.RoleName) + .HasColumnName(nameof(RoleEntityRule.RoleName)) + .HasMaxLength(RoleEntityRuleConsts.MaxRuletNameLength) + .IsRequired(); + b.Property(p => p.AllowProperties) + .HasColumnName(nameof(RoleEntityRule.AllowProperties)) + .HasMaxLength(EntityRuleConsts.MaxAllowPropertiesLength); + + b.Property(p => p.FilterGroup) + .HasColumnName(nameof(RoleEntityRule.FilterGroup)) + .HasConversion(new AbpJsonValueConverter()); + + b.HasOne(p => p.EntityTypeInfo) + .WithMany() + .HasForeignKey(f => f.EntityTypeId) + .IsRequired(); + + b.ConfigureByConvention(); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "OrganizationUnitEntityRules", options.Schema); + + b.Property(p => p.OrgCode) + .HasColumnName(nameof(OrganizationUnitEntityRule.OrgCode)) + .HasMaxLength(OrganizationUnitEntityRuleConsts.MaxCodeLength) + .IsRequired(); + b.Property(p => p.AllowProperties) + .HasColumnName(nameof(RoleEntityRule.AllowProperties)) + .HasMaxLength(EntityRuleConsts.MaxAllowPropertiesLength); + + b.Property(p => p.FilterGroup) + .HasColumnName(nameof(RoleEntityRule.FilterGroup)) + .HasConversion(new AbpJsonValueConverter()); + + b.HasOne(p => p.EntityTypeInfo) + .WithMany() + .HasForeignKey(f => f.EntityTypeId) + .IsRequired(); + + b.ConfigureByConvention(); + }); + } + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementEntityFrameworkCoreModule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementEntityFrameworkCoreModule.cs new file mode 100644 index 000000000..ed2735076 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementEntityFrameworkCoreModule.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.DataProtection.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; + +[DependsOn( + typeof(AbpDataProtectionManagementDomainModule), + typeof(AbpDataProtectionEntityFrameworkCoreModule) +)] +public class AbpDataProtectionManagementEntityFrameworkCoreModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAbpDbContext(options => + { + options.AddRepository(); + + options.AddRepository(); + options.AddRepository(); + + options.AddDefaultRepositories(); + }); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementModelBuilderConfigurationOptions.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementModelBuilderConfigurationOptions.cs new file mode 100644 index 000000000..2b1b6350f --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementModelBuilderConfigurationOptions.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; + +public class AbpDataProtectionManagementModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions +{ + public AbpDataProtectionManagementModelBuilderConfigurationOptions( + [NotNull] string tablePrefix = "", + [CanBeNull] string schema = null) + : base( + tablePrefix, + schema) + { + + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreEntityTypeInfoRepository.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreEntityTypeInfoRepository.cs new file mode 100644 index 000000000..8d8191be9 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreEntityTypeInfoRepository.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; +public class EfCoreEntityTypeInfoRepository : EfCoreRepository, IEntityTypeInfoRepository +{ + public EfCoreEntityTypeInfoRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async virtual Task FindByTypeAsync( + string typeFullName, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.TypeFullName == typeFullName) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListAsync( + ISpecification specification, + string sorting = nameof(EntityTypeInfo.Id), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(EntityTypeInfo.Id) : sorting) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async override Task> WithDetailsAsync() + { + return (await base.WithDetailsAsync()).Include(x => x.Properties); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreOrganizationUnitEntityRuleRepository.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreOrganizationUnitEntityRuleRepository.cs new file mode 100644 index 000000000..bc446dd99 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreOrganizationUnitEntityRuleRepository.cs @@ -0,0 +1,65 @@ +using LINGYUN.Abp.DataProtection; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; +public class EfCoreOrganizationUnitEntityRuleRepository : EfCoreRepository, + IOrganizationUnitEntityRuleRepository +{ + public EfCoreOrganizationUnitEntityRuleRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async virtual Task FindEntityRuleAsync( + string orgCode, + string entityTypeFullName, + DataAccessOperation operation = DataAccessOperation.Read, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.OrgCode == orgCode && x.EntityTypeFullName == entityTypeFullName && x.Operation == operation) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListByEntityAsync( + string entityTypeFullName, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.EntityTypeFullName == entityTypeFullName) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetCountAsync( + ISpecification specification, + string sorting = nameof(OrganizationUnitEntityRule.EntityTypeFullName), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(OrganizationUnitEntityRule.EntityTypeFullName) : sorting) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreRoleEntityRuleRepository.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreRoleEntityRuleRepository.cs new file mode 100644 index 000000000..e36da44fc --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/EfCoreRoleEntityRuleRepository.cs @@ -0,0 +1,65 @@ +using LINGYUN.Abp.DataProtection; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Specifications; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; +public class EfCoreRoleEntityRuleRepository : EfCoreRepository, + IRoleEntityRuleRepository +{ + public EfCoreRoleEntityRuleRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async virtual Task FindEntityRuleAsync( + string roleName, + string entityTypeFullName, + DataAccessOperation operation = DataAccessOperation.Read, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.RoleName == roleName && x.EntityTypeFullName == entityTypeFullName && x.Operation == operation) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListByEntityAsync( + string entityTypeFullName, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.EntityTypeFullName == entityTypeFullName) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetCountAsync( + ISpecification specification, + string sorting = nameof(RoleEntityRule.EntityTypeFullName), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(RoleEntityRule.EntityTypeFullName) : sorting) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/IAbpDataProtectionManagementDbContext.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/IAbpDataProtectionManagementDbContext.cs new file mode 100644 index 000000000..e6b12ff16 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/IAbpDataProtectionManagementDbContext.cs @@ -0,0 +1,9 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore; + +public interface IAbpDataProtectionManagementDbContext : IEfCoreDbContext +{ + DbSet EntityTypeInfos { get; set; } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/FodyWeavers.xml b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/FodyWeavers.xml new file mode 100644 index 000000000..00e1d9a1c --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.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/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN.Abp.DataProtectionManagement.HttpApi.csproj b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN.Abp.DataProtectionManagement.HttpApi.csproj new file mode 100644 index 000000000..60d2f931b --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN.Abp.DataProtectionManagement.HttpApi.csproj @@ -0,0 +1,19 @@ + + + + + + + net8.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementHttpApiModule.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementHttpApiModule.cs new file mode 100644 index 000000000..5e5016307 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/AbpDataProtectionManagementHttpApiModule.cs @@ -0,0 +1,28 @@ +using LINGYUN.Abp.DataProtection.Localization; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[DependsOn( + typeof(AbpAspNetCoreMvcModule), + typeof(AbpDataProtectionManagementApplicationContractsModule))] +public class AbpDataProtectionManagementHttpApiModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpDataProtectionManagementHttpApiModule).Assembly); + }); + + PreConfigure(options => + { + options.AddAssemblyResource( + typeof(DataProtectionResource), + typeof(AbpDataProtectionManagementApplicationContractsModule).Assembly); + }); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoController.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoController.cs new file mode 100644 index 000000000..87c26e2c8 --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/EntityTypeInfoController.cs @@ -0,0 +1,38 @@ +using LINGYUN.Abp.DataProtectionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Controller] +[Authorize(DataProtectionManagementPermissionNames.EntityTypeInfo.Default)] +[RemoteService(Name = DataProtectionManagementRemoteServiceConsts.RemoteServiceName)] +[Area(DataProtectionManagementRemoteServiceConsts.ModuleName)] +[Route($"api/{DataProtectionManagementRemoteServiceConsts.ModuleName}/entity-type-infos")] +public class EntityTypeInfoController : AbpControllerBase, IEntityTypeInfoAppService +{ + private readonly IEntityTypeInfoAppService _service; + + public EntityTypeInfoController(IEntityTypeInfoAppService service) + { + _service = service; + } + + [HttpGet] + [Route("{id}")] + public virtual Task GetAsync(Guid id) + { + return _service.GetAsync(id); + } + + [HttpGet] + public virtual Task> GetListAsync(GetEntityTypeInfoListInput input) + { + return _service.GetListAsync(input); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleController.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleController.cs new file mode 100644 index 000000000..7de044f1d --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleController.cs @@ -0,0 +1,45 @@ +using LINGYUN.Abp.DataProtectionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Controller] +[Authorize(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Default)] +[RemoteService(Name = DataProtectionManagementRemoteServiceConsts.RemoteServiceName)] +[Area(DataProtectionManagementRemoteServiceConsts.ModuleName)] +[Route($"api/{DataProtectionManagementRemoteServiceConsts.ModuleName}/entity-rule/organization-units")] +public class OrganizationUnitEntityRuleController : AbpControllerBase, IOrganizationUnitEntityRuleAppService +{ + private readonly IOrganizationUnitEntityRuleAppService _service; + + public OrganizationUnitEntityRuleController(IOrganizationUnitEntityRuleAppService service) + { + _service = service; + } + + [HttpGet] + public virtual Task GetAsync(OrganizationUnitEntityRuleGetInput input) + { + return _service.GetAsync(input); + } + + [HttpPost] + [Authorize(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Create)] + public virtual Task CreateAsync(OrganizationUnitEntityRuleCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpPut] + [Route("{id}")] + [Authorize(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Update)] + public virtual Task UpdateAsync(Guid id, OrganizationUnitEntityRuleUpdateDto input) + { + return _service.UpdateAsync(id, input); + } +} diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleController.cs b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleController.cs new file mode 100644 index 000000000..2b90b9f4b --- /dev/null +++ b/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.HttpApi/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleController.cs @@ -0,0 +1,45 @@ +using LINGYUN.Abp.DataProtectionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.DataProtectionManagement; + +[Controller] +[Authorize(DataProtectionManagementPermissionNames.RoleEntityRule.Default)] +[RemoteService(Name = DataProtectionManagementRemoteServiceConsts.RemoteServiceName)] +[Area(DataProtectionManagementRemoteServiceConsts.ModuleName)] +[Route($"api/{DataProtectionManagementRemoteServiceConsts.ModuleName}/entity-rule/roles")] +public class RoleEntityRuleController : AbpControllerBase, IRoleEntityRuleAppService +{ + private readonly IRoleEntityRuleAppService _service; + + public RoleEntityRuleController(IRoleEntityRuleAppService service) + { + _service = service; + } + + [HttpGet] + public virtual Task GetAsync(RoleEntityRuleGetInput input) + { + return _service.GetAsync(input); + } + + [HttpPost] + [Authorize(DataProtectionManagementPermissionNames.RoleEntityRule.Create)] + public virtual Task CreateAsync(RoleEntityRuleCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpPut] + [Route("{id}")] + [Authorize(DataProtectionManagementPermissionNames.RoleEntityRule.Update)] + public virtual Task UpdateAsync(Guid id, RoleEntityRuleUpdateDto input) + { + return _service.UpdateAsync(id, input); + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.OrganizaztionUnits/LINGYUN/Abp/Identity/OrganizaztionUnits/OrganizationUnitClaimsPrincipalContributor.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.OrganizaztionUnits/LINGYUN/Abp/Identity/OrganizaztionUnits/OrganizationUnitClaimsPrincipalContributor.cs index 70013ffe1..cfacb09e3 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.OrganizaztionUnits/LINGYUN/Abp/Identity/OrganizaztionUnits/OrganizationUnitClaimsPrincipalContributor.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.OrganizaztionUnits/LINGYUN/Abp/Identity/OrganizaztionUnits/OrganizationUnitClaimsPrincipalContributor.cs @@ -45,10 +45,9 @@ public class OrganizationUnitClaimsPrincipalContributor : IAbpClaimsPrincipalCon foreach (var userOu in userOus) { - var userOuId = userOu.Id.ToString(); - if (!claimsIdentity.HasClaim(AbpOrganizationUnitClaimTypes.OrganizationUnit, userOuId)) + if (!claimsIdentity.HasClaim(AbpOrganizationUnitClaimTypes.OrganizationUnit, userOu.Code)) { - claimsIdentity.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, userOuId)); + claimsIdentity.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, userOu.Code)); } } @@ -60,10 +59,9 @@ public class OrganizationUnitClaimsPrincipalContributor : IAbpClaimsPrincipalCon var roleOus = await _identityRoleRepository.GetOrganizationUnitsAsync(userRoles); foreach (var roleOu in roleOus) { - var roleOuId = roleOu.Id.ToString(); - if (!claimsIdentity.HasClaim(AbpOrganizationUnitClaimTypes.OrganizationUnit, roleOuId)) + if (!claimsIdentity.HasClaim(AbpOrganizationUnitClaimTypes.OrganizationUnit, roleOu.Code)) { - claimsIdentity.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, roleOuId)); + claimsIdentity.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, roleOu.Code)); } } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Portal/LINGYUN/Abp/IdentityServer/Portal/PortalGrantValidator.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Portal/LINGYUN/Abp/IdentityServer/Portal/PortalGrantValidator.cs index c830e2795..e49e13bfc 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Portal/LINGYUN/Abp/IdentityServer/Portal/PortalGrantValidator.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Portal/LINGYUN/Abp/IdentityServer/Portal/PortalGrantValidator.cs @@ -175,7 +175,7 @@ public class PortalGrantValidator : IExtensionGrantValidator errorDescription = resourceOwnerContext.Result.ErrorDescription; } - _logger.LogInformation("User authentication failed: ", errorDescription ?? resourceOwnerContext.Result.Error); + _logger.LogInformation("User authentication failed: {0}", errorDescription ?? resourceOwnerContext.Result.Error); await RaiseFailedResourceOwnerAuthenticationEventAsync(userName, errorDescription, context.Request.Client.ClientId); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, errorDescription, resourceOwnerContext.Result.CustomResponse); diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs index 313b68bd6..d90fb8e06 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksOptions.cs @@ -1,10 +1,15 @@ using System; +using System.Collections.Generic; using Volo.Abp.Collections; namespace LINGYUN.Abp.BackgroundTasks; public class AbpBackgroundTasksOptions { + /// + /// 作业异常类型转换 + /// + public IDictionary ErrorCodeToExceptionTypeMappings { get; } /// /// 任务监听类型列表 /// @@ -135,5 +140,10 @@ public class AbpBackgroundTasksOptions JobMonitors = new TypeList(); DefinitionProviders = new TypeList(); JobDispatcherSelectors = new JobDispatcherSelectorList(); + ErrorCodeToExceptionTypeMappings = new Dictionary(); + } + public void Map(string errorCode, JobExceptionType exceptionType) + { + ErrorCodeToExceptionTypeMappings[errorCode] = exceptionType; } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/DefaultJobExceptionTypeFinder.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/DefaultJobExceptionTypeFinder.cs new file mode 100644 index 000000000..ac5be807d --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/DefaultJobExceptionTypeFinder.cs @@ -0,0 +1,56 @@ +using Microsoft.Extensions.Options; +using System; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.BackgroundTasks; + +public class DefaultJobExceptionTypeFinder : IJobExceptionTypeFinder, ITransientDependency +{ + protected AbpBackgroundTasksOptions Options { get; } + + public DefaultJobExceptionTypeFinder( + IOptions options) + { + Options = options.Value; + } + + public JobExceptionType GetExceptionType(JobEventContext eventContext, Exception exception) + { + if (exception is IHasErrorCode exceptionWithErrorCode && + !exceptionWithErrorCode.Code.IsNullOrWhiteSpace()) + { + if (Options.ErrorCodeToExceptionTypeMappings.TryGetValue(exceptionWithErrorCode.Code!, out var exceptionType)) + { + return exceptionType; + } + } + + if (exception is IBusinessException) + { + return JobExceptionType.Business; + } + + if (exception is AbpValidationException) + { + return JobExceptionType.Business; + } + + if (exception is IHasHttpStatusCode httpStatusCode) + { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status + // 408 Request timeout + // 429 Too Many Requests + if (httpStatusCode.HttpStatusCode == 408 || httpStatusCode.HttpStatusCode == 429 || httpStatusCode.HttpStatusCode >= 500) + { + return JobExceptionType.Network; + } + + return JobExceptionType.Application; + } + + return JobExceptionType.System; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobExceptionTypeFinder.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobExceptionTypeFinder.cs new file mode 100644 index 000000000..9bfb5e82a --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/IJobExceptionTypeFinder.cs @@ -0,0 +1,8 @@ +using System; + +namespace LINGYUN.Abp.BackgroundTasks; +public interface IJobExceptionTypeFinder +{ + JobExceptionType GetExceptionType(JobEventContext eventContext, Exception exception); +} + diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobExceptionType.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobExceptionType.cs new file mode 100644 index 000000000..b77efb955 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Abstractions/LINGYUN/Abp/BackgroundTasks/JobExceptionType.cs @@ -0,0 +1,14 @@ +using System; + +namespace LINGYUN.Abp.BackgroundTasks; + +[Flags] +public enum JobExceptionType +{ + Business = 0, + Application = 2, + Network = 4, + System = 8, + All = Business | Application | Network | System, +} + diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinition.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinition.cs index 5946ccb0c..4172a6dc8 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinition.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinition.cs @@ -31,6 +31,10 @@ public class JobActionDefinition /// 通知提供者 /// public ITypeList Providers { get; } + /// + /// 额外属性 + /// + public Dictionary Properties { get; } public JobActionDefinition( [NotNull] string name, [NotNull] JobActionType type, @@ -45,6 +49,7 @@ public class JobActionDefinition Description = description; Providers = new TypeList(); + Properties = new Dictionary(); } public virtual JobActionDefinition WithProvider() @@ -54,4 +59,15 @@ public class JobActionDefinition return this; } + + public virtual JobActionDefinition WithProperty(string key, object value) + { + Properties[key] = value; + return this; + } + + public override string ToString() + { + return $"[{nameof(JobActionDefinition)} {Name}]"; + } } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinitionExceptionExtensions.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinitionExceptionExtensions.cs new file mode 100644 index 000000000..bd4ced195 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionDefinitionExceptionExtensions.cs @@ -0,0 +1,18 @@ +namespace LINGYUN.Abp.BackgroundTasks.Activities; +public static class JobActionDefinitionExceptionExtensions +{ + private const string ExceptioinTypeKey = "__Abp_BackgroundTasks_Exception_Type__"; + public static JobActionDefinition WithExceptioinType(this JobActionDefinition definition, JobExceptionType exceptionType) + { + return definition.WithProperty(ExceptioinTypeKey, exceptionType); + } + + public static JobExceptionType? GetExceptioinType(this JobActionDefinition definition) + { + if (definition.Properties.TryGetValue(ExceptioinTypeKey, out var value) && value is JobExceptionType exceptionType) + { + return exceptionType; + } + return null; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionEvent.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionEvent.cs index c5e0e9cba..b809cfac3 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionEvent.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.BackgroundTasks.Activities/LINGYUN/Abp/BackgroundTasks/Activities/JobActionEvent.cs @@ -69,6 +69,18 @@ public class JobActionEvent : JobEventBase, ITransientDependency { if (actionDefinition.Type == JobActionType.Failed) { + var exceptionType = actionDefinition.GetExceptioinType(); + if (exceptionType != null) + { + // 应该由用户决定哪些异常才需要发送通知 + var exceptionTypeFinder = context.ServiceProvider.GetRequiredService(); + var findExceptionType = exceptionTypeFinder.GetExceptionType(context, context.EventData.Exception); + if (!exceptionType.Value.HasFlag(findExceptionType)) + { + Logger.LogInformation($"It is not defined in the Acceptable Exception Range, no failed action will be triggered."); + return; + } + } await notifier.NotifyErrorAsync(notifierContext); Logger.LogInformation($"Executed Failed action with {notifierType.Name} was Successed."); } diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs index 2fc062fc3..6e3331877 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.Configure.cs @@ -1,4 +1,5 @@ using DotNetCore.CAP; +using LINGYUN.Abp.DataProtectionManagement; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; @@ -18,6 +19,7 @@ using Microsoft.IdentityModel.Logging; using Microsoft.OpenApi.Models; using StackExchange.Redis; using System; +using System.Collections.Generic; using System.Linq; using System.Text.Encodings.Web; using System.Text.Unicode; @@ -150,6 +152,26 @@ public partial class BackendAdminHttpApiHostModule }); } + private void ConfigureDataProtectedManagement() + { + Configure(options => + { + //options.AddEntities(typeof(IdentityResource), new Type[] + //{ + // typeof(IdentityUser), + // typeof(IdentityRole), + // typeof(OrganizationUnit), + //}); + + //options.AddEntities(typeof(IdentityResource), new Type[] + //{ + // typeof(IdentityUser), + // typeof(IdentityRole), + // typeof(OrganizationUnit), + //}); + }); + } + private void ConfigureSettingManagement() { Configure(options => diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs index 48cffb3c5..f72f6bed9 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs @@ -6,6 +6,7 @@ using LINGYUN.Abp.AuditLogging.Elasticsearch; using LINGYUN.Abp.CachingManagement; using LINGYUN.Abp.CachingManagement.StackExchangeRedis; using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.DataProtectionManagement; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.FeatureManagement; @@ -49,6 +50,7 @@ using Volo.Abp.SettingManagement.EntityFrameworkCore; namespace LY.MicroService.BackendAdmin; [DependsOn( + typeof(AbpCAPEventBusModule), typeof(AbpSerilogEnrichersApplicationModule), typeof(AbpSerilogEnrichersUniqueIdModule), typeof(AbpAspNetCoreSerilogModule), @@ -60,6 +62,8 @@ namespace LY.MicroService.BackendAdmin; typeof(AbpSettingManagementHttpApiModule), typeof(AbpPermissionManagementApplicationModule), typeof(AbpPermissionManagementHttpApiModule), + typeof(AbpDataProtectionManagementApplicationModule), + typeof(AbpDataProtectionManagementHttpApiModule), typeof(AbpFeatureManagementApplicationModule), typeof(AbpFeatureManagementHttpApiModule), typeof(AbpFeatureManagementClientModule), @@ -88,7 +92,6 @@ namespace LY.MicroService.BackendAdmin; typeof(AbpDataDbMigratorModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpEmailingExceptionHandlingModule), - typeof(AbpCAPEventBusModule), typeof(AbpAliyunSmsModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpAspNetCoreHttpOverridesModule), @@ -121,6 +124,7 @@ public partial class BackendAdminHttpApiHostModule : AbpModule ConfigureSettingManagement(); ConfigureFeatureManagement(); ConfigurePermissionManagement(); + ConfigureDataProtectedManagement(); ConfigureIdentity(configuration); ConfigureCaching(configuration); ConfigureAuditing(configuration); diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj index 74609db46..9dd530225 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/LY.MicroService.BackendAdmin.HttpApi.Host.csproj @@ -30,7 +30,7 @@ - + @@ -74,6 +74,8 @@ + + diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj index adbabe107..06d054db0 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/LY.MicroService.PlatformManagement.HttpApi.Host.csproj @@ -57,8 +57,6 @@ - - diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs index 5d36c088f..47f9b1742 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs @@ -68,8 +68,6 @@ namespace LY.MicroService.PlatformManagement; typeof(PlatformApplicationModule), typeof(PlatformHttpApiModule), typeof(PlatformEntityFrameworkCoreModule), - typeof(AbpWeChatWorkApplicationModule), - typeof(AbpWeChatWorkHttpApiModule), typeof(AbpIdentityHttpApiClientModule), typeof(AbpHttpClientIdentityModelWebModule), typeof(AbpFeatureManagementEntityFrameworkCoreModule), diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests.csproj new file mode 100644 index 000000000..3a2201930 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + + false + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/AbpBackgroundTasksActivitiesTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/AbpBackgroundTasksActivitiesTestBase.cs new file mode 100644 index 000000000..374049a1a --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/AbpBackgroundTasksActivitiesTestBase.cs @@ -0,0 +1,7 @@ +using LINGYUN.Abp.Tests; + +namespace LINGYUN.Abp.BackgroundTasks.Activities; + +public class AbpBackgroundTasksActivitiesTestBase : AbpTestsBase +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/AbpBackgroundTasksActivitiesTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/AbpBackgroundTasksActivitiesTestModule.cs new file mode 100644 index 000000000..787a481fd --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/AbpBackgroundTasksActivitiesTestModule.cs @@ -0,0 +1,17 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BackgroundTasks.Activities; + +[DependsOn( + typeof(AbpBackgroundTasksActivitiesModule), + typeof(AbpBackgroundTasksTestModule))] +public class AbpBackgroundTasksActivitiesTestModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Map("TEST:001", JobExceptionType.Business); + }); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/JobExceptionTypeFinder_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/JobExceptionTypeFinder_Tests.cs new file mode 100644 index 000000000..eaefcc941 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/JobExceptionTypeFinder_Tests.cs @@ -0,0 +1,65 @@ +using Shouldly; +using System.Net; +using Volo.Abp; +using Xunit; + +namespace LINGYUN.Abp.BackgroundTasks.Activities; +public class JobExceptionTypeFinder_Tests : AbpBackgroundTasksActivitiesTestBase +{ + private readonly IJobExceptionTypeFinder _jobExceptionTypeFinder; + private readonly IJobActionDefinitionManager _jobActionDefinitionManager; + public JobExceptionTypeFinder_Tests() + { + _jobExceptionTypeFinder = GetRequiredService(); + _jobActionDefinitionManager = GetRequiredService(); + } + + [Fact] + public virtual void Get_Exception_Type_Should_Be_Network() + { + var evntData = new JobEventData( + "test", + typeof(JobExceptionTypeFinder_Tests), + "test", + "test", + null, + new TestApplicationException((int)HttpStatusCode.RequestTimeout)); + var eventContext = new JobEventContext(ServiceProvider, evntData); + var exceptionType = _jobExceptionTypeFinder.GetExceptionType(eventContext, evntData.Exception); + exceptionType.ShouldBe(JobExceptionType.Network); + } + + [Fact] + public virtual void Job_Error_Should_Be_Triggerd() + { + _jobActionDefinitionManager + .Get("test_app") + .GetExceptioinType().Value + .HasFlag(JobExceptionType.Network).ShouldBeFalse(); + + _jobActionDefinitionManager + .Get("test_net") + .GetExceptioinType().Value + .HasFlag(JobExceptionType.Network).ShouldBeTrue(); + + _jobActionDefinitionManager + .Get("test_all") + .GetExceptioinType().Value + .HasFlag(JobExceptionType.Network | JobExceptionType.Application).ShouldBeTrue(); + } + + [Fact] + public virtual void Job_Error_Mapping_Should_Be_Triggerd() + { + var evntData = new JobEventData( + "test_other", + typeof(JobExceptionTypeFinder_Tests), + "test", + "test", + null, + new BusinessException("TEST:001")); + var eventContext = new JobEventContext(ServiceProvider, evntData); + var exceptionType = _jobExceptionTypeFinder.GetExceptionType(eventContext, evntData.Exception); + exceptionType.ShouldBe(JobExceptionType.Business); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/TestApplicationException.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/TestApplicationException.cs new file mode 100644 index 000000000..5a68d853b --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/TestApplicationException.cs @@ -0,0 +1,12 @@ +using Volo.Abp; +using Volo.Abp.ExceptionHandling; + +namespace LINGYUN.Abp.BackgroundTasks.Activities; +public class TestApplicationException : AbpException, IHasHttpStatusCode +{ + public int HttpStatusCode { get; set; } + public TestApplicationException(int httpStatusCode) + { + HttpStatusCode = httpStatusCode; + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/TestJobActionDefinitionProvider.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/TestJobActionDefinitionProvider.cs new file mode 100644 index 000000000..6a053dab7 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Activities.Tests/LINGYUN/Abp/BackgroundTasks/Activities/TestJobActionDefinitionProvider.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.BackgroundTasks.Activities; +public class TestJobActionDefinitionProvider : JobActionDefinitionProvider +{ + public override void Define(IJobActionDefinitionContext context) + { + context.Add(new JobActionDefinition( + "test_app", + JobActionType.Failed, + new FixedLocalizableString("test_app"), + new List()) + .WithExceptioinType(JobExceptionType.Application)); + + context.Add(new JobActionDefinition( + "test_net", + JobActionType.Failed, + new FixedLocalizableString("test_net"), + new List()) + .WithExceptioinType(JobExceptionType.Network)); + + context.Add(new JobActionDefinition( + "test_all", + JobActionType.Failed, + new FixedLocalizableString("test_all"), + new List()) + .WithExceptioinType(JobExceptionType.All)); + + context.Add(new JobActionDefinition( + "test_other", + JobActionType.Failed, + new FixedLocalizableString("test_other"), + new List())); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN.Abp.BackgroundTasks.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN.Abp.BackgroundTasks.Tests.csproj new file mode 100644 index 000000000..3a2954337 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN.Abp.BackgroundTasks.Tests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + + false + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksTestBase.cs new file mode 100644 index 000000000..01674fa4d --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksTestBase.cs @@ -0,0 +1,7 @@ +using LINGYUN.Abp.Tests; + +namespace LINGYUN.Abp.BackgroundTasks; + +public class AbpBackgroundTasksTestBase : AbpTestsBase +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksTestModule.cs new file mode 100644 index 000000000..8533fb13e --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BackgroundTasks.Tests/LINGYUN/Abp/BackgroundTasks/AbpBackgroundTasksTestModule.cs @@ -0,0 +1,11 @@ +using LINGYUN.Abp.Tests; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BackgroundTasks; + +[DependsOn( + typeof(AbpBackgroundTasksModule), + typeof(AbpTestsBaseModule))] +public class AbpBackgroundTasksTestModule : AbpModule +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Nexus.Tests/LINGYUN.Abp.BlobStoring.Nexus.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Nexus.Tests/LINGYUN.Abp.BlobStoring.Nexus.Tests.csproj index 6ef3e1129..51a0434a7 100644 --- a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Nexus.Tests/LINGYUN.Abp.BlobStoring.Nexus.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Nexus.Tests/LINGYUN.Abp.BlobStoring.Nexus.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN.Abp.DataProtection.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN.Abp.DataProtection.Tests.csproj index 6e99e4636..8c3b0d0c1 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN.Abp.DataProtection.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN.Abp.DataProtection.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestDbContext.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestDbContext.cs new file mode 100644 index 000000000..fd34f75d0 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestDbContext.cs @@ -0,0 +1,22 @@ +using LINGYUN.Abp.DataProtection.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace LINGYUN.Abp.DataProtection; +public class AbpDataProtectionTestDbContext : AbpDataProtectionDbContext +{ + public DbSet FakeProtectionObjects { get; set; } + public AbpDataProtectionTestDbContext( + DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity(b => + { + b.ConfigureByConvention(); + }); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs index ca8d99232..f554bf55e 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs @@ -12,7 +12,7 @@ namespace LINGYUN.Abp.DataProtection { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAbpDbContext(options => + context.Services.AddAbpDbContext(options => { options.AddRepository(); }); diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs index 4c7de7efc..82c60251f 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs @@ -1,17 +1,30 @@ -using LINGYUN.Abp.DataProtection.EntityFrameworkCore; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using JetBrains.Annotations; +using LINGYUN.Abp.DataProtection.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp.EntityFrameworkCore; namespace LINGYUN.Abp.DataProtection { public class EfCoreFakeProtectionObjectRepository : - EfCoreRepository, + EfCoreDataProtectionRepository, IFakeProtectionObjectRepository { public EfCoreFakeProtectionObjectRepository( - IDbContextProvider dbContextProvider) - : base(dbContextProvider) + [NotNull] IDbContextProvider dbContextProvider, + [NotNull] IDataAuthorizationService dataAuthorizationService, + [NotNull] IEntityTypeFilterBuilder entityTypeFilterBuilder) + : base(dbContextProvider, dataAuthorizationService, entityTypeFilterBuilder) { } + + [DisableDataProtected] + public async virtual Task> GetAllListAsync() + { + return await (await GetQueryableAsync()) + .ToListAsync(); + } } } diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs index 7423bfb91..94dacc91a 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs @@ -1,8 +1,8 @@ -using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Entities.Auditing; namespace LINGYUN.Abp.DataProtection { - public class FakeProtectionObject : Entity, IHasDataAccess + public class FakeProtectionObject : AuditedAggregateRoot, IDataProtected { public virtual string Protect1 { get; set; } public virtual string Protect2 { get; set; } @@ -11,6 +11,13 @@ namespace LINGYUN.Abp.DataProtection public virtual int ProtectNum1 { get; set; } public virtual int ProtectNum2 { get; set; } public virtual int Num3 { get; set; } - public DataAccessOwner Owner { get; set; } + + public FakeProtectionObject() + { + } + + public FakeProtectionObject(int id) : base(id) + { + } } } diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/IFakeProtectionObjectRepository.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/IFakeProtectionObjectRepository.cs index 635746ee8..5088abdfc 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/IFakeProtectionObjectRepository.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/IFakeProtectionObjectRepository.cs @@ -1,8 +1,11 @@ -using Volo.Abp.Domain.Repositories; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; namespace LINGYUN.Abp.DataProtection { - public interface IFakeProtectionObjectRepository : IBasicRepository + public interface IFakeProtectionObjectRepository : IRepository { + Task> GetAllListAsync(); } } diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs index e9a2449ca..8cc9cde89 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs @@ -1,8 +1,18 @@ -using Shouldly; +using LINGYUN.Abp.Authorization.OrganizationUnits; +using LINGYUN.Abp.Authorization.Permissions; +using LINGYUN.Abp.DataProtection.Keywords; +using NSubstitute; +using Shouldly; using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Security.Claims; using System.Threading.Tasks; +using Volo.Abp.Auditing; +using Volo.Abp.Authorization; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; using Volo.Abp.Security.Claims; using Volo.Abp.Uow; using Xunit; @@ -13,195 +23,136 @@ namespace LINGYUN.Abp.DataProtection { private readonly IFakeProtectionObjectRepository _repository; private readonly ICurrentPrincipalAccessor _accessor; + private readonly IDataProtectedResourceStore _store; + private readonly IDataFilter _dataFilter; public ProtectionFieldTests() { _repository = GetRequiredService(); _accessor = GetRequiredService(); + _store = GetRequiredService(); + _dataFilter = GetRequiredService(); } [Fact] - public async virtual Task FakeAsync() + public async virtual Task Should_Protected_Data_By_Repo() { - - var values = new List() - { - new FakeProtectionObject - { - Protect1 = "Protect1", - Protect2 = "Protect1", - Value1 = "Value1", - Value2 = "Value1", - ProtectNum1 = 100, - ProtectNum2 = 200, - Num3 = 400 - }, - new FakeProtectionObject - { - Protect1 = "test", - Protect2 = "Protect2", - Value1 = "Value2", - Value2 = "Value2", - ProtectNum1 = 1000, - ProtectNum2 = 2000, - Num3 = 3000 - }, - new FakeProtectionObject - { - Protect1 = "test1", - Protect2 = "Protect3", - Value1 = "Value3", - Value2 = "Value3", - ProtectNum1 = 10000, - ProtectNum2 = 20000, - Num3 = 300 - }, - new FakeProtectionObject - { - Protect1 = "test3", - Protect2 = "Protect4", - Value1 = "Value4", - Value2 = "Value4", - ProtectNum1 = 10000, - ProtectNum2 = 20000, - Num3 = 300 - } - }; + var validUser = Guid.NewGuid(); await WithUnitOfWorkAsync(async () => { - var user1Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Write, - DataAccessRole.User, - "user1", - [ - new(nameof(FakeProtectionObject.Num3)), - new(nameof(FakeProtectionObject.Value2)), - ]); - var user2Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Write, - DataAccessRole.User, - "user2", - [ - new(nameof(FakeProtectionObject.Value1)), - ]); - var role1Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Write, - DataAccessRole.Role, - "role1", - [ - new(nameof(FakeProtectionObject.Protect1)), - ]); - - var dataAccessRule = new DataAccessRuleInfo( - [ - user1Rule, - user2Rule, - role1Rule, - ]); - - //var rules = new List() - //{ - // new ProtectedFieldRule - // { - // Field = nameof(FakeProtectionObject.Protect1), - // Logic = PredicateOperator.And, - // Operator = ExpressionType.Equal, - // Resource = resource.Resource, - // Value = "test" - // }, - // new ProtectedFieldRule - // { - // Field = nameof(FakeProtectionObject.Num3), - // Logic = PredicateOperator.Or, - // Operator = ExpressionType.LessThanOrEqual, - // Resource = resource.Resource, - // Value = 300 - // }, - //}; - - var unitOfWorkManager = GetRequiredService(); - - unitOfWorkManager.Current.SetAccessRuleInfo(dataAccessRule); - var identity = new ClaimsIdentity(); - identity.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); + identity.AddClaim(new Claim(AbpClaimTypes.UserId, validUser.ToString())); identity.AddClaim(new Claim(AbpClaimTypes.UserName, "user1")); identity.AddClaim(new Claim(AbpClaimTypes.Role, "role1")); identity.AddClaim(new Claim(AbpClaimTypes.Role, "role2")); + identity.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, "00001")); + identity.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, "00001.00002")); using (_accessor.Change(new ClaimsPrincipal(identity))) { + var values = new List() + { + new FakeProtectionObject(1) + { + Protect1 = "Protect1", + Protect2 = "Protect1", + Value1 = "Value1", + Value2 = "Value1", + ProtectNum1 = 100, + ProtectNum2 = 200, + Num3 = 400, + }, + new FakeProtectionObject(2) + { + Protect1 = "test", + Protect2 = "Protect2", + Value1 = "Value2", + Value2 = "Value2", + ProtectNum1 = 1000, + ProtectNum2 = 2000, + Num3 = 3000 + }, + new FakeProtectionObject(3) + { + Protect1 = "test1", + Protect2 = "Protect3", + Value1 = "Value3", + Value2 = "Value3", + ProtectNum1 = 10000, + ProtectNum2 = 20000, + Num3 = 300 + }, + new FakeProtectionObject(4) + { + Protect1 = "test3", + Protect2 = "Protect4", + Value1 = "Value4", + Value2 = "Value4", + ProtectNum1 = 10000, + ProtectNum2 = 20000, + Num3 = 300 + } + }; await _repository.InsertManyAsync(values, true); } + + // role2规则 + var rule2FilterGroup = new DataAccessFilterGroup(); + // 只允许查询Num3小于等于400 + rule2FilterGroup.AddRule(new DataAccessFilterRule(nameof(FakeProtectionObject.Num3), 400, DataAccessFilterOperate.LessOrEqual)); + _store.Set(new DataAccessResource(RolePermissionValueProvider.ProviderName, "role2", typeof(FakeProtectionObject).FullName, DataAccessOperation.Read, rule2FilterGroup)); + + // role3编辑规则 + var rule3WriteAccess = new DataAccessFilterGroup(); + // 只允许编辑自己提交的数据 + rule3WriteAccess.AddRule(new DataAccessFilterRule(nameof(FakeProtectionObject.CreatorId), DataAccessCurrentUserContributor.Name, DataAccessFilterOperate.Equal)); + var rule3WriteAccessCacheItem = new DataAccessResource(RolePermissionValueProvider.ProviderName, "role3", typeof(FakeProtectionObject).FullName, DataAccessOperation.Write, rule3WriteAccess); + // 只允许编辑Num3字段 + rule3WriteAccessCacheItem.AllowProperties.AddRange(new string[] { nameof(FakeProtectionObject.Num3) }); + _store.Set(rule3WriteAccessCacheItem); + + // role1读取规则 + var rule1ReadAccess = new DataAccessFilterGroup(); + // 只允许读取自己提交的数据 + rule1ReadAccess.AddRule(new DataAccessFilterRule(nameof(FakeProtectionObject.CreatorId), DataAccessCurrentUserContributor.Name, DataAccessFilterOperate.Equal)); + var rule1ReadAccessCacheItem = new DataAccessResource(RolePermissionValueProvider.ProviderName, "role1", typeof(FakeProtectionObject).FullName, DataAccessOperation.Read, rule1ReadAccess); + // 只允许读取Num3字段 + rule1ReadAccessCacheItem.AllowProperties.AddRange(new string[] { nameof(FakeProtectionObject.Id), nameof(FakeProtectionObject.Num3) }); + _store.Set(rule1ReadAccessCacheItem); + + + // ou1读取规则 + var ou1ReadAccess = new DataAccessFilterGroup(); + // 允许读本部门及下级部门数据 + // 获取部门树结构列表, 便利增加多个部门条件集 + ou1ReadAccess.AddRule(new DataAccessFilterRule($"{nameof(FakeProtectionObject.CreatorId)}", new List() { validUser, Guid.NewGuid() }, DataAccessFilterOperate.Contains, true)); + //ou1ReadAccess.AddRule(new DataAccessFilterRule($"{nameof(FakeProtectionObject.ExtraProperties)}.{DataAccessKeywords.AUTH_ORGS}", "[00001]", DataAccessFilterOperate.Contains)); + //ou1ReadAccess.AddRule(new DataAccessFilterRule($"{nameof(FakeProtectionObject.ExtraProperties)}.{DataAccessKeywords.AUTH_ORGS}", "[00001.00002]", DataAccessFilterOperate.Contains)); + + var ou1ReadAccessCacheItem = new DataAccessResource(OrganizationUnitPermissionValueProvider.ProviderName, "00001", typeof(FakeProtectionObject).FullName, DataAccessOperation.Read, ou1ReadAccess); + + // 只允许读取Num3字段 + ou1ReadAccessCacheItem.AllowProperties.AddRange(new string[] { nameof(FakeProtectionObject.Id), nameof(FakeProtectionObject.Num3) }); + _store.Set(ou1ReadAccessCacheItem); }); await WithUnitOfWorkAsync(async () => { - var user1Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Read, - DataAccessRole.User, - "user1", - [ - new(nameof(FakeProtectionObject.Num3)), - new(nameof(FakeProtectionObject.Value2)), - ]); - var user2Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Write, - DataAccessRole.User, - "user2", - [ - new(nameof(FakeProtectionObject.Value1)), - ]); - var role1Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Write, - DataAccessRole.Role, - "role1", - [ - new(nameof(FakeProtectionObject.Protect1)), - ]); - - var dataAccessRule = new DataAccessRuleInfo( - [ - user1Rule, - user2Rule, - role1Rule, - ]); - - //var rules = new List() - //{ - // new ProtectedFieldRule - // { - // Field = nameof(FakeProtectionObject.Protect1), - // Logic = PredicateOperator.And, - // Operator = ExpressionType.Equal, - // Resource = resource.Resource, - // Value = "test" - // }, - // new ProtectedFieldRule - // { - // Field = nameof(FakeProtectionObject.Num3), - // Logic = PredicateOperator.Or, - // Operator = ExpressionType.LessThanOrEqual, - // Resource = resource.Resource, - // Value = 300 - // }, - //}; - - var unitOfWorkManager = GetRequiredService(); - unitOfWorkManager.Current.SetAccessRuleInfo(dataAccessRule); + // 标记不启用数据过滤器应该能获取全部数据 + var result = await _repository.GetAllListAsync(); + result.Count.ShouldBe(4); + }); + var readUser = Guid.NewGuid(); + await WithUnitOfWorkAsync(async () => + { var identity2 = new ClaimsIdentity(); - identity2.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); + identity2.AddClaim(new Claim(AbpClaimTypes.UserId, readUser.ToString())); identity2.AddClaim(new Claim(AbpClaimTypes.UserName, "user2")); identity2.AddClaim(new Claim(AbpClaimTypes.Role, "role2")); using (_accessor.Change(identity2)) { + // 应该只能读取到 Num3小于等于400的数据,只有3条 var result = await _repository.GetListAsync(); result.Count.ShouldBe(3); } @@ -209,32 +160,93 @@ namespace LINGYUN.Abp.DataProtection await WithUnitOfWorkAsync(async () => { - var user1Rule = new DataAccessRule( - typeof(FakeProtectionObject).FullName, - DataAccessOperation.Read, - DataAccessRole.User, - "user3", - [ - new(nameof(FakeProtectionObject.Num3)), - new(nameof(FakeProtectionObject.Value2)), - ]); - - var dataAccessRule = new DataAccessRuleInfo( - [ - user1Rule, - ]); - - var unitOfWorkManager = GetRequiredService(); - unitOfWorkManager.Current.SetAccessRuleInfo(dataAccessRule); + var identity3 = new ClaimsIdentity(); + identity3.AddClaim(new Claim(AbpClaimTypes.UserId, readUser.ToString())); + identity3.AddClaim(new Claim(AbpClaimTypes.UserName, "user2")); + identity3.AddClaim(new Claim(AbpOrganizationUnitClaimTypes.OrganizationUnit, "00001")); + using (_accessor.Change(identity3)) + { + // 应该能获取4条数据 + var result = await _repository.GetListAsync(); + result.Count.ShouldBe(4); + } + }); + await WithUnitOfWorkAsync(async () => + { + var identity3 = new ClaimsIdentity(); + identity3.AddClaim(new Claim(AbpClaimTypes.UserId, validUser.ToString())); + identity3.AddClaim(new Claim(AbpClaimTypes.UserName, "user3")); + identity3.AddClaim(new Claim(AbpClaimTypes.Role, "role3")); + using (_accessor.Change(identity3)) + { + var entity = await _repository.FindAsync(1); + entity.Protect1 = "New Protect1"; + entity.Num3 = 100; + // 切换为授权用户应该可以保存数据 + var resultEntity = await _repository.UpdateAsync(entity, true); + // 授权字段应该会保存成功 + resultEntity.Num3.ShouldBe(100); + // 未授权字段应该不会保存成功 + resultEntity.Protect1.ShouldBe("Protect1"); + } + }); + + await WithUnitOfWorkAsync(async () => + { + var identity3 = new ClaimsIdentity(); + identity3.AddClaim(new Claim(AbpClaimTypes.UserId, validUser.ToString())); + identity3.AddClaim(new Claim(AbpClaimTypes.UserName, "user3")); + identity3.AddClaim(new Claim(AbpClaimTypes.Role, "role1")); + // identity3.AddClaim(new Claim(AbpClaimTypes.Role, "role3")); + using (_accessor.Change(identity3)) + { + + //var filterBuilder = GetRequiredService(); + //var group = new DataAccessFilterGroup(); + //group.AddRule(new DataAccessFilterRule(nameof(FakeProtectionObject.Num3), 300, DataAccessFilterOperate.LessOrEqual)); + + //var exp1 = await filterBuilder.BuildAsync(typeof(FakeProtectionObject), DataAccessOperation.Read, group); + //var queryable = await _repository.GetQueryableAsync(); + //var entities = queryable.Where(exp1.Compile().As>()).ToList(); + + var entity = await _repository.FindAsync(1); + + var resultBuilder = GetRequiredService(); + var exp = resultBuilder.Build(typeof(FakeProtectionObject), DataAccessOperation.Read); + var comp = exp.Compile(); + // 使用非泛型接口编译表达式树,对返回结果进行替换 + var resultEntity = comp.DynamicInvoke(entity).As(); + // 未授权字段应返回默认值 + resultEntity.Protect1.ShouldBeNullOrWhiteSpace(); + } + }); + + await WithUnitOfWorkAsync(async () => + { var identity3 = new ClaimsIdentity(); identity3.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); identity3.AddClaim(new Claim(AbpClaimTypes.UserName, "user3")); identity3.AddClaim(new Claim(AbpClaimTypes.Role, "role3")); using (_accessor.Change(identity3)) { - var result = await _repository.GetListAsync(); - result.Count.ShouldBe(0); + var entity = await _repository.FindAsync(1); + + entity.Num3 = 300; + // 对未授权实体的操作应该抛出未授权异常 + await Assert.ThrowsAsync(async () => await _repository.UpdateAsync(entity, true)); + } + }); + + await WithUnitOfWorkAsync(async () => + { + var entity = await _repository.FindAsync(1); + entity.Num3 = 200; + using (_dataFilter.Disable()) + { + // 禁用数据保护过滤器之后应可保存数据 + var resultEntity = await _repository.UpdateAsync(entity); + resultEntity.Num3.ShouldBe(200); } }); } diff --git a/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests.csproj index d20964626..4bbb0fa0e 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests/LINGYUN.Abp.Features.LimitValidation.Redis.Tests.csproj @@ -14,10 +14,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Tests/LINGYUN.Abp.Features.LimitValidation.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Tests/LINGYUN.Abp.Features.LimitValidation.Tests.csproj index 4706f4362..f3342888f 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Tests/LINGYUN.Abp.Features.LimitValidation.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Features.LimitValidation.Tests/LINGYUN.Abp.Features.LimitValidation.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.Localization.Xml.Tests/LINGYUN.Abp.Localization.Xml.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Localization.Xml.Tests/LINGYUN.Abp.Localization.Xml.Tests.csproj index e7c5172c7..c375c0b4c 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Localization.Xml.Tests/LINGYUN.Abp.Localization.Xml.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Localization.Xml.Tests/LINGYUN.Abp.Localization.Xml.Tests.csproj @@ -23,10 +23,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.Location.Baidu.Tests/LINGYUN.Abp.Location.Baidu.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Location.Baidu.Tests/LINGYUN.Abp.Location.Baidu.Tests.csproj index ab2e09527..85f459e7b 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Location.Baidu.Tests/LINGYUN.Abp.Location.Baidu.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Location.Baidu.Tests/LINGYUN.Abp.Location.Baidu.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.Location.Tencent.Tests/LINGYUN.Abp.Location.Tencent.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Location.Tencent.Tests/LINGYUN.Abp.Location.Tencent.Tests.csproj index 4ddb2101d..00b7be49f 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Location.Tencent.Tests/LINGYUN.Abp.Location.Tencent.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Location.Tencent.Tests/LINGYUN.Abp.Location.Tencent.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Nexus.Tests/LINGYUN.Abp.OssManagement.Nexus.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Nexus.Tests/LINGYUN.Abp.OssManagement.Nexus.Tests.csproj index 16ad8c864..d22cffcff 100644 --- a/aspnet-core/tests/LINGYUN.Abp.OssManagement.Nexus.Tests/LINGYUN.Abp.OssManagement.Nexus.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.OssManagement.Nexus.Tests/LINGYUN.Abp.OssManagement.Nexus.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj index 2d6a33797..099233441 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN.Abp.WeChat.Work.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN.Abp.WeChat.Work.Tests.csproj index 49111ca84..43a82d4e2 100644 --- a/aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN.Abp.WeChat.Work.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.WeChat.Work.Tests/LINGYUN.Abp.WeChat.Work.Tests.csproj @@ -13,10 +13,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - runtime; build; native; contentfiles; analyzers; buildtransitive - all -