diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index 7d6295555..d1d055c97 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -573,6 +573,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TextTemplating. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.TextTemplating.Razor", "modules\text-templating\LINGYUN.Abp.TextTemplating.Razor\LINGYUN.Abp.TextTemplating.Razor.csproj", "{5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.PermissionManagement.Application.Contracts", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application.Contracts\LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj", "{35D17AF3-FDCD-4704-969C-E82DBCC0A232}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.PermissionManagement.Application", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application\LINGYUN.Abp.PermissionManagement.Application.csproj", "{984F481B-79FF-4825-917B-944F151694BC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.PermissionManagement.HttpApi", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.HttpApi\LINGYUN.Abp.PermissionManagement.HttpApi.csproj", "{B12BECC4-8A58-4DBD-A5CD-144A507972BB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "feature-management", "feature-management", "{12896A3F-5F7E-4192-8A58-E1D2527109D1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.Application.Contracts", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application.Contracts\LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj", "{F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.Application", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application\LINGYUN.Abp.FeatureManagement.Application.csproj", "{4E8DA436-8FAF-4028-8A0C-E4EEB3615972}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.HttpApi", "modules\feature-management\LINGYUN.Abp.FeatureManagement.HttpApi\LINGYUN.Abp.FeatureManagement.HttpApi.csproj", "{405694F8-0051-4DAE-A991-919FAC36C7DA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1459,6 +1473,30 @@ Global {5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}.Debug|Any CPU.Build.0 = Debug|Any CPU {5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}.Release|Any CPU.ActiveCfg = Release|Any CPU {5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2}.Release|Any CPU.Build.0 = Release|Any CPU + {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35D17AF3-FDCD-4704-969C-E82DBCC0A232}.Release|Any CPU.Build.0 = Release|Any CPU + {984F481B-79FF-4825-917B-944F151694BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {984F481B-79FF-4825-917B-944F151694BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {984F481B-79FF-4825-917B-944F151694BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {984F481B-79FF-4825-917B-944F151694BC}.Release|Any CPU.Build.0 = Release|Any CPU + {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B12BECC4-8A58-4DBD-A5CD-144A507972BB}.Release|Any CPU.Build.0 = Release|Any CPU + {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012}.Release|Any CPU.Build.0 = Release|Any CPU + {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E8DA436-8FAF-4028-8A0C-E4EEB3615972}.Release|Any CPU.Build.0 = Release|Any CPU + {405694F8-0051-4DAE-A991-919FAC36C7DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {405694F8-0051-4DAE-A991-919FAC36C7DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {405694F8-0051-4DAE-A991-919FAC36C7DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {405694F8-0051-4DAE-A991-919FAC36C7DA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1735,6 +1773,13 @@ Global {6AC6AC37-0163-4EF2-A49C-2E0B87F73AE9} = {B1AC656F-8F4C-43D5-B5A0-CCF5F119EA44} {E2019836-1C67-47E4-B3AF-D62F4AFC7679} = {ABD89F39-62D9-439E-8662-BE4F36BFA04F} {5F83F8D0-822B-4316-B7DD-85DAFDFAA0E2} = {ABD89F39-62D9-439E-8662-BE4F36BFA04F} + {35D17AF3-FDCD-4704-969C-E82DBCC0A232} = {CC362C67-6FC1-42B3-A130-8120AA8D790C} + {984F481B-79FF-4825-917B-944F151694BC} = {CC362C67-6FC1-42B3-A130-8120AA8D790C} + {B12BECC4-8A58-4DBD-A5CD-144A507972BB} = {CC362C67-6FC1-42B3-A130-8120AA8D790C} + {12896A3F-5F7E-4192-8A58-E1D2527109D1} = {C5CAD011-DF84-4914-939C-0C029DCEF26F} + {F7A8000A-D8DA-4A1F-B0B2-9A52183F2012} = {12896A3F-5F7E-4192-8A58-E1D2527109D1} + {4E8DA436-8FAF-4028-8A0C-E4EEB3615972} = {12896A3F-5F7E-4192-8A58-E1D2527109D1} + {405694F8-0051-4DAE-A991-919FAC36C7DA} = {12896A3F-5F7E-4192-8A58-E1D2527109D1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln index 6bc440a13..7c3928366 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln @@ -287,7 +287,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.Pe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.CultureMap", "modules\localization\LINGYUN.Abp.Localization.CultureMap\LINGYUN.Abp.Localization.CultureMap.csproj", "{86ED8028-5533-4B5D-8594-C09929F2A553}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization", "localization", "{C056C11F-EC74-4720-ACEA-D4C57DC4736F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization-management", "localization-management", "{C056C11F-EC74-4720-ACEA-D4C57DC4736F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Mvc.Localization", "modules\localization\LINGYUN.Abp.AspNetCore.Mvc.Localization\LINGYUN.Abp.AspNetCore.Mvc.Localization.csproj", "{A09032AD-D895-4D83-8D3D-67FF3285F7A6}" EndProject @@ -444,6 +444,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.MicroService.Internal.ApiGateway", "..\gateways\internal\LINGYUN.MicroService.Internal.ApiGateway\src\LINGYUN.MicroService.Internal.ApiGateway\LINGYUN.MicroService.Internal.ApiGateway.csproj", "{21878B72-9801-41CE-88CD-7195714AE9BA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "feature-management", "feature-management", "{97C36EF3-805E-4B93-9AF6-C1E22AA583B1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "permissions-management", "permissions-management", "{99CB6AD9-92E8-4B9B-99E3-28404AA41655}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FeatureManagement.Application.Contracts", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application.Contracts\LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj", "{2263600B-30CB-4188-925D-92F12F904163}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FeatureManagement.Application", "modules\feature-management\LINGYUN.Abp.FeatureManagement.Application\LINGYUN.Abp.FeatureManagement.Application.csproj", "{2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.FeatureManagement.HttpApi", "modules\feature-management\LINGYUN.Abp.FeatureManagement.HttpApi\LINGYUN.Abp.FeatureManagement.HttpApi.csproj", "{C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.PermissionManagement.Application.Contracts", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application.Contracts\LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj", "{FAD86432-6A95-47DE-8E3A-FC2101753C52}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.PermissionManagement.Application", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.Application\LINGYUN.Abp.PermissionManagement.Application.csproj", "{5F278E32-3A2A-4654-BD3C-B183301382FB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.PermissionManagement.HttpApi", "modules\permissions-management\LINGYUN.Abp.PermissionManagement.HttpApi\LINGYUN.Abp.PermissionManagement.HttpApi.csproj", "{1DB57C74-1C40-4414-B968-937C3C1C157E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1158,6 +1174,30 @@ Global {21878B72-9801-41CE-88CD-7195714AE9BA}.Debug|Any CPU.Build.0 = Debug|Any CPU {21878B72-9801-41CE-88CD-7195714AE9BA}.Release|Any CPU.ActiveCfg = Release|Any CPU {21878B72-9801-41CE-88CD-7195714AE9BA}.Release|Any CPU.Build.0 = Release|Any CPU + {2263600B-30CB-4188-925D-92F12F904163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2263600B-30CB-4188-925D-92F12F904163}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2263600B-30CB-4188-925D-92F12F904163}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2263600B-30CB-4188-925D-92F12F904163}.Release|Any CPU.Build.0 = Release|Any CPU + {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E}.Release|Any CPU.Build.0 = Release|Any CPU + {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8}.Release|Any CPU.Build.0 = Release|Any CPU + {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAD86432-6A95-47DE-8E3A-FC2101753C52}.Release|Any CPU.Build.0 = Release|Any CPU + {5F278E32-3A2A-4654-BD3C-B183301382FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5F278E32-3A2A-4654-BD3C-B183301382FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F278E32-3A2A-4654-BD3C-B183301382FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5F278E32-3A2A-4654-BD3C-B183301382FB}.Release|Any CPU.Build.0 = Release|Any CPU + {1DB57C74-1C40-4414-B968-937C3C1C157E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1DB57C74-1C40-4414-B968-937C3C1C157E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1DB57C74-1C40-4414-B968-937C3C1C157E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1DB57C74-1C40-4414-B968-937C3C1C157E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1375,6 +1415,14 @@ Global {E2BA59EA-769B-4D5B-8032-CB9682D0D73A} = {0D69B63D-F082-4D57-9FF0-355642C56993} {5F0926F3-463D-445B-9746-0A037DC431F9} = {42F31C68-B8B2-4BE0-9AD0-A7DFA6092629} {21878B72-9801-41CE-88CD-7195714AE9BA} = {B4247B78-34BC-4A3F-91A4-661F7DCD6E10} + {97C36EF3-805E-4B93-9AF6-C1E22AA583B1} = {0B58AA48-665A-443F-A6A8-751FB9629DAF} + {99CB6AD9-92E8-4B9B-99E3-28404AA41655} = {0B58AA48-665A-443F-A6A8-751FB9629DAF} + {2263600B-30CB-4188-925D-92F12F904163} = {97C36EF3-805E-4B93-9AF6-C1E22AA583B1} + {2ED0ED0F-15F6-4555-BC97-F5426FCC0C0E} = {97C36EF3-805E-4B93-9AF6-C1E22AA583B1} + {C1023A56-87CE-4227-8F0E-0F9DAA1E20B8} = {97C36EF3-805E-4B93-9AF6-C1E22AA583B1} + {FAD86432-6A95-47DE-8E3A-FC2101753C52} = {99CB6AD9-92E8-4B9B-99E3-28404AA41655} + {5F278E32-3A2A-4654-BD3C-B183301382FB} = {99CB6AD9-92E8-4B9B-99E3-28404AA41655} + {1DB57C74-1C40-4414-B968-937C3C1C157E} = {99CB6AD9-92E8-4B9B-99E3-28404AA41655} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.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/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj new file mode 100644 index 000000000..415515fbf --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN.Abp.FeatureManagement.Application.Contracts.csproj @@ -0,0 +1,23 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs new file mode 100644 index 000000000..e4fbd5a9b --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs @@ -0,0 +1,33 @@ +using Volo.Abp.FeatureManagement.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Localization.ExceptionHandling; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; +using VoloAbpFeatureManagementApplicationContractsModule = Volo.Abp.FeatureManagement.AbpFeatureManagementApplicationContractsModule; + +namespace LINGYUN.Abp.FeatureManagement; + +[DependsOn( + typeof(VoloAbpFeatureManagementApplicationContractsModule))] +public class AbpFeatureManagementApplicationContractsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts"); + }); + + Configure(options => + { + options.MapCodeNamespace(FeatureManagementErrorCodes.Namespace, typeof(AbpFeatureManagementResource)); + }); + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateDto.cs new file mode 100644 index 000000000..8eba14954 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateDto.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public class FeatureDefinitionCreateDto : FeatureDefinitionCreateOrUpdateDto +{ + [Required] + [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxNameLength))] + public string Name { get; set; } + + [Required] + [DynamicStringLength(typeof(FeatureGroupDefinitionRecordConsts), nameof(FeatureGroupDefinitionRecordConsts.MaxNameLength))] + public string GroupName { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateOrUpdateDto.cs new file mode 100644 index 000000000..437dbb7f9 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionCreateOrUpdateDto.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Data; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public abstract class FeatureDefinitionCreateOrUpdateDto : IHasExtraProperties +{ + [Required] + [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxNameLength))] + public string ParentName { get; set; } + + [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxDescriptionLength))] + public string Description { get; set; } + + [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxDefaultValueLength))] + public string DefaultValue { get; set; } + + public bool IsVisibleToClients { get; set; } + + public bool IsAvailableToHost { get; set; } + + public List AllowedProviders { get; set; } = new List(); + + [DynamicStringLength(typeof(FeatureDefinitionRecordConsts), nameof(FeatureDefinitionRecordConsts.MaxValueTypeLength))] + public string ValueType { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary(); +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionDto.cs new file mode 100644 index 000000000..413ab0563 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionDto.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Volo.Abp.Data; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public class FeatureDefinitionDto : IHasExtraProperties +{ + public string GroupName { get; set; } + + public string Name { get; set; } + + public string ParentName { get; set; } + + public string DisplayName { get; set; } + + public string FormatedDisplayName { get; set; } + + public string Description { get; set; } + + public string FormatedDescription { get; set; } + + public string DefaultValue { get; set; } + + public bool IsVisibleToClients { get; set; } + + public bool IsAvailableToHost { get; set; } + + public List AllowedProviders { get; set; } = new List(); + + public string ValueType { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary(); +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionGetListInput.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionGetListInput.cs new file mode 100644 index 000000000..a81654c74 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionGetListInput.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; +public class FeatureDefinitionGetListInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } + + public string GroupName { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionUpdateDto.cs new file mode 100644 index 000000000..9be0e4b3e --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureDefinitionUpdateDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Domain.Entities; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; +public class FeatureDefinitionUpdateDto : FeatureDefinitionCreateOrUpdateDto, IHasConcurrencyStamp +{ + [StringLength(40)] + public string ConcurrencyStamp { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateDto.cs new file mode 100644 index 000000000..1b465d53e --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateDto.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; +public class FeatureGroupDefinitionCreateDto : FeatureGroupDefinitionCreateOrUpdateDto +{ + [Required] + [DynamicStringLength(typeof(FeatureGroupDefinitionRecordConsts), nameof(FeatureGroupDefinitionRecordConsts.MaxNameLength))] + public string Name { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateOrUpdateDto.cs new file mode 100644 index 000000000..67cdb9794 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionCreateOrUpdateDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Data; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public abstract class FeatureGroupDefinitionCreateOrUpdateDto : IHasExtraProperties +{ + [Required] + [DynamicStringLength(typeof(FeatureGroupDefinitionRecordConsts), nameof(FeatureGroupDefinitionRecordConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary(); +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionDto.cs new file mode 100644 index 000000000..1ab58525a --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionDto.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Data; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public class FeatureGroupDefinitionDto : IHasExtraProperties +{ + public string Name { get; set; } + + public string DisplayName { get; set; } + + public string FormatedDisplayName { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionGetListInput.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionGetListInput.cs new file mode 100644 index 000000000..dfeea833e --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionGetListInput.cs @@ -0,0 +1,7 @@ +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; +public class FeatureGroupDefinitionGetListInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionUpdateDto.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionUpdateDto.cs new file mode 100644 index 000000000..dafa11775 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/Dto/FeatureGroupDefinitionUpdateDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Domain.Entities; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; +public class FeatureGroupDefinitionUpdateDto : FeatureGroupDefinitionCreateOrUpdateDto, IHasConcurrencyStamp +{ + [StringLength(40)] + public string ConcurrencyStamp { get; set; } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureDefinitionAppService.cs new file mode 100644 index 000000000..48fda8bf4 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureDefinitionAppService.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public interface IFeatureDefinitionAppService : IApplicationService +{ + Task GetAsync(string name); + + Task DeleteAsync(string name); + + Task CreateAsync(FeatureDefinitionCreateDto input); + + Task UpdateAsync(string name, FeatureDefinitionUpdateDto input); + + Task> GetListAsync(FeatureDefinitionGetListInput input); +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureGroupDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureGroupDefinitionAppService.cs new file mode 100644 index 000000000..c4aa9f19a --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Definitions/IFeatureGroupDefinitionAppService.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +public interface IFeatureGroupDefinitionAppService : IApplicationService +{ + Task GetAsync(string name); + + Task DeleteAsync(string name); + + Task CreateAsync(FeatureGroupDefinitionCreateDto input); + + Task UpdateAsync(string name, FeatureGroupDefinitionUpdateDto input); + + Task> GetListAsync(FeatureGroupDefinitionGetListInput input); +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/FeatureManagementErrorCodes.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/FeatureManagementErrorCodes.cs new file mode 100644 index 000000000..9e3de97e0 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/FeatureManagementErrorCodes.cs @@ -0,0 +1,25 @@ +namespace LINGYUN.Abp.FeatureManagement; +public static class FeatureManagementErrorCodes +{ + public const string Namespace = "FeatureManagement"; + + public static class GroupDefinition + { + private const string Prefix = Namespace + ":001"; + + public const string AlreayNameExists = Prefix + "100"; + + public const string NameNotFount = Prefix + "404"; + } + + public static class Definition + { + private const string Prefix = Namespace + ":002"; + + public const string AlreayNameExists = Prefix + "100"; + + public const string FailedGetGroup = Prefix + "101"; + + public const string NameNotFount = Prefix + "404"; + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/en.json b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/en.json new file mode 100644 index 000000000..e8df379f9 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/en.json @@ -0,0 +1,16 @@ +{ + "culture": "en", + "texts": { + "Permission:FeatureManagement": "Feature Management", + "Permission:GroupDefinitions": "Group Definitions", + "Permission:FeatureDefinitions": "Permission Definitions", + "Permission:Create": "Create", + "Permission:Edit": "Edit", + "Permission:Delete": "Delete", + "FeatureManagement:001100": "Feature group {Name} already exists!", + "FeatureManagement:001404": "Feature group named {Name} not found!", + "FeatureManagement:002100": "Feature {Name} already exists!", + "FeatureManagement:002101": "The group definition of feature {Name} could not be retrieved!", + "FeatureManagement:0021404": "Feature named {Name} not found!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/zh-Hans.json b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/zh-Hans.json new file mode 100644 index 000000000..3d7bcf834 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Localization/Application/Contracts/zh-Hans.json @@ -0,0 +1,15 @@ +{ + "culture": "zh-Hans", + "texts": { + "Permission:GroupDefinitions": "分组定义", + "Permission:FeatureDefinitions": "功能定义", + "Permission:Create": "新增", + "Permission:Edit": "修改", + "Permission:Delete": "删除", + "FeatureManagement:001100": "功能分组 {Name} 已经存在!", + "FeatureManagement:001404": "没有找到名为 {Name} 的功能分组!", + "FeatureManagement:002100": "功能 {Name} 已经存在!", + "FeatureManagement:002101": "未能检索到功能 {Name} 所在分组定义!", + "FeatureManagement:0021404": "没有找到名为 {Name} 的功能定义!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionDefinitionProvider.cs new file mode 100644 index 000000000..5c2eb752d --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionDefinitionProvider.cs @@ -0,0 +1,53 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.FeatureManagement.Localization; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.FeatureManagement.Permissions; + +public class FeatureManagementPermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + var featureGroup = context.GetGroup(FeatureManagementPermissionNames.GroupName); + + var groupDefinition = featureGroup.AddPermission( + FeatureManagementPermissionNames.GroupDefinition.Default, + L("Permission:GroupDefinitions"), + MultiTenancySides.Host); + groupDefinition.AddChild( + FeatureManagementPermissionNames.GroupDefinition.Create, + L("Permission:Create"), + MultiTenancySides.Host); + groupDefinition.AddChild( + FeatureManagementPermissionNames.GroupDefinition.Update, + L("Permission:Edit"), + MultiTenancySides.Host); + groupDefinition.AddChild( + FeatureManagementPermissionNames.GroupDefinition.Delete, + L("Permission:Delete"), + MultiTenancySides.Host); + + var featureDefinition = featureGroup.AddPermission( + FeatureManagementPermissionNames.Definition.Default, + L("Permission:FeatureDefinitions"), + MultiTenancySides.Host); + featureDefinition.AddChild( + FeatureManagementPermissionNames.Definition.Create, + L("Permission:Create"), + MultiTenancySides.Host); + featureDefinition.AddChild( + FeatureManagementPermissionNames.Definition.Update, + L("Permission:Edit"), + MultiTenancySides.Host); + featureDefinition.AddChild( + FeatureManagementPermissionNames.Definition.Delete, + L("Permission:Delete"), + MultiTenancySides.Host); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionNames.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionNames.cs new file mode 100644 index 000000000..ea138177e --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application.Contracts/LINGYUN/Abp/FeatureManagement/Permissions/FeatureManagementPermissionNames.cs @@ -0,0 +1,25 @@ +using Volo.Abp.FeatureManagement; + +namespace LINGYUN.Abp.FeatureManagement.Permissions; +public static class FeatureManagementPermissionNames +{ + public const string GroupName = FeatureManagementPermissions.GroupName; + + public static class GroupDefinition + { + public const string Default = GroupName + ".GroupDefinitions"; + + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } + + public static class Definition + { + public const string Default = GroupName + ".Definitions"; + + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xml b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xsd b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.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/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN.Abp.FeatureManagement.Application.csproj b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN.Abp.FeatureManagement.Application.csproj new file mode 100644 index 000000000..3e961d82a --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN.Abp.FeatureManagement.Application.csproj @@ -0,0 +1,19 @@ + + + + + + + net7.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs new file mode 100644 index 000000000..bc5573f63 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Modularity; +using VoloAbpFeatureManagementApplicationModule = Volo.Abp.FeatureManagement.AbpFeatureManagementApplicationModule; + +namespace LINGYUN.Abp.FeatureManagement; + +[DependsOn( + typeof(AbpFeatureManagementApplicationContractsModule), + typeof(VoloAbpFeatureManagementApplicationModule))] +public class AbpFeatureManagementApplicationModule : AbpModule +{ +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/DynamicFeatureDefinitionStoreCacheInvalidator.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/DynamicFeatureDefinitionStoreCacheInvalidator.cs new file mode 100644 index 000000000..d7403b7a5 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/DynamicFeatureDefinitionStoreCacheInvalidator.cs @@ -0,0 +1,64 @@ +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Threading; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; +public class DynamicPermissionDefinitionStoreCacheInvalidator : + ILocalEventHandler>, + ILocalEventHandler>, + ITransientDependency +{ + private readonly IDynamicFeatureDefinitionStoreInMemoryCache _storeCache; + + private readonly IClock _clock; + private readonly IDistributedCache _distributedCache; + private readonly AbpDistributedCacheOptions _cacheOptions; + + public DynamicPermissionDefinitionStoreCacheInvalidator( + IClock clock, + IDistributedCache distributedCache, + IDynamicFeatureDefinitionStoreInMemoryCache storeCache, + IOptions cacheOptions) + { + _storeCache = storeCache; + _clock = clock; + _distributedCache = distributedCache; + _cacheOptions = cacheOptions.Value; + } + + public async virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + await RemoveStampInDistributedCacheAsync(); + } + + public async virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + await RemoveStampInDistributedCacheAsync(); + } + + protected async virtual Task RemoveStampInDistributedCacheAsync() + { + using (await _storeCache.SyncSemaphore.LockAsync()) + { + var cacheKey = GetCommonStampCacheKey(); + + await _distributedCache.RemoveAsync(cacheKey); + + _storeCache.CacheStamp = Guid.NewGuid().ToString(); + _storeCache.LastCheckTime = _clock.Now.AddMinutes(-5); + } + } + + protected virtual string GetCommonStampCacheKey() + { + return $"{_cacheOptions.KeyPrefix}_AbpInMemoryFeatureCacheStamp"; + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionAppService.cs new file mode 100644 index 000000000..1d801c1c2 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionAppService.cs @@ -0,0 +1,334 @@ +using LINGYUN.Abp.FeatureManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +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 Volo.Abp.Application.Dtos; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Features; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +[Authorize(FeatureManagementPermissionNames.Definition.Default)] +public class FeatureDefinitionAppService : FeatureManagementAppServiceBase, IFeatureDefinitionAppService +{ + private readonly ILocalizableStringSerializer _localizableStringSerializer; + private readonly IFeatureDefinitionManager _featureDefinitionManager; + + private readonly IFeatureDefinitionRecordRepository _definitionRepository; + private readonly IRepository _definitionBasicRepository; + + public FeatureDefinitionAppService( + ILocalizableStringSerializer localizableStringSerializer, + IFeatureDefinitionManager featureDefinitionManager, + IFeatureDefinitionRecordRepository definitionRepository, + IRepository definitionBasicRepository) + { + _localizableStringSerializer = localizableStringSerializer; + _featureDefinitionManager = featureDefinitionManager; + _definitionRepository = definitionRepository; + _definitionBasicRepository = definitionBasicRepository; + } + + [Authorize(FeatureManagementPermissionNames.Definition.Create)] + public async virtual Task CreateAsync(FeatureDefinitionCreateDto input) + { + if (await _featureDefinitionManager.GetOrNullAsync(input.Name) != null) + { + throw new BusinessException(FeatureManagementErrorCodes.Definition.AlreayNameExists) + .WithData(nameof(FeatureDefinitionRecord.Name), input.Name); + } + + var groupDefinition = await _featureDefinitionManager.GetGroupOrNullAsync(input.GroupName); + if (groupDefinition == null) + { + throw new BusinessException(FeatureManagementErrorCodes.GroupDefinition.NameNotFount) + .WithData(nameof(FeatureGroupDefinitionRecord.Name), input.GroupName); + } + + var definitionRecord = new FeatureDefinitionRecord( + GuidGenerator.Create(), + groupDefinition.Name, + input.Name, + input.ParentName, + input.DisplayName, + input.Description, + input.DefaultValue, + input.IsVisibleToClients, + input.IsAvailableToHost, + valueType: input.ValueType); + + if (input.AllowedProviders.Any()) + { + definitionRecord.AllowedProviders = input.AllowedProviders.JoinAsString(","); + } + + foreach (var property in input.ExtraProperties) + { + definitionRecord.SetProperty(property.Key, property.Value); + } + + await _definitionRepository.InsertAsync(definitionRecord); + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await DefinitionRecordToDto(definitionRecord); + + return dto; + } + + [Authorize(FeatureManagementPermissionNames.Definition.Delete)] + public async virtual Task DeleteAsync(string name) + { + var definitionRecord = await FindByNameAsync(name); + + if (definitionRecord == null) + { + return; + } + + await _definitionRepository.DeleteAsync(definitionRecord); + } + + public async virtual Task GetAsync(string name) + { + var definition = await _featureDefinitionManager.GetOrNullAsync(name); + if (definition == null) + { + throw new BusinessException(FeatureManagementErrorCodes.Definition.NameNotFount) + .WithData(nameof(FeatureDefinitionRecord.Name), name); + } + + var groupDefinition = await GetGroupDefinition(definition); + + var dto = await DefinitionToDto(groupDefinition, definition); + + return dto; + } + + public async virtual Task> GetListAsync(FeatureDefinitionGetListInput input) + { + var permissions = new List(); + + IReadOnlyList definitionPermissions; + + if (!input.GroupName.IsNullOrWhiteSpace()) + { + var group = await _featureDefinitionManager.GetGroupOrNullAsync(input.GroupName); + if (group == null) + { + return new PagedResultDto(0, permissions); + } + + definitionPermissions = group.GetFeaturesWithChildren(); + } + else + { + definitionPermissions = await _featureDefinitionManager.GetAllAsync(); + } + + var definitionFilter = definitionPermissions.AsQueryable() + .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter) || + (x.Parent != null && x.Parent.Name.Contains(input.Filter))); + + var sorting = input.Sorting; + if (sorting.IsNullOrWhiteSpace()) + { + sorting = nameof(FeatureDefinitionRecord.Name); + } + + var filterDefinitionCount = definitionFilter.Count(); + var filterDefinitions = definitionFilter + .OrderBy(sorting) + .PageBy(input.SkipCount, input.MaxResultCount); + + foreach (var definition in filterDefinitions) + { + var groupDefinition = await GetGroupDefinition(definition); + var Dto = await DefinitionToDto(groupDefinition, definition); + + permissions.Add(Dto); + } + + return new PagedResultDto(filterDefinitionCount, permissions); + } + + [Authorize(FeatureManagementPermissionNames.Definition.Update)] + public async virtual Task UpdateAsync(string name, FeatureDefinitionUpdateDto input) + { + var definition = await _featureDefinitionManager.GetAsync(name); + var definitionRecord = await FindByNameAsync(name); + + if (definitionRecord == null) + { + var groupDefinition = await GetGroupDefinition(definition); + definitionRecord = new FeatureDefinitionRecord( + GuidGenerator.Create(), + groupDefinition.Name, + name, + input.ParentName, + input.DisplayName, + input.Description, + input.DefaultValue, + input.IsVisibleToClients, + input.IsAvailableToHost, + valueType: input.ValueType); + + if (input.AllowedProviders.Any()) + { + definitionRecord.AllowedProviders = input.AllowedProviders.JoinAsString(","); + } + + foreach (var property in input.ExtraProperties) + { + definitionRecord.SetProperty(property.Key, property.Value); + } + + definitionRecord = await _definitionBasicRepository.InsertAsync(definitionRecord); + } + else + { + definitionRecord.ExtraProperties.Clear(); + foreach (var property in input.ExtraProperties) + { + definitionRecord.SetProperty(property.Key, property.Value); + } + + if (input.AllowedProviders.Any()) + { + definitionRecord.AllowedProviders = input.AllowedProviders.JoinAsString(","); + } + + if (!string.Equals(definitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) + { + definitionRecord.DisplayName = input.DisplayName; + } + + if (!string.Equals(definitionRecord.Description, input.Description, StringComparison.InvariantCultureIgnoreCase)) + { + definitionRecord.Description = input.Description; + } + + if (!string.Equals(definitionRecord.DefaultValue, input.DefaultValue, StringComparison.InvariantCultureIgnoreCase)) + { + definitionRecord.DefaultValue = input.DefaultValue; + } + + if (!string.Equals(definitionRecord.ValueType, input.ValueType, StringComparison.InvariantCultureIgnoreCase)) + { + definitionRecord.ValueType = input.ValueType; + } + + definitionRecord.IsAvailableToHost = input.IsAvailableToHost; + definitionRecord.IsVisibleToClients = input.IsVisibleToClients; + + definitionRecord = await _definitionBasicRepository.UpdateAsync(definitionRecord); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await DefinitionRecordToDto(definitionRecord); + + return dto; + } + + protected async virtual Task FindByNameAsync(string name) + { + var DefinitionFilter = await _definitionBasicRepository.GetQueryableAsync(); + + var definitionRecord = await AsyncExecuter.FirstOrDefaultAsync( + DefinitionFilter.Where(x => x.Name == name)); + + return definitionRecord; + } + + protected async virtual Task GetGroupDefinition(FeatureDefinition definition) + { + var groups = await _featureDefinitionManager.GetGroupsAsync(); + + foreach (var group in groups) + { + if (group.GetFeatureOrNull(definition.Name) != null) + { + return group; + } + } + + throw new BusinessException(FeatureManagementErrorCodes.Definition.FailedGetGroup) + .WithData(nameof(FeatureDefinitionRecord.Name), definition.Name); + } + + protected async virtual Task DefinitionRecordToDto(FeatureDefinitionRecord definitionRecord) + { + var dto = new FeatureDefinitionDto + { + Name = definitionRecord.Name, + GroupName = definitionRecord.GroupName, + ParentName = definitionRecord.ParentName, + IsAvailableToHost = definitionRecord.IsAvailableToHost, + IsVisibleToClients = definitionRecord.IsVisibleToClients, + DefaultValue = definitionRecord.DefaultValue, + ValueType = definitionRecord.ValueType, + AllowedProviders = definitionRecord.AllowedProviders.Split(',').ToList(), + FormatedDescription = definitionRecord.Description, + FormatedDisplayName = definitionRecord.DisplayName, + }; + + var displayName = _localizableStringSerializer.Deserialize(definitionRecord.DisplayName); + dto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory); + + if (!definitionRecord.Description.IsNullOrWhiteSpace()) + { + var description = _localizableStringSerializer.Deserialize(definitionRecord.Description); + dto.Description = await description.LocalizeAsync(StringLocalizerFactory); + } + + foreach (var property in definitionRecord.ExtraProperties) + { + dto.SetProperty(property.Key, property.Value); + } + + return dto; + } + + protected async virtual Task DefinitionToDto(FeatureGroupDefinition groupDefinition, FeatureDefinition definition) + { + var dto = new FeatureDefinitionDto + { + Name = definition.Name, + GroupName = groupDefinition.Name, + ParentName = definition.Parent?.Name, + DefaultValue = definition.DefaultValue, + AllowedProviders = definition.AllowedProviders, + IsAvailableToHost = definition.IsAvailableToHost, + IsVisibleToClients = definition.IsVisibleToClients, + ValueType = definition.ValueType.Name, + }; + + if (definition.DisplayName != null) + { + dto.DisplayName = await definition.DisplayName.LocalizeAsync(StringLocalizerFactory); + dto.FormatedDisplayName = _localizableStringSerializer.Serialize(definition.DisplayName); + } + + if (definition.Description != null) + { + dto.Description = await definition.Description.LocalizeAsync(StringLocalizerFactory); + dto.FormatedDescription = _localizableStringSerializer.Serialize(definition.Description); + } + + foreach (var property in definition.Properties) + { + dto.SetProperty(property.Key, property.Value); + } + + return dto; + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionAppService.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionAppService.cs new file mode 100644 index 000000000..d186b2006 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionAppService.cs @@ -0,0 +1,215 @@ +using LINGYUN.Abp.FeatureManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Features; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.FeatureManagement.Definitions; + +[Authorize(FeatureManagementPermissionNames.GroupDefinition.Default)] +public class FeatureGroupDefinitionAppService : FeatureManagementAppServiceBase, IFeatureGroupDefinitionAppService +{ + private readonly ILocalizableStringSerializer _localizableStringSerializer; + private readonly IFeatureDefinitionManager _featureDefinitionManager; + + private readonly IFeatureGroupDefinitionRecordRepository _groupDefinitionRepository; + private readonly IRepository _groupDefinitionBasicRepository; + + public FeatureGroupDefinitionAppService( + ILocalizableStringSerializer localizableStringSerializer, + IFeatureDefinitionManager featureDefinitionManager, + IFeatureGroupDefinitionRecordRepository groupDefinitionRepository, + IRepository groupDefinitionBasicRepository) + { + _localizableStringSerializer = localizableStringSerializer; + _featureDefinitionManager = featureDefinitionManager; + _groupDefinitionRepository = groupDefinitionRepository; + _groupDefinitionBasicRepository = groupDefinitionBasicRepository; + } + + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Create)] + public async virtual Task CreateAsync(FeatureGroupDefinitionCreateDto input) + { + if (await _featureDefinitionManager.GetGroupOrNullAsync(input.Name) != null) + { + throw new BusinessException(FeatureManagementErrorCodes.GroupDefinition.AlreayNameExists) + .WithData(nameof(FeatureGroupDefinitionRecord.Name), input.Name); + } + + var groupDefinitionRecord = new FeatureGroupDefinitionRecord( + GuidGenerator.Create(), + input.Name, + input.DisplayName); + + foreach (var property in input.ExtraProperties) + { + groupDefinitionRecord.SetProperty(property.Key, property.Value); + } + + await _groupDefinitionRepository.InsertAsync(groupDefinitionRecord); + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord); + + return dto; + } + + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)] + public async virtual Task DeleteAsync(string name) + { + var groupDefinitionRecord = await FindByNameAsync(name); + + if (groupDefinitionRecord == null) + { + return; + } + + await _groupDefinitionRepository.DeleteAsync(groupDefinitionRecord); + } + + public async virtual Task GetAsync(string name) + { + var groupDefinition = await _featureDefinitionManager.GetGroupOrNullAsync(name); + if (groupDefinition == null) + { + throw new BusinessException(FeatureManagementErrorCodes.GroupDefinition.NameNotFount) + .WithData(nameof(FeatureGroupDefinitionRecord.Name), name); + } + + var dto = await GroupDefinitionToDto(groupDefinition); + + return dto; + } + + public async virtual Task> GetListAsync(FeatureGroupDefinitionGetListInput input) + { + var groups = new List(); + + var groupDefinitions = await _featureDefinitionManager.GetGroupsAsync(); + + var groupDefinitionFilter = groupDefinitions.AsQueryable() + .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter)); + + var sorting = input.Sorting; + if (sorting.IsNullOrWhiteSpace()) + { + sorting = nameof(FeatureDefinitionRecord.Name); + } + + var filterGroupDefinitionCount = groupDefinitionFilter.Count(); + var filterGroupDefinitions = groupDefinitionFilter + .OrderBy(sorting) + .PageBy(input.SkipCount, input.MaxResultCount); + + foreach (var groupDefinition in filterGroupDefinitions) + { + var groupDto = await GroupDefinitionToDto(groupDefinition); + + groups.Add(groupDto); + } + + return new PagedResultDto(filterGroupDefinitionCount, groups); + } + + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Update)] + public async virtual Task UpdateAsync(string name, FeatureGroupDefinitionUpdateDto input) + { + var groupDefinitionRecord = await FindByNameAsync(name); + + if (groupDefinitionRecord == null) + { + groupDefinitionRecord = new FeatureGroupDefinitionRecord( + GuidGenerator.Create(), + name, + input.DisplayName); + + foreach (var property in input.ExtraProperties) + { + groupDefinitionRecord.SetProperty(property.Key, property.Value); + } + + groupDefinitionRecord = await _groupDefinitionBasicRepository.InsertAsync(groupDefinitionRecord); + } + else + { + groupDefinitionRecord.ExtraProperties.Clear(); + foreach (var property in input.ExtraProperties) + { + groupDefinitionRecord.SetProperty(property.Key, property.Value); + } + + if (!string.Equals(groupDefinitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) + { + groupDefinitionRecord.DisplayName = input.DisplayName; + } + + groupDefinitionRecord = await _groupDefinitionBasicRepository.UpdateAsync(groupDefinitionRecord); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord); + + return dto; + } + + protected async virtual Task FindByNameAsync(string name) + { + var groupDefinitionFilter = await _groupDefinitionBasicRepository.GetQueryableAsync(); + + var groupDefinitionRecord = await AsyncExecuter.FirstOrDefaultAsync( + groupDefinitionFilter.Where(x => x.Name == name)); + + return groupDefinitionRecord; + } + + protected async virtual Task GroupDefinitionRecordToDto(FeatureGroupDefinitionRecord groupDefinitionRecord) + { + var groupDto = new FeatureGroupDefinitionDto + { + Name = groupDefinitionRecord.Name, + FormatedDisplayName = groupDefinitionRecord.DisplayName, + }; + + var displayName = _localizableStringSerializer.Deserialize(groupDefinitionRecord.DisplayName); + groupDto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory); + + foreach (var property in groupDefinitionRecord.ExtraProperties) + { + groupDto.SetProperty(property.Key, property.Value); + } + + return groupDto; + } + + protected async virtual Task GroupDefinitionToDto(FeatureGroupDefinition groupDefinition) + { + var groupDto = new FeatureGroupDefinitionDto + { + Name = groupDefinition.Name + }; + + if (groupDefinition.DisplayName != null) + { + groupDto.DisplayName = await groupDefinition.DisplayName.LocalizeAsync(StringLocalizerFactory); + groupDto.FormatedDisplayName = _localizableStringSerializer.Serialize(groupDefinition.DisplayName); + } + + foreach (var property in groupDefinition.Properties) + { + groupDto.SetProperty(property.Key, property.Value); + } + + return groupDto; + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/FeatureGroupDefinitionExtensions.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/FeatureGroupDefinitionExtensions.cs new file mode 100644 index 000000000..d712d9c48 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/FeatureGroupDefinitionExtensions.cs @@ -0,0 +1,36 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace Volo.Abp.Features; +public static class FeatureGroupDefinitionExtensions +{ + public static FeatureDefinition GetFeatureOrNull( + this FeatureGroupDefinition group, + [NotNull] string name) + { + Check.NotNull(name, nameof(name)); + + return GetFeatureOrNullRecursively(group.Features, name); + } + + private static FeatureDefinition GetFeatureOrNullRecursively( + IReadOnlyList features, + string name) + { + foreach (var feature in features) + { + if (feature.Name == name) + { + return feature; + } + + var childFeature = GetFeatureOrNullRecursively(feature.Children, name); + if (childFeature != null) + { + return childFeature; + } + } + + return null; + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/IFeatureDefinitionManagerExtensions.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/IFeatureDefinitionManagerExtensions.cs new file mode 100644 index 000000000..c19f8f8d0 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.Application/Volo/Abp/Features/IFeatureDefinitionManagerExtensions.cs @@ -0,0 +1,16 @@ +using System.Linq; +using System.Threading.Tasks; + +namespace Volo.Abp.Features; +public static class IPermissionDefinitionManagerExtensions +{ + public async static Task GetGroupOrNullAsync( + this IFeatureDefinitionManager featureDefinitionManager, + string name + ) + { + var groups = await featureDefinitionManager.GetGroupsAsync(); + + return groups.FirstOrDefault(x => x.Name == name); + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xml b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.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/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN.Abp.FeatureManagement.HttpApi.csproj b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN.Abp.FeatureManagement.HttpApi.csproj new file mode 100644 index 000000000..ba8a44267 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN.Abp.FeatureManagement.HttpApi.csproj @@ -0,0 +1,19 @@ + + + + + + + net7.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs new file mode 100644 index 000000000..a2069e501 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.FeatureManagement.Localization; +using Volo.Abp.Modularity; +using VoloAbpFeatureManagementHttpApiModule = Volo.Abp.FeatureManagement.AbpFeatureManagementHttpApiModule; + +namespace LINGYUN.Abp.FeatureManagement.HttpApi; + +[DependsOn( + typeof(AbpFeatureManagementApplicationContractsModule), + typeof(VoloAbpFeatureManagementHttpApiModule))] +public class AbpFeatureManagementHttpApiModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(delegate (IMvcBuilder mvcBuilder) + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFeatureManagementHttpApiModule)!.Assembly); + }); + + PreConfigure(options => + { + options.AddAssemblyResource( + typeof(AbpFeatureManagementResource), + typeof(AbpFeatureManagementApplicationContractsModule).Assembly); + }); + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionController.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionController.cs new file mode 100644 index 000000000..e7bb8be4d --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureDefinitionController.cs @@ -0,0 +1,62 @@ +using LINGYUN.Abp.FeatureManagement.Definitions; +using LINGYUN.Abp.FeatureManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.FeatureManagement; + +namespace LINGYUN.Abp.FeatureManagement.HttpApi.Definitions; + +[Controller] +[Authorize(FeatureManagementPermissionNames.Definition.Default)] +[RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)] +[Area(FeatureManagementRemoteServiceConsts.ModuleName)] +[Route("api/feature-management/definitions")] +public class FeatureDefinitionController : FeatureManagementControllerBase, IFeatureDefinitionAppService +{ + private readonly IFeatureDefinitionAppService _service; + + public FeatureDefinitionController(IFeatureDefinitionAppService service) + { + _service = service; + } + + [HttpPost] + [Authorize(FeatureManagementPermissionNames.Definition.Create)] + public virtual Task CreateAsync(FeatureDefinitionCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{name}")] + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)] + public virtual Task DeleteAsync(string name) + { + return _service.DeleteAsync(name); + } + + [HttpGet] + [Route("{name}")] + [Authorize(FeatureManagementPermissionNames.Definition.Delete)] + public virtual Task GetAsync(string name) + { + return _service.GetAsync(name); + } + + [HttpGet] + public virtual Task> GetListAsync(FeatureDefinitionGetListInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{name}")] + [Authorize(FeatureManagementPermissionNames.Definition.Update)] + public virtual Task UpdateAsync(string name, FeatureDefinitionUpdateDto input) + { + return _service.UpdateAsync(name, input); + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionController.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionController.cs new file mode 100644 index 000000000..0df8db38b --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/Definitions/FeatureGroupDefinitionController.cs @@ -0,0 +1,62 @@ +using LINGYUN.Abp.FeatureManagement.Definitions; +using LINGYUN.Abp.FeatureManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.FeatureManagement; + +namespace LINGYUN.Abp.FeatureManagement.HttpApi.Definitions; + +[Controller] +[Authorize(FeatureManagementPermissionNames.GroupDefinition.Default)] +[RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)] +[Area(FeatureManagementRemoteServiceConsts.ModuleName)] +[Route("api/feature-management/definitions/groups")] +public class FeatureGroupDefinitionController : FeatureManagementControllerBase, IFeatureGroupDefinitionAppService +{ + private readonly IFeatureGroupDefinitionAppService _service; + + public FeatureGroupDefinitionController(IFeatureGroupDefinitionAppService service) + { + _service = service; + } + + [HttpPost] + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Create)] + public virtual Task CreateAsync(FeatureGroupDefinitionCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{name}")] + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)] + public virtual Task DeleteAsync(string name) + { + return _service.DeleteAsync(name); + } + + [HttpGet] + [Route("{name}")] + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Delete)] + public virtual Task GetAsync(string name) + { + return _service.GetAsync(name); + } + + [HttpGet] + public virtual Task> GetListAsync(FeatureGroupDefinitionGetListInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{name}")] + [Authorize(FeatureManagementPermissionNames.GroupDefinition.Update)] + public virtual Task UpdateAsync(string name, FeatureGroupDefinitionUpdateDto input) + { + return _service.UpdateAsync(name, input); + } +} diff --git a/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/FeatureManagementControllerBase.cs b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/FeatureManagementControllerBase.cs new file mode 100644 index 000000000..81aa88098 --- /dev/null +++ b/aspnet-core/modules/feature-management/LINGYUN.Abp.FeatureManagement.HttpApi/LINGYUN/Abp/FeatureManagement/FeatureManagementControllerBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.FeatureManagement.Localization; + +namespace LINGYUN.Abp.FeatureManagement.HttpApi; + +public abstract class FeatureManagementControllerBase : AbpControllerBase +{ + protected FeatureManagementControllerBase() + { + LocalizationResource = typeof(AbpFeatureManagementResource); + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs index 7ca157451..2e92f56ee 100644 --- a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/AbpLocalizationPersistenceModule.cs @@ -11,5 +11,10 @@ public class AbpLocalizationPersistenceModule : AbpModule public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddHostedService(); + + Configure(options => + { + options.GlobalContributors.Add(); + }); } } diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/DefaultStaticLocalizationSaver.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/DefaultStaticLocalizationSaver.cs new file mode 100644 index 000000000..ba3262c45 --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/DefaultStaticLocalizationSaver.cs @@ -0,0 +1,135 @@ +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.Localization.Persistence; + +[Dependency(ReplaceServices = true)] +public class DefaultStaticLocalizationSaver : IStaticLocalizationSaver, ITransientDependency +{ + protected ILocalizationPersistenceWriter LocalizationPersistenceWriter { get; } + + protected AbpLocalizationOptions LocalizationOptions { get; } + protected IServiceProvider ServiceProvider { get; } + protected AbpLocalizationPersistenceOptions LocalizationPersistenceOptions { get; } + + public DefaultStaticLocalizationSaver( + IServiceProvider serviceProvider, + ILocalizationPersistenceWriter localizationPersistenceWriter, + IOptions localizationOptions, + IOptions localizationPersistenceOptions) + { + ServiceProvider = serviceProvider; + LocalizationPersistenceWriter = localizationPersistenceWriter; + LocalizationOptions = localizationOptions.Value; + LocalizationPersistenceOptions = localizationPersistenceOptions.Value; + } + + [UnitOfWork] + public async virtual Task SaveAsync() + { + if (!LocalizationPersistenceOptions.SaveStaticLocalizationsToPersistence) + { + return; + } + + var canWriterTexts = new List(); + + foreach (var localizationResource in LocalizationOptions.Resources) + { + if (ShouldSaveToPersistence(localizationResource.Value)) + { + if (!await LocalizationPersistenceWriter.WriteResourceAsync(localizationResource.Value)) + { + continue; + } + + foreach (var language in LocalizationOptions.Languages) + { + if (!await LocalizationPersistenceWriter.WriteLanguageAsync(language)) + { + continue; + } + + using (CultureHelper.Use(language.CultureName, language.UiCultureName)) + { + await FillCanWriterTextxAsync(localizationResource.Value, language, canWriterTexts); + } + } + } + } + + if (canWriterTexts.Any()) + { + await LocalizationPersistenceWriter.WriteTextsAsync(canWriterTexts); + } + } + + protected virtual bool ShouldSaveToPersistence(LocalizationResourceBase localizationResource) + { + var saveResource = false; + if (localizationResource.Contributors.Exists(IsMatchSaveToPersistenceContributor)) + { + saveResource = true; + } + if (!saveResource) + { + saveResource = LocalizationPersistenceOptions + .SaveToPersistenceResources + .Contains(localizationResource.ResourceName); + } + + return saveResource; + } + + protected virtual bool IsMatchSaveToPersistenceContributor(ILocalizationResourceContributor contributor) + { + return typeof(LocalizationSaveToPersistenceContributor).IsAssignableFrom(contributor.GetType()); + } + + protected async virtual Task FillCanWriterTextxAsync( + LocalizationResourceBase localizationResource, + LanguageInfo language, + List canWriterTexts) + { + var fillTexts = new Dictionary(); + var context = new LocalizationResourceInitializationContext(localizationResource, ServiceProvider); + foreach (var contributor in localizationResource.Contributors) + { + if (contributor.IsDynamic) + { + continue; + } + + contributor.Initialize(context); + + await contributor.FillAsync(language.CultureName, fillTexts); + } + + var existsKeys = await LocalizationPersistenceWriter.GetExistsTextsAsync( + localizationResource.ResourceName, + language.CultureName, + fillTexts.Values.Select(x => x.Name)); + + var notExistsKeys = fillTexts.Values.Where(x => !existsKeys.Contains(x.Name)); + + foreach (var notExistsKey in notExistsKeys) + { + if (!canWriterTexts.Any(x => x.CultureName == language.CultureName && x.Name == notExistsKey.Name)) + { + canWriterTexts.Add( + new LocalizableStringText( + localizationResource.ResourceName, + language.CultureName, + notExistsKey.Name, + notExistsKey.Value)); + } + } + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceReader.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceReader.cs new file mode 100644 index 000000000..7f2bc4388 --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceReader.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Localization; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Localization.Persistence; + +public interface ILocalizationPersistenceReader +{ + LocalizedString GetOrNull(string resourceName, string cultureName, string name); + + void Fill(string resourceName, string cultureName, Dictionary dictionary); + + Task FillAsync(string resourceName, string cultureName, Dictionary dictionary); + + Task> GetSupportedCulturesAsync(); +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceWriter.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceWriter.cs new file mode 100644 index 000000000..ee5826b6f --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/ILocalizationPersistenceWriter.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Localization.Persistence; +public interface ILocalizationPersistenceWriter +{ + Task WriteLanguageAsync( + LanguageInfo language, + CancellationToken cancellationToken = default); + + Task WriteResourceAsync( + LocalizationResourceBase resource, + CancellationToken cancellationToken = default); + + Task> GetExistsTextsAsync( + string resourceName, + string cultureName, + IEnumerable keys, + CancellationToken cancellationToken = default); + + Task WriteTextsAsync( + IEnumerable texts, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizableStringText.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizableStringText.cs new file mode 100644 index 000000000..07dd33a80 --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizableStringText.cs @@ -0,0 +1,24 @@ +namespace LINGYUN.Abp.Localization.Persistence; +public class LocalizableStringText +{ + public LocalizableStringText( + string resourceName, + string cultureName, + string name, + string value) + { + ResourceName = resourceName; + CultureName = cultureName; + Name = name; + Value = value; + } + + public string ResourceName { get; set; } + public string CultureName { get; set; } + public string Name { get; set; } + public string Value { get; set; } + public override string ToString() + { + return $"[R]:{ResourceName},[C]:{CultureName ?? ""},[N]:{Name},[V]:{Value ?? ""}"; + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationPersistenceContributor.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationPersistenceContributor.cs new file mode 100644 index 000000000..e6a9477d4 --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationPersistenceContributor.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Localization.Persistence; + +public class LocalizationPersistenceContributor : ILocalizationResourceContributor +{ + public bool IsDynamic => true; + + private LocalizationResourceBase _resource; + private ILocalizationPersistenceReader _persistenceSupport; + public void Initialize(LocalizationResourceInitializationContext context) + { + _resource = context.Resource; + _persistenceSupport = context.ServiceProvider.GetRequiredService(); + } + + public virtual void Fill(string cultureName, Dictionary dictionary) + { + _persistenceSupport.Fill(_resource.ResourceName, cultureName, dictionary); + } + + public async virtual Task FillAsync(string cultureName, Dictionary dictionary) + { + await _persistenceSupport.FillAsync(_resource.ResourceName, cultureName, dictionary); + } + + public virtual LocalizedString GetOrNull(string cultureName, string name) + { + return _persistenceSupport.GetOrNull(_resource.ResourceName, cultureName, name); + } + + public async virtual Task> GetSupportedCulturesAsync() + { + return await _persistenceSupport.GetSupportedCulturesAsync(); + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationSaveToPersistenceContributor.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationSaveToPersistenceContributor.cs new file mode 100644 index 000000000..192604dfa --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/LocalizationSaveToPersistenceContributor.cs @@ -0,0 +1,39 @@ +using Microsoft.Extensions.Localization; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Localization.Persistence; + +/// +/// 空接口, 使用此提供者可持久化本地化资源到持久设施 +/// +public class LocalizationSaveToPersistenceContributor : ILocalizationResourceContributor +{ + public bool IsDynamic => true; + + public void Fill(string cultureName, Dictionary dictionary) + { + } + + public Task FillAsync(string cultureName, Dictionary dictionary) + { + return Task.CompletedTask; + } + + public LocalizedString GetOrNull(string cultureName, string name) + { + return null; + } + + public Task> GetSupportedCulturesAsync() + { + IEnumerable emptyCultures = new string[0]; + + return Task.FromResult(emptyCultures); + } + + public void Initialize(LocalizationResourceInitializationContext context) + { + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceReader.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceReader.cs new file mode 100644 index 000000000..c2509aebe --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceReader.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Localization; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Localization.Persistence; + +[Dependency(TryRegister = true)] +public class NoneLocalizationPersistenceReader : ILocalizationPersistenceReader, ISingletonDependency +{ + public void Fill(string resourceName, string cultureName, Dictionary dictionary) + { + + } + + public Task FillAsync(string resourceName, string cultureName, Dictionary dictionary) + { + return Task.CompletedTask; + } + + public LocalizedString GetOrNull(string resourceName, string cultureName, string name) + { + return null; + } + + public Task> GetSupportedCulturesAsync() + { + IEnumerable emptyCultures = new string[0]; + + return Task.FromResult(emptyCultures); + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceWriter.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceWriter.cs new file mode 100644 index 000000000..b6faa0da4 --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/LINGYUN/Abp/Localization/Persistence/NoneLocalizationPersistenceWriter.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Localization.Persistence; + +[Dependency(TryRegister = true)] +public class NoneLocalizationPersistenceWriter : ILocalizationPersistenceWriter, ISingletonDependency +{ + public Task> GetExistsTextsAsync( + string resourceName, + string cultureName, + IEnumerable keys, + CancellationToken cancellationToken = default) + { + return Task.FromResult(keys); + } + + public Task WriteLanguageAsync(LanguageInfo language, CancellationToken cancellationToken = default) + { + return Task.FromResult(false); + } + + public Task WriteResourceAsync(LocalizationResourceBase resource, CancellationToken cancellationToken = default) + { + return Task.FromResult(false); + } + + public Task WriteTextsAsync(IEnumerable texts, CancellationToken cancellationToken = default) + { + return Task.FromResult(false); + } +} diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md index 85a964815..2c36cd63c 100644 --- a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/README.md @@ -33,6 +33,13 @@ // 指定你的本地化资源类型, 此类型下定义的静态文档将被持久化到存储设施 options.AddPersistenceResource(); }); + + // 或者使用扩展方法持久化本地化资源类型 + Configure(options => + { + // 效果如上 + options.UsePersistence(); + }); } } diff --git a/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs new file mode 100644 index 000000000..84170dc60 --- /dev/null +++ b/aspnet-core/modules/localization/LINGYUN.Abp.Localization.Persistence/Volo/Abp/Localization/AbpLocalizationOptionsExtensions.cs @@ -0,0 +1,44 @@ +using LINGYUN.Abp.Localization.Persistence; +using System; + +namespace Volo.Abp.Localization; +public static class AbpLocalizationOptionsExtensions +{ + public static void UsePersistence( + this AbpLocalizationOptions options) + { + options.Resources + .Get() + .Contributors + .Add(new LocalizationSaveToPersistenceContributor()); + } + + public static void UsePersistence( + this AbpLocalizationOptions options, + Type localizationResourceType) + { + options.Resources + .Get(localizationResourceType) + .Contributors + .Add(new LocalizationSaveToPersistenceContributor()); + } + + public static void UsePersistences( + this AbpLocalizationOptions options, + params Type[] localizationResourceTypes) + { + foreach (var localizationResourceType in localizationResourceTypes) + { + options.UsePersistence(localizationResourceType); + } + } + + public static void UseAllPersistence( + this AbpLocalizationOptions options) + { + foreach (var resource in options.Resources) + { + resource.Value.Contributors.Add(new LocalizationSaveToPersistenceContributor()); + } + } +} diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs index 47d253f82..eb710de0b 100644 --- a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs +++ b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs @@ -1,10 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; +using LINGYUN.Abp.Localization.Persistence; +using LINGYUN.Abp.LocalizationManagement.Localization; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AutoMapper; using Volo.Abp.Domain; -using Volo.Abp.Localization; using Volo.Abp.Modularity; -using LINGYUN.Abp.Localization.Persistence; -using LINGYUN.Abp.LocalizationManagement.Localization; namespace LINGYUN.Abp.LocalizationManagement { @@ -24,11 +23,6 @@ namespace LINGYUN.Abp.LocalizationManagement options.AddProfile(validate: true); }); - Configure(options => - { - options.GlobalContributors.Add(); - }); - Configure(options => { options.AddPersistenceResource(); diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementExternalContributor.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementExternalContributor.cs deleted file mode 100644 index 2f0c334ed..000000000 --- a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementExternalContributor.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Localization; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.Localization; -using Volo.Abp.Threading; - -namespace LINGYUN.Abp.LocalizationManagement; - -public class LocalizationManagementExternalContributor : ILocalizationResourceContributor -{ - public bool IsDynamic => true; - - private LocalizationResourceBase _resource; - - private ILocalizationStoreCache _localizationStoreCache; - private LocalizationStoreCacheInitializeContext _cacheInitializeContext; - - public void Initialize(LocalizationResourceInitializationContext context) - { - _resource = context.Resource; - - _cacheInitializeContext = new LocalizationStoreCacheInitializeContext(context.ServiceProvider); - _localizationStoreCache = context.ServiceProvider.GetRequiredService(); - } - - public virtual void Fill(string cultureName, Dictionary dictionary) - { - AsyncHelper.RunSync(async () => await FillAsync(cultureName, dictionary)); - } - - public async virtual Task FillAsync(string cultureName, Dictionary dictionary) - { - await _localizationStoreCache.InitializeAsync(_cacheInitializeContext); - - var localizedStrings = _localizationStoreCache.GetAllLocalizedStrings(cultureName); - - var localizedStringsInResource = localizedStrings.GetOrDefault(_resource.ResourceName); - if (localizedStringsInResource != null) - { - foreach (var localizedString in localizedStringsInResource) - { - dictionary[localizedString.Key] = localizedString.Value; - } - } - } - - public virtual LocalizedString GetOrNull(string cultureName, string name) - { - return _localizationStoreCache - .GetLocalizedStringOrNull(_resource.ResourceName, cultureName, name); - } - - public virtual Task> GetSupportedCulturesAsync() - { - var languageInfos = _localizationStoreCache.GetLanguages(); - - IEnumerable languages = languageInfos - .Select(x => x.CultureName) - .ToList(); - - return Task.FromResult(languages); - } -} diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceReader.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceReader.cs new file mode 100644 index 000000000..9ec5f9757 --- /dev/null +++ b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceReader.cs @@ -0,0 +1,65 @@ +using LINGYUN.Abp.Localization.Persistence; +using Microsoft.Extensions.Localization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace LINGYUN.Abp.LocalizationManagement; + +[Dependency(ReplaceServices = true)] +[ExposeServices( + typeof(ILocalizationPersistenceReader), + typeof(LocalizationManagementPersistenceReader))] +public class LocalizationManagementPersistenceReader : ILocalizationPersistenceReader, ITransientDependency +{ + private readonly ILocalizationStoreCache _localizationStoreCache; + private readonly LocalizationStoreCacheInitializeContext _cacheInitializeContext; + + public LocalizationManagementPersistenceReader( + IServiceProvider serviceProvider, + ILocalizationStoreCache localizationStoreCache) + { + _localizationStoreCache = localizationStoreCache; + _cacheInitializeContext = new LocalizationStoreCacheInitializeContext(serviceProvider); + } + + public virtual void Fill(string resourceName, string cultureName, Dictionary dictionary) + { + AsyncHelper.RunSync(async () => await FillAsync(resourceName, cultureName, dictionary)); + } + + public async virtual Task FillAsync(string resourceName, string cultureName, Dictionary dictionary) + { + await _localizationStoreCache.InitializeAsync(_cacheInitializeContext); + + var localizedStrings = _localizationStoreCache.GetAllLocalizedStrings(cultureName); + + var localizedStringsInResource = localizedStrings.GetOrDefault(resourceName); + if (localizedStringsInResource != null) + { + foreach (var localizedString in localizedStringsInResource) + { + dictionary[localizedString.Key] = localizedString.Value; + } + } + } + + public virtual LocalizedString GetOrNull(string resourceName, string cultureName, string name) + { + return _localizationStoreCache.GetLocalizedStringOrNull(resourceName, cultureName, name); + } + + public virtual Task> GetSupportedCulturesAsync() + { + var languageInfos = _localizationStoreCache.GetLanguages(); + + IEnumerable languages = languageInfos + .Select(x => x.CultureName) + .ToList(); + + return Task.FromResult(languages); + } +} diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceWriter.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceWriter.cs new file mode 100644 index 000000000..0d7fde110 --- /dev/null +++ b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationManagementPersistenceWriter.cs @@ -0,0 +1,203 @@ +using LINGYUN.Abp.Localization.Persistence; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +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; + +namespace LINGYUN.Abp.LocalizationManagement; + +[Dependency(ReplaceServices = true)] +[ExposeServices( + typeof(ILocalizationPersistenceWriter), + typeof(LocalizationManagementPersistenceWriter))] +public class LocalizationManagementPersistenceWriter : ILocalizationPersistenceWriter, ITransientDependency +{ + protected IDistributedCache Cache { get; } + protected IAbpDistributedLock DistributedLock { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + protected IApplicationInfoAccessor ApplicationInfoAccessor { get; } + + protected IGuidGenerator GuidGenerator { get; } + protected ILanguageRepository LanguageRepository { get; } + protected ITextRepository TextRepository { get; } + protected IResourceRepository ResourceRepository { get; } + + public LocalizationManagementPersistenceWriter( + IDistributedCache cache, + IGuidGenerator guidGenerator, + IAbpDistributedLock distributedLock, + ITextRepository textRepository, + ILanguageRepository languageRepository, + IResourceRepository resourceRepository, + IApplicationInfoAccessor applicationInfoAccessor, + IOptions cacheOptions) + { + Cache = cache; + GuidGenerator = guidGenerator; + DistributedLock = distributedLock; + LanguageRepository = languageRepository; + TextRepository = textRepository; + ResourceRepository = resourceRepository; + ApplicationInfoAccessor = applicationInfoAccessor; + CacheOptions = cacheOptions.Value; + } + + public async virtual Task> GetExistsTextsAsync( + string resourceName, + string cultureName, + IEnumerable keys, + CancellationToken cancellationToken = default) + { + if (!await ShouldCalculateTextsHash(keys, cancellationToken)) + { + return keys; + } + + return await TextRepository.GetExistsKeysAsync( + resourceName, + cultureName, + keys, + cancellationToken); + } + + + + public async virtual Task WriteLanguageAsync( + LanguageInfo language, + CancellationToken cancellationToken = default) + { + var commonDistributedLockKey = GetCommonDistributedLockKey("Language", language.CultureName); + await using var lockHandle = await DistributedLock.TryAcquireAsync(commonDistributedLockKey); + if (lockHandle == null) + { + return false; + } + + if (await LanguageRepository.FindByCultureNameAsync(language.CultureName, cancellationToken) == null) + { + await LanguageRepository.InsertAsync( + new Language( + GuidGenerator.Create(), + language.CultureName, + language.UiCultureName, + language.DisplayName, + language.FlagIcon), + autoSave: true, + cancellationToken: cancellationToken); + } + + return true; + } + + public async virtual Task WriteResourceAsync( + LocalizationResourceBase resource, + CancellationToken cancellationToken = default) + { + var commonDistributedLockKey = GetCommonDistributedLockKey("Resource", resource.ResourceName); + await using var lockHandle = await DistributedLock.TryAcquireAsync(commonDistributedLockKey); + if (lockHandle == null) + { + return false; + } + + if (await ResourceRepository.FindByNameAsync(resource.ResourceName, cancellationToken) == null) + { + await ResourceRepository.InsertAsync( + new Resource( + GuidGenerator.Create(), + resource.ResourceName, + resource.ResourceName, + resource.ResourceName, + resource.DefaultCultureName), + autoSave: true, + cancellationToken: cancellationToken); + } + + return true; + } + + public async virtual Task WriteTextsAsync( + IEnumerable texts, + CancellationToken cancellationToken = default) + { + if (!await ShouldCalculateTextsHash(texts.Select(x => x.Name), cancellationToken)) + { + return false; + } + + var cacheKey = GetApplicationHashCacheKey(); + var currentHash = CalculateTextsHash(texts.Select(x => x.Name)); + + var savedTexts = texts.Select(text => + new Text( + text.ResourceName, + text.CultureName, + text.Name, + text.Value)); + + await TextRepository.InsertManyAsync( + savedTexts, + autoSave: true, + cancellationToken: cancellationToken); + + await Cache.SetStringAsync( + cacheKey, + currentHash, + new DistributedCacheEntryOptions + { + SlidingExpiration = TimeSpan.FromDays(30) + }, + cancellationToken); + + return true; + } + + private async Task ShouldCalculateTextsHash(IEnumerable texts, CancellationToken cancellationToken = default) + { + var cacheKey = GetApplicationHashCacheKey(); + var cachedHash = await Cache.GetStringAsync(cacheKey, cancellationToken); + + var currentHash = CalculateTextsHash(texts); + + if (cachedHash == currentHash) + { + return false; + } + + return cachedHash != currentHash; + } + + private static string CalculateTextsHash(IEnumerable texts) + { + var stringBuilder = new StringBuilder(); + + stringBuilder.Append("LocalizableStrings:"); + stringBuilder.Append(texts.JoinAsString(",")); + + return stringBuilder + .ToString() + .ToMd5(); + } + + private string GetCommonDistributedLockKey( + string lockResourceName, + string lockResourceKey) + { + return $"{CacheOptions.KeyPrefix}_Common_AbpLocalizationWriter_{lockResourceName}_{lockResourceKey}_Lock"; + } + + private string GetApplicationHashCacheKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationInfoAccessor.ApplicationName}_AbpLocalizationHash"; + } +} diff --git a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs b/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs deleted file mode 100644 index 9ecb9acd6..000000000 --- a/aspnet-core/modules/lt/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/StaticLocalizationSaver.cs +++ /dev/null @@ -1,128 +0,0 @@ -using LINGYUN.Abp.Localization.Persistence; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Guids; -using Volo.Abp.Localization; -using Volo.Abp.Uow; - -namespace LINGYUN.Abp.LocalizationManagement; - -[Dependency(ReplaceServices = true)] -public class StaticLocalizationSaver : IStaticLocalizationSaver, ITransientDependency -{ - protected IGuidGenerator GuidGenerator { get; } - protected ILanguageRepository LanguageRepository { get; } - protected ITextRepository TextRepository { get; } - protected IResourceRepository ResourceRepository { get; } - protected IStringLocalizerFactory StringLocalizerFactory { get; } - protected AbpLocalizationOptions LocalizationOptions { get; } - protected IServiceProvider ServiceProvider { get; } - protected AbpLocalizationPersistenceOptions LocalizationPersistenceOptions { get; } - - public StaticLocalizationSaver( - IGuidGenerator guidGenerator, - IServiceProvider serviceProvider, - ILanguageRepository languageRepository, - ITextRepository textRepository, - IResourceRepository resourceRepository, - IStringLocalizerFactory stringLocalizerFactory, - IOptions localizationOptions, - IOptions localizationPersistenceOptions) - { - GuidGenerator = guidGenerator; - ServiceProvider = serviceProvider; - LanguageRepository = languageRepository; - TextRepository = textRepository; - ResourceRepository = resourceRepository; - StringLocalizerFactory = stringLocalizerFactory; - LocalizationOptions = localizationOptions.Value; - LocalizationPersistenceOptions = localizationPersistenceOptions.Value; - } - - [UnitOfWork] - public async virtual Task SaveAsync() - { - var insertNewTexts = new List(); - - foreach (var language in LocalizationOptions.Languages) - { - if (await LanguageRepository.FindByCultureNameAsync(language.CultureName) == null) - { - await LanguageRepository.InsertAsync( - new Language( - GuidGenerator.Create(), - language.CultureName, - language.UiCultureName, - language.DisplayName, - language.FlagIcon)); - } - - foreach (var resource in LocalizationPersistenceOptions.SaveToPersistenceResources) - { - using (CultureHelper.Use(language.CultureName, language.UiCultureName)) - { - var localizationResource = LocalizationOptions.Resources.GetOrDefault(resource); - if (localizationResource == null) - { - continue; - } - - if (await ResourceRepository.FindByNameAsync(localizationResource.ResourceName) == null) - { - await ResourceRepository.InsertAsync( - new Resource( - GuidGenerator.Create(), - localizationResource.ResourceName, - localizationResource.ResourceName, - localizationResource.ResourceName, - localizationResource.DefaultCultureName)); - } - - var context = new LocalizationResourceInitializationContext(localizationResource, ServiceProvider); - foreach (var contributor in localizationResource.Contributors) - { - if (contributor.IsDynamic) - { - continue; - } - - contributor.Initialize(context); - var fillTexts = new Dictionary(); - - await contributor.FillAsync(language.CultureName, fillTexts); - - var existsKeys = await TextRepository.GetExistsKeysAsync( - localizationResource.ResourceName, - language.CultureName, - fillTexts.Values.Select(x => x.Name)); - - var notExistsKeys = fillTexts.Values.Where(x => !existsKeys.Contains(x.Name)); - - foreach (var notExistsKey in notExistsKeys) - { - if (!insertNewTexts.Any(x => x.CultureName == language.CultureName && x.Key == notExistsKey.Name)) - { - insertNewTexts.Add( - new Text( - localizationResource.ResourceName, - language.CultureName, - notExistsKey.Name, - notExistsKey.Value)); - } - } - } - } - } - } - - if (insertNewTexts.Any()) - { - await TextRepository.InsertManyAsync(insertNewTexts); - } - } -} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.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/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj new file mode 100644 index 000000000..9d4293ad2 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN.Abp.PermissionManagement.Application.Contracts.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationContractsModule.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationContractsModule.cs new file mode 100644 index 000000000..d22a2e4ad --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationContractsModule.cs @@ -0,0 +1,33 @@ +using Volo.Abp.Localization; +using Volo.Abp.Localization.ExceptionHandling; +using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement.Localization; +using Volo.Abp.VirtualFileSystem; +using VoloAbpPermissionManagementApplicationContractsModule = Volo.Abp.PermissionManagement.AbpPermissionManagementApplicationContractsModule; + +namespace LINGYUN.Abp.PermissionManagement; + +[DependsOn( + typeof(VoloAbpPermissionManagementApplicationContractsModule))] +public class AbpPermissionManagementApplicationContractsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts"); + }); + + Configure(options => + { + options.MapCodeNamespace(PermissionManagementErrorCodes.Namespace, typeof(AbpPermissionManagementResource)); + }); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateDto.cs new file mode 100644 index 000000000..c581bce2b --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateDto.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.PermissionManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public class PermissionDefinitionCreateDto : PermissionDefinitionCreateOrUpdateDto +{ + [Required] + [DynamicStringLength(typeof(PermissionDefinitionRecordConsts), nameof(PermissionDefinitionRecordConsts.MaxNameLength))] + public string Name { get; set; } + + [Required] + [DynamicStringLength(typeof(PermissionGroupDefinitionRecordConsts), nameof(PermissionGroupDefinitionRecordConsts.MaxNameLength))] + public string GroupName { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateOrUpdateDto.cs new file mode 100644 index 000000000..49ae50e3b --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionCreateOrUpdateDto.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Data; +using Volo.Abp.MultiTenancy; +using Volo.Abp.PermissionManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public abstract class PermissionDefinitionCreateOrUpdateDto : IHasExtraProperties +{ + [Required] + [DynamicStringLength(typeof(PermissionDefinitionRecordConsts), nameof(PermissionDefinitionRecordConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + [DynamicStringLength(typeof(PermissionDefinitionRecordConsts), nameof(PermissionDefinitionRecordConsts.MaxNameLength))] + public string ParentName { get; set; } + + public bool IsEnabled { get; set; } + + public MultiTenancySides? MultiTenancySide { get; set; } + + public List Providers { get; set; } = new List(); + + public List StateCheckers { get; set; } = new List(); + + public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary(); +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionDto.cs new file mode 100644 index 000000000..867ac90f6 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionDto.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Volo.Abp.Data; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public class PermissionDefinitionDto : IHasExtraProperties +{ + public string Name { get; set; } + + public string ParentName { get; set; } + + public string DisplayName { get; set; } + + public string FormatedDisplayName { get; set; } + + public string GroupName { get; set; } + + public bool IsEnabled { get; set; } + + public MultiTenancySides? MultiTenancySide { get; set; } + + public List Providers { get; set; } = new List(); + + public List StateCheckers { get; set; } = new List(); + + public ExtraPropertyDictionary ExtraProperties { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionGetListInput.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionGetListInput.cs new file mode 100644 index 000000000..834f37091 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionGetListInput.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; +public class PermissionDefinitionGetListInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } + + public string GroupName { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionUpdateDto.cs new file mode 100644 index 000000000..07d4044cf --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionDefinitionUpdateDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Domain.Entities; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; +public class PermissionDefinitionUpdateDto : PermissionDefinitionCreateOrUpdateDto, IHasConcurrencyStamp +{ + [StringLength(40)] + public string ConcurrencyStamp { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateDto.cs new file mode 100644 index 000000000..4d93939d3 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateDto.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.PermissionManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; +public class PermissionGroupDefinitionCreateDto : PermissionGroupDefinitionCreateOrUpdateDto +{ + [Required] + [DynamicStringLength(typeof(PermissionGroupDefinitionRecordConsts), nameof(PermissionGroupDefinitionRecordConsts.MaxNameLength))] + public string Name { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateOrUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateOrUpdateDto.cs new file mode 100644 index 000000000..b9c3eb78c --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionCreateOrUpdateDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Data; +using Volo.Abp.PermissionManagement; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public abstract class PermissionGroupDefinitionCreateOrUpdateDto : IHasExtraProperties +{ + [Required] + [DynamicStringLength(typeof(PermissionGroupDefinitionRecordConsts), nameof(PermissionGroupDefinitionRecordConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; set; } = new ExtraPropertyDictionary(); +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionDto.cs new file mode 100644 index 000000000..336df036d --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionDto.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Data; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public class PermissionGroupDefinitionDto : IHasExtraProperties +{ + public string Name { get; set; } + + public string DisplayName { get; set; } + + public string FormatedDisplayName { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionGetListInput.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionGetListInput.cs new file mode 100644 index 000000000..9e7265dc5 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionGetListInput.cs @@ -0,0 +1,7 @@ +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; +public class PermissionGroupDefinitionGetListInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionUpdateDto.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionUpdateDto.cs new file mode 100644 index 000000000..370fe95e5 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/Dto/PermissionGroupDefinitionUpdateDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Domain.Entities; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; +public class PermissionGroupDefinitionUpdateDto : PermissionGroupDefinitionCreateOrUpdateDto, IHasConcurrencyStamp +{ + [StringLength(40)] + public string ConcurrencyStamp { get; set; } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionDefinitionAppService.cs new file mode 100644 index 000000000..7cf6793ab --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionDefinitionAppService.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public interface IPermissionDefinitionAppService : IApplicationService +{ + Task GetAsync(string name); + + Task DeleteAsync(string name); + + Task CreateAsync(PermissionDefinitionCreateDto input); + + Task UpdateAsync(string name, PermissionDefinitionUpdateDto input); + + Task> GetListAsync(PermissionDefinitionGetListInput input); +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionGroupDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionGroupDefinitionAppService.cs new file mode 100644 index 000000000..cd1c8d3f7 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Definitions/IPermissionGroupDefinitionAppService.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +public interface IPermissionGroupDefinitionAppService : IApplicationService +{ + Task GetAsync(string name); + + Task DeleteAsync(string name); + + Task CreateAsync(PermissionGroupDefinitionCreateDto input); + + Task UpdateAsync(string name, PermissionGroupDefinitionUpdateDto input); + + Task> GetListAsync(PermissionGroupDefinitionGetListInput input); +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/en.json b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/en.json new file mode 100644 index 000000000..34517b84d --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/en.json @@ -0,0 +1,16 @@ +{ + "culture": "en", + "texts": { + "Permission:PermissionManagement": "Permission Management", + "Permission:GroupDefinitions": "Group Definitions", + "Permission:PermissionDefinitions": "Permission Definitions", + "Permission:Create": "Create", + "Permission:Edit": "Edit", + "Permission:Delete": "Delete", + "PermissionManagement:001100": "Permission group {Name} already exists!", + "PermissionManagement:001404": "Permission group named {Name} not found!", + "PermissionManagement:002100": "Permission {Name} already exists!", + "PermissionManagement:002101": "The group definition of permission {Name} could not be retrieved!", + "PermissionManagement:0021404": "Permission named {Name} not found!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/zh-Hans.json b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/zh-Hans.json new file mode 100644 index 000000000..3a036509d --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Localization/Application/Contracts/zh-Hans.json @@ -0,0 +1,16 @@ +{ + "culture": "zh-Hans", + "texts": { + "Permission:PermissionManagement": "权限管理", + "Permission:GroupDefinitions": "分组定义", + "Permission:PermissionDefinitions": "权限定义", + "Permission:Create": "新增", + "Permission:Edit": "修改", + "Permission:Delete": "删除", + "PermissionManagement:001100": "权限分组 {Name} 已经存在!", + "PermissionManagement:001404": "没有找到名为 {Name} 的权限分组!", + "PermissionManagement:002100": "权限 {Name} 已经存在!", + "PermissionManagement:002101": "未能检索到权限 {Name} 所在分组定义!", + "PermissionManagement:0021404": "没有找到名为 {Name} 的权限定义!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/PermissionManagementErrorCodes.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/PermissionManagementErrorCodes.cs new file mode 100644 index 000000000..b6c519ae0 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/PermissionManagementErrorCodes.cs @@ -0,0 +1,25 @@ +namespace LINGYUN.Abp.PermissionManagement; +public static class PermissionManagementErrorCodes +{ + public const string Namespace = "PermissionManagement"; + + public static class GroupDefinition + { + private const string Prefix = Namespace + ":001"; + + public const string AlreayNameExists = Prefix + "100"; + + public const string NameNotFount = Prefix + "404"; + } + + public static class Definition + { + private const string Prefix = Namespace + ":002"; + + public const string AlreayNameExists = Prefix + "100"; + + public const string FailedGetGroup = Prefix + "101"; + + public const string NameNotFount = Prefix + "404"; + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionDefinitionProvider.cs new file mode 100644 index 000000000..4c90e9848 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionDefinitionProvider.cs @@ -0,0 +1,55 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; +using Volo.Abp.PermissionManagement.Localization; + +namespace LINGYUN.Abp.PermissionManagement.Permissions; + +public class PermissionManagementPermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + var permissionGroup = context.AddGroup( + PermissionManagementPermissionNames.GroupName, + L("Permission:PermissionManagement")); + + var groupDefinition = permissionGroup.AddPermission( + PermissionManagementPermissionNames.GroupDefinition.Default, + L("Permission:GroupDefinitions"), + MultiTenancySides.Host); + groupDefinition.AddChild( + PermissionManagementPermissionNames.GroupDefinition.Create, + L("Permission:Create"), + MultiTenancySides.Host); + groupDefinition.AddChild( + PermissionManagementPermissionNames.GroupDefinition.Update, + L("Permission:Edit"), + MultiTenancySides.Host); + groupDefinition.AddChild( + PermissionManagementPermissionNames.GroupDefinition.Delete, + L("Permission:Delete"), + MultiTenancySides.Host); + + var permissionDefinition = permissionGroup.AddPermission( + PermissionManagementPermissionNames.Definition.Default, + L("Permission:PermissionDefinitions"), + MultiTenancySides.Host); + permissionDefinition.AddChild( + PermissionManagementPermissionNames.Definition.Create, + L("Permission:Create"), + MultiTenancySides.Host); + permissionDefinition.AddChild( + PermissionManagementPermissionNames.Definition.Update, + L("Permission:Edit"), + MultiTenancySides.Host); + permissionDefinition.AddChild( + PermissionManagementPermissionNames.Definition.Delete, + L("Permission:Delete"), + MultiTenancySides.Host); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionNames.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionNames.cs new file mode 100644 index 000000000..7f234b16d --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application.Contracts/LINGYUN/Abp/PermissionManagement/Permissions/PermissionManagementPermissionNames.cs @@ -0,0 +1,23 @@ +namespace LINGYUN.Abp.PermissionManagement.Permissions; +public static class PermissionManagementPermissionNames +{ + public const string GroupName = "PermissionManagement"; + + public static class GroupDefinition + { + public const string Default = GroupName + ".GroupDefinitions"; + + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } + + public static class Definition + { + public const string Default = GroupName + ".Definitions"; + + public const string Create = Default + ".Create"; + public const string Update = Default + ".Update"; + public const string Delete = Default + ".Delete"; + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xml b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xsd b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.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/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN.Abp.PermissionManagement.Application.csproj b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN.Abp.PermissionManagement.Application.csproj new file mode 100644 index 000000000..81161aa88 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN.Abp.PermissionManagement.Application.csproj @@ -0,0 +1,19 @@ + + + + + + + net7.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationModule.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationModule.cs new file mode 100644 index 000000000..6ed24af73 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/AbpPermissionManagementApplicationModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; +using VoloAbpPermissionManagementApplicationModule = Volo.Abp.PermissionManagement.AbpPermissionManagementApplicationModule; + +namespace LINGYUN.Abp.PermissionManagement; + +[DependsOn( + typeof(AbpPermissionManagementApplicationContractsModule), + typeof(VoloAbpPermissionManagementApplicationModule))] +public class AbpPermissionManagementApplicationModule : AbpModule +{ + +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/DynamicPermissionDefinitionStoreCacheInvalidator.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/DynamicPermissionDefinitionStoreCacheInvalidator.cs new file mode 100644 index 000000000..7a12b3bc7 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/DynamicPermissionDefinitionStoreCacheInvalidator.cs @@ -0,0 +1,64 @@ +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.PermissionManagement; +using Volo.Abp.Threading; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; +public class DynamicPermissionDefinitionStoreCacheInvalidator : + ILocalEventHandler>, + ILocalEventHandler>, + ITransientDependency +{ + private readonly IDynamicPermissionDefinitionStoreInMemoryCache _storeCache; + + private readonly IClock _clock; + private readonly IDistributedCache _distributedCache; + private readonly AbpDistributedCacheOptions _cacheOptions; + + public DynamicPermissionDefinitionStoreCacheInvalidator( + IClock clock, + IDistributedCache distributedCache, + IDynamicPermissionDefinitionStoreInMemoryCache storeCache, + IOptions cacheOptions) + { + _storeCache = storeCache; + _clock = clock; + _distributedCache = distributedCache; + _cacheOptions = cacheOptions.Value; + } + + public async virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + await RemoveStampInDistributedCacheAsync(); + } + + public async virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + await RemoveStampInDistributedCacheAsync(); + } + + protected async virtual Task RemoveStampInDistributedCacheAsync() + { + using (await _storeCache.SyncSemaphore.LockAsync()) + { + var cacheKey = GetCommonStampCacheKey(); + + await _distributedCache.RemoveAsync(cacheKey); + + _storeCache.CacheStamp = Guid.NewGuid().ToString(); + _storeCache.LastCheckTime = _clock.Now.AddMinutes(-5); + } + } + + protected virtual string GetCommonStampCacheKey() + { + return $"{_cacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionDefinitionAppService.cs new file mode 100644 index 000000000..a24a09cba --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionDefinitionAppService.cs @@ -0,0 +1,331 @@ +using LINGYUN.Abp.PermissionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Localization; +using Volo.Abp.PermissionManagement; +using Volo.Abp.SimpleStateChecking; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +[Authorize(PermissionManagementPermissionNames.Definition.Default)] +public class PermissionDefinitionAppService : PermissionManagementAppServiceBase, IPermissionDefinitionAppService +{ + private readonly ISimpleStateCheckerSerializer _simpleStateCheckerSerializer; + private readonly ILocalizableStringSerializer _localizableStringSerializer; + private readonly IPermissionDefinitionManager _permissionDefinitionManager; + + private readonly IPermissionDefinitionRecordRepository _definitionRepository; + private readonly IRepository _definitionBasicRepository; + + public PermissionDefinitionAppService( + ILocalizableStringSerializer localizableStringSerializer, + IPermissionDefinitionManager permissionDefinitionManager, + ISimpleStateCheckerSerializer simpleStateCheckerSerializer, + IPermissionDefinitionRecordRepository definitionRepository, + IRepository definitionBasicRepository) + { + _localizableStringSerializer = localizableStringSerializer; + _permissionDefinitionManager = permissionDefinitionManager; + _simpleStateCheckerSerializer = simpleStateCheckerSerializer; + _definitionRepository = definitionRepository; + _definitionBasicRepository = definitionBasicRepository; + } + + [Authorize(PermissionManagementPermissionNames.Definition.Create)] + public async virtual Task CreateAsync(PermissionDefinitionCreateDto input) + { + if (await _permissionDefinitionManager.GetOrNullAsync(input.Name) != null) + { + throw new BusinessException(PermissionManagementErrorCodes.Definition.AlreayNameExists) + .WithData(nameof(PermissionDefinitionRecord.Name), input.Name); + } + + var groupDefinition = await _permissionDefinitionManager.GetGroupOrNullAsync(input.GroupName); + if (groupDefinition == null) + { + throw new BusinessException(PermissionManagementErrorCodes.GroupDefinition.NameNotFount) + .WithData(nameof(PermissionGroupDefinitionRecord.Name), input.GroupName); + } + + var definitionRecord = new PermissionDefinitionRecord( + GuidGenerator.Create(), + groupDefinition.Name, + input.Name, + input.ParentName, + input.DisplayName, + input.IsEnabled); + + if (input.MultiTenancySide.HasValue) + { + definitionRecord.MultiTenancySide = input.MultiTenancySide.Value; + } + + if (input.Providers.Any()) + { + definitionRecord.Providers = input.Providers.JoinAsString(","); + } + + if (input.StateCheckers.Any()) + { + definitionRecord.StateCheckers = input.StateCheckers.JoinAsString(","); + } + + foreach (var property in input.ExtraProperties) + { + definitionRecord.SetProperty(property.Key, property.Value); + } + + await _definitionRepository.InsertAsync(definitionRecord); + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await DefinitionRecordToDto(definitionRecord); + + return dto; + } + + [Authorize(PermissionManagementPermissionNames.Definition.Delete)] + public async virtual Task DeleteAsync(string name) + { + var definitionRecord = await FindByNameAsync(name); + + if (definitionRecord == null) + { + return; + } + + await _definitionRepository.DeleteAsync(definitionRecord); + } + + public async virtual Task GetAsync(string name) + { + var definition = await _permissionDefinitionManager.GetOrNullAsync(name); + if (definition == null) + { + throw new BusinessException(PermissionManagementErrorCodes.Definition.NameNotFount) + .WithData(nameof(PermissionDefinitionRecord.Name), name); + } + + var groupDefinition = await GetGroupDefinition(definition); + + var dto = await DefinitionToDto(groupDefinition, definition); + + return dto; + } + + public async virtual Task> GetListAsync(PermissionDefinitionGetListInput input) + { + var permissions = new List(); + + IReadOnlyList definitionPermissions; + + if (!input.GroupName.IsNullOrWhiteSpace()) + { + var group = await _permissionDefinitionManager.GetGroupOrNullAsync(input.GroupName); + if (group == null) + { + return new PagedResultDto(0, permissions); + } + + definitionPermissions = group.GetPermissionsWithChildren(); + } + else + { + definitionPermissions = await _permissionDefinitionManager.GetPermissionsAsync(); + } + + var definitionFilter = definitionPermissions.AsQueryable() + .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter) || + (x.Parent != null && x.Parent.Name.Contains(input.Filter))); + + var sorting = input.Sorting; + if (sorting.IsNullOrWhiteSpace()) + { + sorting = nameof(PermissionDefinitionRecord.Name); + } + + var filterDefinitionCount = definitionFilter.Count(); + var filterDefinitions = definitionFilter + .OrderBy(sorting) + .PageBy(input.SkipCount, input.MaxResultCount); + + foreach (var definition in filterDefinitions) + { + var groupDefinition = await GetGroupDefinition(definition); + var Dto = await DefinitionToDto(groupDefinition, definition); + + permissions.Add(Dto); + } + + return new PagedResultDto(filterDefinitionCount, permissions); + } + + [Authorize(PermissionManagementPermissionNames.Definition.Update)] + public async virtual Task UpdateAsync(string name, PermissionDefinitionUpdateDto input) + { + var definition = await _permissionDefinitionManager.GetOrNullAsync(name); + var definitionRecord = await FindByNameAsync(name); + + if (definitionRecord == null) + { + var groupDefinition = await GetGroupDefinition(definition); + definitionRecord = new PermissionDefinitionRecord( + GuidGenerator.Create(), + groupDefinition.Name, + name, + input.ParentName, + input.DisplayName, + input.IsEnabled); + + if (input.MultiTenancySide.HasValue) + { + definitionRecord.MultiTenancySide = input.MultiTenancySide.Value; + } + + if (input.Providers.Any()) + { + definitionRecord.Providers = input.Providers.JoinAsString(","); + } + + if (input.StateCheckers.Any()) + { + definitionRecord.StateCheckers = input.StateCheckers.JoinAsString(","); + } + + foreach (var property in input.ExtraProperties) + { + definitionRecord.SetProperty(property.Key, property.Value); + } + + definitionRecord = await _definitionBasicRepository.InsertAsync(definitionRecord); + } + else + { + definitionRecord.ExtraProperties.Clear(); + foreach (var property in input.ExtraProperties) + { + definitionRecord.SetProperty(property.Key, property.Value); + } + + if (input.MultiTenancySide.HasValue) + { + definitionRecord.MultiTenancySide = input.MultiTenancySide.Value; + } + + if (input.Providers.Any()) + { + definitionRecord.Providers = input.Providers.JoinAsString(","); + } + + if (input.StateCheckers.Any()) + { + definitionRecord.StateCheckers = input.StateCheckers.JoinAsString(","); + } + + if (!string.Equals(definitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) + { + definitionRecord.DisplayName = input.DisplayName; + } + + definitionRecord = await _definitionBasicRepository.UpdateAsync(definitionRecord); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await DefinitionRecordToDto(definitionRecord); + + return dto; + } + + protected async virtual Task FindByNameAsync(string name) + { + var DefinitionFilter = await _definitionBasicRepository.GetQueryableAsync(); + + var definitionRecord = await AsyncExecuter.FirstOrDefaultAsync( + DefinitionFilter.Where(x => x.Name == name)); + + return definitionRecord; + } + + protected async virtual Task GetGroupDefinition(PermissionDefinition definition) + { + var groups = await _permissionDefinitionManager.GetGroupsAsync(); + + foreach (var group in groups) + { + if (group.GetPermissionOrNull(definition.Name) != null) + { + return group; + } + } + + throw new BusinessException(PermissionManagementErrorCodes.Definition.FailedGetGroup) + .WithData(nameof(PermissionDefinitionRecord.Name), definition.Name); + } + + protected async virtual Task DefinitionRecordToDto(PermissionDefinitionRecord definitionRecord) + { + var dto = new PermissionDefinitionDto + { + Name = definitionRecord.Name, + GroupName = definitionRecord.GroupName, + ParentName = definitionRecord.ParentName, + IsEnabled = definitionRecord.IsEnabled, + FormatedDisplayName = definitionRecord.DisplayName, + Providers = definitionRecord.Providers.Split(',').ToList(), + StateCheckers = definitionRecord.StateCheckers.Split(',').ToList(), + MultiTenancySide = definitionRecord.MultiTenancySide, + }; + + var displayName = _localizableStringSerializer.Deserialize(definitionRecord.DisplayName); + dto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory); + + foreach (var property in definitionRecord.ExtraProperties) + { + dto.SetProperty(property.Key, property.Value); + } + + return dto; + } + + protected async virtual Task DefinitionToDto(PermissionGroupDefinition groupDefinition, PermissionDefinition definition) + { + var dto = new PermissionDefinitionDto + { + Name = definition.Name, + GroupName = groupDefinition.Name, + ParentName = definition.Parent?.Name, + IsEnabled = definition.IsEnabled, + Providers = definition.Providers, + MultiTenancySide = definition.MultiTenancySide, + }; + + if (definition.StateCheckers.Any()) + { + var stateCheckers = _simpleStateCheckerSerializer.Serialize(definition.StateCheckers); + dto.StateCheckers = stateCheckers.Split(',').ToList(); + } + + if (definition.DisplayName != null) + { + dto.DisplayName = await definition.DisplayName.LocalizeAsync(StringLocalizerFactory); + dto.FormatedDisplayName = _localizableStringSerializer.Serialize(definition.DisplayName); + } + + foreach (var property in definition.Properties) + { + dto.SetProperty(property.Key, property.Value); + } + + return dto; + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionGroupDefinitionAppService.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionGroupDefinitionAppService.cs new file mode 100644 index 000000000..e71ea10b3 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/Definitions/PermissionGroupDefinitionAppService.cs @@ -0,0 +1,216 @@ +using LINGYUN.Abp.PermissionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Localization; +using Volo.Abp.PermissionManagement; + +namespace LINGYUN.Abp.PermissionManagement.Definitions; + +[Authorize(PermissionManagementPermissionNames.GroupDefinition.Default)] +public class PermissionGroupDefinitionAppService : PermissionManagementAppServiceBase, IPermissionGroupDefinitionAppService +{ + private readonly ILocalizableStringSerializer _localizableStringSerializer; + private readonly IPermissionDefinitionManager _permissionDefinitionManager; + + private readonly IPermissionGroupDefinitionRecordRepository _groupDefinitionRepository; + private readonly IRepository _groupDefinitionBasicRepository; + + public PermissionGroupDefinitionAppService( + ILocalizableStringSerializer localizableStringSerializer, + IPermissionDefinitionManager permissionDefinitionManager, + IPermissionGroupDefinitionRecordRepository groupDefinitionRepository, + IRepository groupDefinitionBasicRepository) + { + _localizableStringSerializer = localizableStringSerializer; + _permissionDefinitionManager = permissionDefinitionManager; + _groupDefinitionRepository = groupDefinitionRepository; + _groupDefinitionBasicRepository = groupDefinitionBasicRepository; + } + + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Create)] + public async virtual Task CreateAsync(PermissionGroupDefinitionCreateDto input) + { + if (await _permissionDefinitionManager.GetGroupOrNullAsync(input.Name) != null) + { + throw new BusinessException(PermissionManagementErrorCodes.GroupDefinition.AlreayNameExists) + .WithData(nameof(PermissionGroupDefinitionRecord.Name), input.Name); + } + + var groupDefinitionRecord = new PermissionGroupDefinitionRecord( + GuidGenerator.Create(), + input.Name, + input.DisplayName); + + foreach (var property in input.ExtraProperties) + { + groupDefinitionRecord.SetProperty(property.Key, property.Value); + } + + await _groupDefinitionRepository.InsertAsync(groupDefinitionRecord); + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord); + + return dto; + } + + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)] + public async virtual Task DeleteAsync(string name) + { + var groupDefinitionRecord = await FindByNameAsync(name); + + if (groupDefinitionRecord == null) + { + return; + } + + await _groupDefinitionRepository.DeleteAsync(groupDefinitionRecord); + } + + public async virtual Task GetAsync(string name) + { + var groupDefinition = await _permissionDefinitionManager.GetGroupOrNullAsync(name); + if (groupDefinition == null) + { + throw new BusinessException(PermissionManagementErrorCodes.GroupDefinition.NameNotFount) + .WithData(nameof(PermissionGroupDefinitionRecord.Name), name); + } + + var dto = await GroupDefinitionToDto(groupDefinition); + + return dto; + } + + public async virtual Task> GetListAsync(PermissionGroupDefinitionGetListInput input) + { + var groups = new List(); + + var groupDefinitions = await _permissionDefinitionManager.GetGroupsAsync(); + + var groupDefinitionFilter = groupDefinitions.AsQueryable() + .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter)); + + var sorting = input.Sorting; + if (sorting.IsNullOrWhiteSpace()) + { + sorting = nameof(PermissionDefinitionRecord.Name); + } + + var filterGroupDefinitionCount = groupDefinitionFilter.Count(); + var filterGroupDefinitions = groupDefinitionFilter + .OrderBy(sorting) + .PageBy(input.SkipCount, input.MaxResultCount); + + foreach (var groupDefinition in filterGroupDefinitions) + { + var groupDto = await GroupDefinitionToDto(groupDefinition); + + groups.Add(groupDto); + } + + return new PagedResultDto(filterGroupDefinitionCount, groups); + } + + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Update)] + public async virtual Task UpdateAsync(string name, PermissionGroupDefinitionUpdateDto input) + { + var groupDefinition = await _permissionDefinitionManager.GetGroupOrNullAsync(name); + var groupDefinitionRecord = await FindByNameAsync(name); + + if (groupDefinitionRecord == null) + { + groupDefinitionRecord = new PermissionGroupDefinitionRecord( + GuidGenerator.Create(), + name, + input.DisplayName); + + foreach (var property in input.ExtraProperties) + { + groupDefinitionRecord.SetProperty(property.Key, property.Value); + } + + groupDefinitionRecord = await _groupDefinitionBasicRepository.InsertAsync(groupDefinitionRecord); + } + else + { + groupDefinitionRecord.ExtraProperties.Clear(); + foreach (var property in input.ExtraProperties) + { + groupDefinitionRecord.SetProperty(property.Key, property.Value); + } + + if (!string.Equals(groupDefinitionRecord.DisplayName, input.DisplayName, StringComparison.InvariantCultureIgnoreCase)) + { + groupDefinitionRecord.DisplayName = input.DisplayName; + } + + groupDefinitionRecord = await _groupDefinitionBasicRepository.UpdateAsync(groupDefinitionRecord); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + + var dto = await GroupDefinitionRecordToDto(groupDefinitionRecord); + + return dto; + } + + protected async virtual Task FindByNameAsync(string name) + { + var groupDefinitionFilter = await _groupDefinitionBasicRepository.GetQueryableAsync(); + + var groupDefinitionRecord = await AsyncExecuter.FirstOrDefaultAsync( + groupDefinitionFilter.Where(x => x.Name == name)); + + return groupDefinitionRecord; + } + + protected async virtual Task GroupDefinitionRecordToDto(PermissionGroupDefinitionRecord groupDefinitionRecord) + { + var groupDto = new PermissionGroupDefinitionDto + { + Name = groupDefinitionRecord.Name, + FormatedDisplayName = groupDefinitionRecord.DisplayName, + }; + + var displayName = _localizableStringSerializer.Deserialize(groupDefinitionRecord.DisplayName); + groupDto.DisplayName = await displayName.LocalizeAsync(StringLocalizerFactory); + + foreach (var property in groupDefinitionRecord.ExtraProperties) + { + groupDto.SetProperty(property.Key, property.Value); + } + + return groupDto; + } + + protected async virtual Task GroupDefinitionToDto(PermissionGroupDefinition groupDefinition) + { + var groupDto = new PermissionGroupDefinitionDto + { + Name = groupDefinition.Name + }; + + if (groupDefinition.DisplayName != null) + { + groupDto.DisplayName = await groupDefinition.DisplayName.LocalizeAsync(StringLocalizerFactory); + groupDto.FormatedDisplayName = _localizableStringSerializer.Serialize(groupDefinition.DisplayName); + } + + foreach (var property in groupDefinition.Properties) + { + groupDto.SetProperty(property.Key, property.Value); + } + + return groupDto; + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/PermissionManagementAppServiceBase.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/PermissionManagementAppServiceBase.cs new file mode 100644 index 000000000..edb4c2439 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/LINGYUN/Abp/PermissionManagement/PermissionManagementAppServiceBase.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Application.Services; +using Volo.Abp.PermissionManagement.Localization; + +namespace LINGYUN.Abp.PermissionManagement; +public abstract class PermissionManagementAppServiceBase : ApplicationService +{ + protected PermissionManagementAppServiceBase() + { + LocalizationResource = typeof(AbpPermissionManagementResource); + ObjectMapperContext = typeof(AbpPermissionManagementApplicationModule); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManagerExtensions.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManagerExtensions.cs new file mode 100644 index 000000000..132b6e6ea --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.Application/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManagerExtensions.cs @@ -0,0 +1,16 @@ +using System.Linq; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions; +public static class IPermissionDefinitionManagerExtensions +{ + public async static Task GetGroupOrNullAsync( + this IPermissionDefinitionManager permissionDefinitionManager, + string name + ) + { + var groups = await permissionDefinitionManager.GetGroupsAsync(); + + return groups.FirstOrDefault(x => x.Name == name); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xml b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.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/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN.Abp.PermissionManagement.HttpApi.csproj b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN.Abp.PermissionManagement.HttpApi.csproj new file mode 100644 index 000000000..cc612254d --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN.Abp.PermissionManagement.HttpApi.csproj @@ -0,0 +1,19 @@ + + + + + + + net7.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/AbpPermissionManagementHttpApiModule.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/AbpPermissionManagementHttpApiModule.cs new file mode 100644 index 000000000..605858340 --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/AbpPermissionManagementHttpApiModule.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement.Localization; +using VoloAbpPermissionManagementHttpApiModule = Volo.Abp.PermissionManagement.HttpApi.AbpPermissionManagementHttpApiModule; + +namespace LINGYUN.Abp.PermissionManagement.HttpApi; + +[DependsOn( + typeof(AbpPermissionManagementApplicationContractsModule), + typeof(VoloAbpPermissionManagementHttpApiModule))] +public class AbpPermissionManagementHttpApiModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(delegate (IMvcBuilder mvcBuilder) + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpPermissionManagementHttpApiModule)!.Assembly); + }); + + PreConfigure(options => + { + options.AddAssemblyResource( + typeof(AbpPermissionManagementResource), + typeof(AbpPermissionManagementApplicationContractsModule).Assembly); + }); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionDefinitionController.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionDefinitionController.cs new file mode 100644 index 000000000..b9905869f --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionDefinitionController.cs @@ -0,0 +1,62 @@ +using LINGYUN.Abp.PermissionManagement.Definitions; +using LINGYUN.Abp.PermissionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.PermissionManagement; + +namespace LINGYUN.Abp.PermissionManagement.HttpApi.Definitions; + +[Controller] +[Authorize(PermissionManagementPermissionNames.Definition.Default)] +[RemoteService(Name = PermissionManagementRemoteServiceConsts.RemoteServiceName)] +[Area(PermissionManagementRemoteServiceConsts.ModuleName)] +[Route("api/permission-management/definitions")] +public class PermissionDefinitionController : PermissionManagementControllerBase, IPermissionDefinitionAppService +{ + private readonly IPermissionDefinitionAppService _service; + + public PermissionDefinitionController(IPermissionDefinitionAppService service) + { + _service = service; + } + + [HttpPost] + [Authorize(PermissionManagementPermissionNames.Definition.Create)] + public virtual Task CreateAsync(PermissionDefinitionCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{name}")] + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)] + public virtual Task DeleteAsync(string name) + { + return _service.DeleteAsync(name); + } + + [HttpGet] + [Route("{name}")] + [Authorize(PermissionManagementPermissionNames.Definition.Delete)] + public virtual Task GetAsync(string name) + { + return _service.GetAsync(name); + } + + [HttpGet] + public virtual Task> GetListAsync(PermissionDefinitionGetListInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{name}")] + [Authorize(PermissionManagementPermissionNames.Definition.Update)] + public virtual Task UpdateAsync(string name, PermissionDefinitionUpdateDto input) + { + return _service.UpdateAsync(name, input); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionGroupDefinitionController.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionGroupDefinitionController.cs new file mode 100644 index 000000000..92ab1677d --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/Definitions/PermissionGroupDefinitionController.cs @@ -0,0 +1,62 @@ +using LINGYUN.Abp.PermissionManagement.Definitions; +using LINGYUN.Abp.PermissionManagement.Permissions; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.PermissionManagement; + +namespace LINGYUN.Abp.PermissionManagement.HttpApi.Definitions; + +[Controller] +[Authorize(PermissionManagementPermissionNames.GroupDefinition.Default)] +[RemoteService(Name = PermissionManagementRemoteServiceConsts.RemoteServiceName)] +[Area(PermissionManagementRemoteServiceConsts.ModuleName)] +[Route("api/permission-management/definitions/groups")] +public class PermissionGroupDefinitionController : PermissionManagementControllerBase, IPermissionGroupDefinitionAppService +{ + private readonly IPermissionGroupDefinitionAppService _service; + + public PermissionGroupDefinitionController(IPermissionGroupDefinitionAppService service) + { + _service = service; + } + + [HttpPost] + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Create)] + public virtual Task CreateAsync(PermissionGroupDefinitionCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{name}")] + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)] + public virtual Task DeleteAsync(string name) + { + return _service.DeleteAsync(name); + } + + [HttpGet] + [Route("{name}")] + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Delete)] + public virtual Task GetAsync(string name) + { + return _service.GetAsync(name); + } + + [HttpGet] + public virtual Task> GetListAsync(PermissionGroupDefinitionGetListInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{name}")] + [Authorize(PermissionManagementPermissionNames.GroupDefinition.Update)] + public virtual Task UpdateAsync(string name, PermissionGroupDefinitionUpdateDto input) + { + return _service.UpdateAsync(name, input); + } +} diff --git a/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/PermissionManagementControllerBase.cs b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/PermissionManagementControllerBase.cs new file mode 100644 index 000000000..a2266adda --- /dev/null +++ b/aspnet-core/modules/permissions-management/LINGYUN.Abp.PermissionManagement.HttpApi/LINGYUN/Abp/PermissionManagement/HttpApi/PermissionManagementControllerBase.cs @@ -0,0 +1,11 @@ +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.PermissionManagement.Localization; + +namespace LINGYUN.Abp.PermissionManagement.HttpApi; +public abstract class PermissionManagementControllerBase : AbpControllerBase +{ + protected PermissionManagementControllerBase() + { + LocalizationResource = typeof(AbpPermissionManagementResource); + } +} diff --git a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj index 0c4cc9212..4eaa76c22 100644 --- a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj +++ b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Razor/LINGYUN.Abp.TextTemplating.Razor.csproj @@ -4,7 +4,7 @@ - netstandard2.0 + netstandard2.1 diff --git a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj index 80a85ad29..c664ce204 100644 --- a/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj +++ b/aspnet-core/modules/text-templating/LINGYUN.Abp.TextTemplating.Scriban/LINGYUN.Abp.TextTemplating.Scriban.csproj @@ -4,7 +4,7 @@ - netstandard2.0 + netstandard2.1 diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/.gitignore b/aspnet-core/services/LY.MicroService.Applications.Single/.gitignore new file mode 100644 index 000000000..6cdbad2bc --- /dev/null +++ b/aspnet-core/services/LY.MicroService.Applications.Single/.gitignore @@ -0,0 +1,2 @@ +wwwroot +package*.json \ No newline at end of file diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index 37b961fa8..2437dde64 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -103,6 +103,8 @@ + + @@ -160,7 +162,9 @@ + + diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs index 26b4d1d2d..ea3bcb9dc 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs @@ -491,6 +491,8 @@ public partial class MicroServiceApplicationsSingleModule .AddLanguagesMapOrUpdate( "vben-admin-ui", new NameValue("zh_CN", "zh-Hans")); + + options.UseAllPersistence(); }); Configure(options => @@ -553,7 +555,7 @@ public partial class MicroServiceApplicationsSingleModule if (isDevelopment) { - // services.AddAlwaysAllowAuthorization(); + services.AddAlwaysAllowAuthorization(); } if (!isDevelopment) diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index 7e80bc4ea..fa265d816 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -27,6 +27,8 @@ using LINGYUN.Abp.Elsa.EntityFrameworkCore; using LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.FeatureManagement; +using LINGYUN.Abp.FeatureManagement.HttpApi; using LINGYUN.Abp.Features.LimitValidation; using LINGYUN.Abp.Features.LimitValidation.Redis.Client; using LINGYUN.Abp.Http.Client.Wrapper; @@ -56,6 +58,8 @@ using LINGYUN.Abp.OpenIddict; using LINGYUN.Abp.OssManagement; using LINGYUN.Abp.OssManagement.FileSystem.ImageSharp; using LINGYUN.Abp.OssManagement.SettingManagement; +using LINGYUN.Abp.PermissionManagement; +using LINGYUN.Abp.PermissionManagement.HttpApi; using LINGYUN.Abp.PermissionManagement.OrganizationUnits; using LINGYUN.Abp.Saas; using LINGYUN.Abp.Saas.EntityFrameworkCore; @@ -94,15 +98,12 @@ using Volo.Abp.Autofac; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.EntityFrameworkCore.MySQL; using Volo.Abp.EventBus; -using Volo.Abp.FeatureManagement; using Volo.Abp.FeatureManagement.EntityFrameworkCore; using Volo.Abp.Identity.AspNetCore; using Volo.Abp.Modularity; using Volo.Abp.OpenIddict; using Volo.Abp.OpenIddict.EntityFrameworkCore; -using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement.EntityFrameworkCore; -using Volo.Abp.PermissionManagement.HttpApi; using Volo.Abp.PermissionManagement.Identity; using Volo.Abp.PermissionManagement.IdentityServer; using Volo.Abp.SettingManagement; @@ -179,7 +180,6 @@ namespace LY.MicroService.Applications.Single; typeof(WebhooksManagementApplicationModule), typeof(WebhooksManagementHttpApiModule), typeof(WebhooksManagementEntityFrameworkCoreModule), - typeof(AbpFeatureManagementDomainModule), typeof(AbpFeatureManagementApplicationModule), typeof(AbpFeatureManagementHttpApiModule), typeof(AbpFeatureManagementEntityFrameworkCoreModule), @@ -187,7 +187,6 @@ namespace LY.MicroService.Applications.Single; typeof(AbpSettingManagementApplicationModule), typeof(AbpSettingManagementHttpApiModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), - typeof(AbpPermissionManagementDomainModule), typeof(AbpPermissionManagementApplicationModule), typeof(AbpPermissionManagementHttpApiModule), typeof(AbpPermissionManagementDomainIdentityModule), diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json b/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json index e896a500f..1bf0d8d7f 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json +++ b/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json @@ -14,7 +14,7 @@ "launchBrowser": false, "applicationUrl": "http://127.0.0.1:30000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Production" + "ASPNETCORE_ENVIRONMENT": "Development" } } } diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/gulpfile.js b/aspnet-core/services/LY.MicroService.Applications.Single/gulpfile.js new file mode 100644 index 000000000..5dcf4c5c6 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.Applications.Single/gulpfile.js @@ -0,0 +1,9 @@ +"use strict"; + +var gulp = require("gulp"), + path = require('path'), + copyResources = require('./node_modules/@abp/aspnetcore.mvc.ui/gulp/copy-resources.js'); + +exports.default = function(){ + return copyResources(path.resolve('./')); +}; \ No newline at end of file diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs index f4750e6e8..e65c75eb3 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs @@ -5,6 +5,8 @@ using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.OpenIddict.Permissions; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using Medallion.Threading; +using Medallion.Threading.Redis; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; @@ -26,10 +28,12 @@ using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.FeatureManagement; using Volo.Abp.GlobalFeatures; +using Volo.Abp.Identity.Localization; using Volo.Abp.Json; using Volo.Abp.Json.SystemTextJson; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; +using Volo.Abp.OpenIddict.Localization; using Volo.Abp.PermissionManagement; using Volo.Abp.Threading; using Volo.Abp.UI.Navigation.Urls; @@ -178,6 +182,16 @@ public partial class AuthServerHttpApiHostModule }); } + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + private void ConfigureCaching(IConfiguration configuration) { Configure(options => @@ -268,6 +282,10 @@ public partial class AuthServerHttpApiHostModule { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.UsePersistences( + typeof(IdentityResource), + typeof(AbpOpenIddictResource)); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs index 6fd04ba1a..1cde28844 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs @@ -92,6 +92,7 @@ public partial class AuthServerHttpApiHostModule : AbpModule ConfigureSwagger(context.Services); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj index 66c71169f..a89f0e3c6 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/LY.MicroService.AuthServer.HttpApi.Host.csproj @@ -10,6 +10,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json index 74d17f1f3..f8b69155c 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json @@ -55,6 +55,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application" diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs index e4b34a115..3f436d880 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.Configure.cs @@ -2,6 +2,8 @@ using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using Medallion.Threading.Redis; +using Medallion.Threading; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Extensions.DependencyInjection; @@ -194,6 +196,17 @@ public partial class AuthServerModule options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); }); } + + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + private void ConfigureCaching(IConfiguration configuration) { Configure(options => @@ -237,6 +250,8 @@ public partial class AuthServerModule options.Resources .Get() .AddVirtualJson("/Localization/Resources"); + + options.UsePersistence(); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs index fc632d3e8..1446881f0 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs +++ b/aspnet-core/services/LY.MicroService.AuthServer/AuthServerModule.cs @@ -9,6 +9,7 @@ using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.Identity.EntityFrameworkCore; using LINGYUN.Abp.Identity.OrganizaztionUnits; using LINGYUN.Abp.Localization.CultureMap; +using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.OpenIddict.LinkUser; using LINGYUN.Abp.OpenIddict.Sms; using LINGYUN.Abp.OpenIddict.WeChat; @@ -60,6 +61,7 @@ namespace LY.MicroService.AuthServer; typeof(AbpAuthenticationQQModule), typeof(AbpAuthenticationWeChatModule), typeof(AbpIdentityOrganizaztionUnitsModule), + typeof(AbpLocalizationManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementDomainIdentityModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), @@ -106,6 +108,7 @@ public partial class AuthServerModule : AbpModule ConfigureAuditing(configuration); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj b/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj index d852ec065..e181ad8df 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj +++ b/aspnet-core/services/LY.MicroService.AuthServer/LY.MicroService.AuthServer.csproj @@ -15,6 +15,7 @@ + @@ -56,6 +57,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json b/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json index e66c45cb3..de3361ed3 100644 --- a/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.AuthServer/appsettings.Development.json @@ -29,10 +29,11 @@ "Default": "Server=127.0.0.1;Database=AuthServer-v70;User Id=root;Password=123456", "AbpIdentity": "Server=127.0.0.1;Database=AuthServer-v70;User Id=root;Password=123456", "OpenIddict": "Server=127.0.0.1;Database=AuthServer-v70;User Id=root;Password=123456", - "AbpSaas": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", - "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", - "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", - "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" + "AbpSaas": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-V70;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456" }, "CAP": { "EventBus": { @@ -55,6 +56,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application" 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 92546e12f..7a115cf17 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 Autofac.Core; +using DotNetCore.CAP; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; @@ -6,6 +7,8 @@ using LINGYUN.Abp.Saas; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LINGYUN.Abp.TextTemplating; +using Medallion.Threading.Redis; +using Medallion.Threading; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; @@ -181,6 +184,16 @@ public partial class BackendAdminHttpApiHostModule }); } + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + private void ConfigureVirtualFileSystem() { Configure(options => @@ -280,6 +293,8 @@ public partial class BackendAdminHttpApiHostModule .AddLanguagesMapOrUpdate( "vben-admin-ui", new NameValue("zh_CN", "zh-Hans")); + + options.UseAllPersistence(); }); 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 bcdd76896..851ec6abf 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs @@ -1,5 +1,4 @@ -using DotNetCore.CAP; -using LINGYUN.Abp.AspNetCore.HttpOverrides; +using LINGYUN.Abp.AspNetCore.HttpOverrides; using LINGYUN.Abp.AspNetCore.Mvc.Localization; using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; using LINGYUN.Abp.Auditing; @@ -10,11 +9,14 @@ using LINGYUN.Abp.Data.DbMigrator; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.FeatureManagement; +using LINGYUN.Abp.FeatureManagement.HttpApi; using LINGYUN.Abp.Http.Client.Wrapper; using LINGYUN.Abp.Identity.EntityFrameworkCore; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.Logging.Serilog.Elasticsearch; +using LINGYUN.Abp.PermissionManagement; +using LINGYUN.Abp.PermissionManagement.HttpApi; using LINGYUN.Abp.PermissionManagement.OrganizationUnits; using LINGYUN.Abp.Saas; using LINGYUN.Abp.Saas.EntityFrameworkCore; @@ -24,12 +26,12 @@ using LINGYUN.Abp.SettingManagement; using LINGYUN.Abp.Sms.Aliyun; using LINGYUN.Abp.TextTemplating; using LINGYUN.Abp.TextTemplating.EntityFrameworkCore; +using LINGYUN.Abp.TextTemplating.Scriban; using LY.MicroService.BackendAdmin.EntityFrameworkCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using System.Linq; using Volo.Abp; using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; @@ -37,13 +39,10 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.EntityFrameworkCore.MySQL; -using Volo.Abp.FeatureManagement; using Volo.Abp.FeatureManagement.EntityFrameworkCore; using Volo.Abp.IdentityServer.EntityFrameworkCore; using Volo.Abp.Modularity; -using Volo.Abp.PermissionManagement; using Volo.Abp.PermissionManagement.EntityFrameworkCore; -using Volo.Abp.PermissionManagement.HttpApi; using Volo.Abp.PermissionManagement.Identity; using Volo.Abp.PermissionManagement.IdentityServer; using Volo.Abp.SettingManagement.EntityFrameworkCore; @@ -97,6 +96,7 @@ namespace LY.MicroService.BackendAdmin; typeof(AbpLocalizationCultureMapModule), typeof(AbpHttpClientWrapperModule), typeof(AbpAspNetCoreMvcWrapperModule), + typeof(AbpTextTemplatingScribanModule), typeof(AbpAutofacModule) )] public partial class BackendAdminHttpApiHostModule : AbpModule @@ -128,6 +128,7 @@ public partial class BackendAdminHttpApiHostModule : AbpModule ConfigureSwagger(context.Services); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } 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 0686ca906..7c0a0f5e4 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 @@ -14,6 +14,7 @@ + @@ -55,6 +56,8 @@ + + @@ -66,7 +69,9 @@ + + @@ -75,5 +80,6 @@ + diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json index 80ee99743..47ca95b17 100644 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/appsettings.Development.json @@ -60,6 +60,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application" diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj index 51cce78a3..78d1fa139 100644 --- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LY.MicroService.LocalizationManagement.HttpApi.Host.csproj @@ -10,6 +10,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs index bb491d1c0..9ab597ce3 100644 --- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.Configure.cs @@ -4,6 +4,8 @@ using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using Medallion.Threading.Redis; +using Medallion.Threading; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; @@ -28,7 +30,7 @@ using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem; - +using LINGYUN.Abp.LocalizationManagement.Localization; namespace LY.MicroService.LocalizationManagement; @@ -144,6 +146,15 @@ public partial class LocalizationManagementHttpApiHostModule } }); } + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } private void ConfigureCaching(IConfiguration configuration) { @@ -216,6 +227,8 @@ public partial class LocalizationManagementHttpApiHostModule { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.UsePersistence(); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs index 4f58d9727..cfda98277 100644 --- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs @@ -84,6 +84,7 @@ namespace LY.MicroService.LocalizationManagement ConfigureSwagger(context.Services); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json index b25a694b0..6fac88373 100644 --- a/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/appsettings.Development.json @@ -50,6 +50,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application" 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 65403e9e7..81c069075 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 @@ -10,6 +10,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs index 858aea532..f09f6d410 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs @@ -4,6 +4,9 @@ using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Platform.Localization; +using Medallion.Threading; +using Medallion.Threading.Redis; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; @@ -178,6 +181,16 @@ public partial class PlatformManagementHttpApiHostModule }); } + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + private void ConfigureCaching(IConfiguration configuration) { Configure(options => @@ -262,6 +275,8 @@ public partial class PlatformManagementHttpApiHostModule { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.UsePersistence(); }); Configure(options => 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 e55316df9..fa7858839 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs @@ -120,6 +120,7 @@ public partial class PlatformManagementHttpApiHostModule : AbpModule ConfigureSwagger(context.Services); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json index 5de881913..b0ec23206 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/appsettings.Development.json @@ -83,6 +83,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application" diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj index af338c52f..199a15653 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj @@ -14,6 +14,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs index 10eb0c53b..f7a322e91 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.Configure.cs @@ -7,6 +7,8 @@ using LINGYUN.Abp.Notifications; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LY.MicroService.RealtimeMessage.BackgroundJobs; +using Medallion.Threading.Redis; +using Medallion.Threading; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; @@ -36,6 +38,7 @@ using Volo.Abp.MultiTenancy; using Volo.Abp.Quartz; using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem; +using LINGYUN.Abp.Notifications.Localization; namespace LY.MicroService.RealtimeMessage; @@ -190,6 +193,16 @@ public partial class RealtimeMessageHttpApiHostModule }); } + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + private void ConfigureCaching(IConfiguration configuration) { Configure(options => @@ -333,6 +346,10 @@ public partial class RealtimeMessageHttpApiHostModule options.Resources .Get() .AddVirtualJson("/Localization/Resources"); + + options.UsePersistences( + typeof(MessageServiceResource), + typeof(NotificationsResource)); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs index b9327c39d..ed73ad8c0 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs @@ -134,6 +134,7 @@ public partial class RealtimeMessageHttpApiHostModule : AbpModule ConfigureSwagger(context.Services); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json index 273ea5c8e..fb38ce161 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/appsettings.Development.json @@ -47,6 +47,12 @@ "AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", "AbpTextTemplating": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456" }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "IsEnabled": true, "Configuration": "127.0.0.1,defaultDatabase=8", diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs index ad9bdebb1..56602315c 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.Configure.cs @@ -5,6 +5,7 @@ using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Abp.TaskManagement.Localization; using Medallion.Threading; using Medallion.Threading.Redis; using Microsoft.AspNetCore.Authentication.JwtBearer; @@ -126,8 +127,12 @@ public partial class TaskManagementHttpApiHostModule private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration) { - var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); - services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } } private void ConfigureDbContext() @@ -275,6 +280,8 @@ public partial class TaskManagementHttpApiHostModule { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.UsePersistence(); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json index c03b0e207..283ac37d2 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/appsettings.Development.json @@ -80,6 +80,7 @@ } }, "DistributedLock": { + "IsEnabled": true, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=15" } diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs index 31af82d0c..069951ab4 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.Configure.cs @@ -7,6 +7,7 @@ using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LINGYUN.Abp.Webhooks; using LINGYUN.Abp.Webhooks.BackgroundJobs; using LINGYUN.Abp.WebhooksManagement; +using LINGYUN.Abp.WebhooksManagement.Localization; using LINGYUN.Abp.Wrapper; using Medallion.Threading; using Medallion.Threading.Redis; @@ -342,6 +343,8 @@ public partial class WebhooksManagementHttpApiHostModule { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.UsePersistence(); }); } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs index 9dc187c7f..c6e134fa1 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs @@ -5,6 +5,7 @@ using Elsa.Options; using Elsa.Rebus.RabbitMq; using LINGYUN.Abp.BackgroundTasks; using LINGYUN.Abp.BlobStoring.OssManagement; +using LINGYUN.Abp.Elsa.Localization; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; @@ -369,6 +370,8 @@ public partial class WorkflowManagementHttpApiHostModule { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.UsePersistence(); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs index 70dbdf4a9..ec6f496d7 100644 --- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs @@ -4,6 +4,8 @@ using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using Medallion.Threading.Redis; +using Medallion.Threading; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; @@ -34,6 +36,7 @@ using Volo.Abp.PermissionManagement; using Volo.Abp.Threading; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; +using Volo.Abp.IdentityServer.Localization; namespace LY.MicroService.IdentityServer; @@ -177,6 +180,15 @@ public partial class IdentityServerHttpApiHostModule options.Applications["STS"].RootUrl = configuration["App:StsUrl"]; }); } + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } private void ConfigureCaching(IConfiguration configuration) { @@ -272,6 +284,10 @@ public partial class IdentityServerHttpApiHostModule options.Resources .Get() .AddVirtualJson("/Localization/Resources"); + + options.UsePersistences( + typeof(IdentityResource), + typeof(AbpIdentityServerResource)); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs index 65bb3a130..71c228cf7 100644 --- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.cs @@ -94,6 +94,7 @@ public partial class IdentityServerHttpApiHostModule : AbpModule ConfigureSwagger(context.Services); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj index 94c13e1a4..ab1ae994f 100644 --- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/LY.MicroService.identityServer.HttpApi.Host.csproj @@ -18,6 +18,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json index a6b151399..ee970f9d9 100644 --- a/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json @@ -55,6 +55,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application" diff --git a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs index 9db5936b8..2a58c3f12 100644 --- a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.Configure.cs @@ -4,6 +4,8 @@ using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; using LY.MicroService.IdentityServer.IdentityResources; +using Medallion.Threading; +using Medallion.Threading.Redis; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; @@ -144,6 +146,17 @@ public partial class IdentityServerModule options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); }); } + + private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["DistributedLock:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + private void ConfigureCaching(IConfiguration configuration) { Configure(options => @@ -201,6 +214,8 @@ public partial class IdentityServerModule options.Resources .Get() .AddVirtualJson("/Localization/Resources"); + + options.UsePersistence(); }); Configure(options => diff --git a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs index 1482b2007..664a90681 100644 --- a/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs +++ b/aspnet-core/services/LY.MicroService.identityServer/IdentityServerModule.cs @@ -13,6 +13,7 @@ using LINGYUN.Abp.Identity.OrganizaztionUnits; using LINGYUN.Abp.IdentityServer; using LINGYUN.Abp.IdentityServer.EntityFrameworkCore; using LINGYUN.Abp.Localization.CultureMap; +using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; @@ -59,6 +60,7 @@ namespace LY.MicroService.IdentityServer; typeof(AbpAuthenticationWeChatModule), typeof(AbpAuthenticationQQModule), typeof(AbpIdentityOrganizaztionUnitsModule), + typeof(AbpLocalizationManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementDomainIdentityModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), @@ -108,6 +110,7 @@ public partial class IdentityServerModule : AbpModule ConfigureUrls(configuration); ConfigureMultiTenancy(configuration); ConfigureCors(context.Services, configuration); + ConfigureDistributedLocking(context.Services, configuration); ConfigureSeedWorker(context.Services, hostingEnvironment.IsDevelopment()); ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); } diff --git a/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj b/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj index fd9d7a66f..0fd004f62 100644 --- a/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj +++ b/aspnet-core/services/LY.MicroService.identityServer/LY.MicroService.IdentityServer.csproj @@ -16,6 +16,7 @@ + @@ -58,6 +59,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json b/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json index 8c5e09b4c..f4e522891 100644 --- a/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json +++ b/aspnet-core/services/LY.MicroService.identityServer/appsettings.Development.json @@ -55,6 +55,12 @@ "VirtualHost": "/" } }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=13" + } + }, "Redis": { "Configuration": "127.0.0.1,defaultDatabase=10", "InstanceName": "LINGYUN.Abp.Application"