From cf595eb711175e8e370f2d841ae2f02a32c6aab5 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 26 Jun 2025 16:10:47 +0800 Subject: [PATCH] Force to set parent feature if children set. --- .../FeatureManagement/FeatureAppService.cs | 41 ++++++++++++++++++- .../FeatureAppService_Tests.cs | 35 ++++++++++++++++ .../TestFeatureDefinitionProvider.cs | 9 +++- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs index 4423036b51..af0bce93db 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs @@ -97,9 +97,48 @@ public class FeatureAppService : FeatureManagementAppServiceBase, IFeatureAppSer { await CheckProviderPolicy(providerName, providerKey); + var inputFeatureNames = input.Features.Select(f => f.Name).ToHashSet(); + var featureMap = input.Features.ToDictionary(f => f.Name); + var features = new Dictionary>(); + var processed = new HashSet(); + foreach (var feature in input.Features) { - await FeatureManager.SetAsync(feature.Name, feature.Value, providerName, providerKey); + if (!processed.Add(feature.Name)) + { + continue; + } + + var featureDefinition = await FeatureDefinitionManager.GetAsync(feature.Name); + var validChildren = new List(); + + foreach (var childFeature in featureDefinition.Children) + { + if (inputFeatureNames.Contains(childFeature.Name) && + featureMap.TryGetValue(childFeature.Name, out var childDto) && + processed.Add(childFeature.Name)) + { + validChildren.Add(childDto); + } + } + + features[feature] = validChildren; + } + + foreach (var feature in features) + { + var forceToSet = false; + foreach (var childFeature in feature.Value) + { + await FeatureManager.SetAsync(childFeature.Name, childFeature.Value, providerName, providerKey); + var value = await FeatureManager.GetOrNullWithProviderAsync(childFeature.Name, providerName, providerKey); + if (value.Provider.Name == providerName && value.Provider.Key == providerKey) + { + forceToSet = true; + } + } + + await FeatureManager.SetAsync(feature.Key.Name, feature.Key.Value, providerName, providerKey, forceToSet: forceToSet); } } diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs index 0bea533bc7..f3475d6ded 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs @@ -65,7 +65,42 @@ public class FeatureAppService_Tests : FeatureManagementApplicationTestBase x.Name == TestFeatureDefinitionProvider.SocialLogins && x.Value == false.ToString().ToLowerInvariant()) .ShouldBeTrue(); + } + + [Fact] + public async Task Select_Child_Feature_Should_Also_Update_Parent_Feature() + { + Login(_testData.User1Id); + + await _featureAppService.UpdateAsync(EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString(), new UpdateFeaturesDto() + { + Features = new List() + { + new UpdateFeatureDto() + { + Name = TestFeatureDefinitionProvider.EmailSupport, + Value = true.ToString().ToLowerInvariant() + }, + new UpdateFeatureDto() + { + Name = TestFeatureDefinitionProvider.EmailSupportMaxNumber, + Value = true.ToString().ToLowerInvariant() + } + } + }); + + (await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString())).Groups.SelectMany(g => g.Features).Any(x => + x.Name == TestFeatureDefinitionProvider.EmailSupportMaxNumber && + x.Value == true.ToString().ToLowerInvariant()) + .ShouldBeTrue(); + (await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName, + TestEditionIds.Regular.ToString())).Groups.SelectMany(g => g.Features).Any(x => + x.Name == TestFeatureDefinitionProvider.EmailSupport && + x.Value == true.ToString().ToLowerInvariant()) + .ShouldBeTrue(); } [Fact] diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestFeatureDefinitionProvider.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestFeatureDefinitionProvider.cs index 7590d8f3b9..0a19e56956 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestFeatureDefinitionProvider.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestFeatureDefinitionProvider.cs @@ -7,6 +7,7 @@ public class TestFeatureDefinitionProvider : FeatureDefinitionProvider { public const string SocialLogins = "SocialLogins"; public const string EmailSupport = "EmailSupport"; + public const string EmailSupportMaxNumber = "EmailSupportMaxNumber"; public const string DailyAnalysis = "DailyAnalysis"; public const string UserCount = "UserCount"; public const string ProjectCount = "ProjectCount"; @@ -21,11 +22,17 @@ public class TestFeatureDefinitionProvider : FeatureDefinitionProvider valueType: new ToggleStringValueType() ); - group.AddFeature( + var emailSupport = group.AddFeature( EmailSupport, + "true", valueType: new ToggleStringValueType() ); + emailSupport.CreateChild( + EmailSupportMaxNumber, + "false", + valueType: new ToggleStringValueType()); + group.AddFeature( DailyAnalysis, defaultValue: false.ToString().ToLowerInvariant(), //Optional, it is already false by default