Skip to content

Commit

Permalink
Merge pull request #5176 from abpframework/maliming/feature-patch
Browse files Browse the repository at this point in the history
Disable features based on inheritance relationship.
  • Loading branch information
hikalkan authored Aug 29, 2020
2 parents baf4c03 + e8504af commit 88ad0b5
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using Volo.Abp.Validation.StringValues;

namespace Volo.Abp.FeatureManagement
Expand All @@ -11,6 +10,8 @@ public class FeatureDto

public string Value { get; set; }

public FeatureProviderDto Provider { get; set; }

public string Description { get; set; }

public IStringValueType ValueType { get; set; }
Expand All @@ -19,4 +20,4 @@ public class FeatureDto

public string ParentName { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Volo.Abp.FeatureManagement
{
public class FeatureProviderDto
{
public string Name { get; set; }

public string Key { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ public virtual async Task<FeatureListDto> GetAsync([NotNull] string providerName

foreach (var featureDefinition in featureDefinitions)
{
var feature = await FeatureManager.GetOrNullWithProviderAsync(featureDefinition.Name, providerName, providerKey);
features.Add(new FeatureDto
{
Name = featureDefinition.Name,
DisplayName = featureDefinition.DisplayName?.Localize(StringLocalizerFactory),
ValueType = featureDefinition.ValueType,
Description = featureDefinition.Description?.Localize(StringLocalizerFactory),
ParentName = featureDefinition.Parent?.Name,
Value = await FeatureManager.GetOrNullAsync(featureDefinition.Name, providerName, providerKey)
Value = feature.Value,
Provider = new FeatureProviderDto
{
Name = feature.Provider?.Name,
Key = feature.Provider?.Key
}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ public class DefaultValueFeatureManagementProvider : IFeatureManagementProvider,
{
public string Name => DefaultValueFeatureValueProvider.ProviderName;

public bool Compatible(string providerName)
{
return providerName == Name;
}

public virtual Task<string> GetOrNullAsync(FeatureDefinition feature, string providerKey)
{
return Task.FromResult(feature.DefaultValue);
Expand All @@ -23,4 +28,4 @@ public virtual Task ClearAsync(FeatureDefinition feature, string providerKey)
throw new AbpException($"Can not clear default value of a feature. It is only possible while defining the feature in a {typeof(IFeatureDefinitionProvider)} implementation.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,15 @@ public static Task<List<FeatureNameValue>> GetAllDefaultAsync(this IFeatureManag
{
return featureManager.GetAllAsync(DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}

public static Task<FeatureNameValueWithGrantedProvider> GetOrNullWithProviderAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true)
{
return featureManager.GetOrNullWithProviderAsync(name, DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}

public static Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderAsync(this IFeatureManager featureManager, bool fallback = true)
{
return featureManager.GetAllWithProviderAsync(DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,19 @@ public static Task<List<FeatureNameValue>> GetAllForEditionAsync(this IFeatureMa
return featureManager.GetAllAsync(EditionFeatureValueProvider.ProviderName, editionId.ToString(), fallback);
}

public static Task<FeatureNameValueWithGrantedProvider> GetOrNullWithProviderForEditionAsync(this IFeatureManager featureManager, [NotNull] string name, Guid editionId, bool fallback = true)
{
return featureManager.GetOrNullWithProviderAsync(name, EditionFeatureValueProvider.ProviderName, editionId.ToString(), fallback);
}

public static Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderForEditionAsync(this IFeatureManager featureManager, Guid editionId, bool fallback = true)
{
return featureManager.GetAllWithProviderAsync(EditionFeatureValueProvider.ProviderName, editionId.ToString(), fallback);
}

public static Task SetForEditionAsync(this IFeatureManager featureManager, Guid editionId, [NotNull] string name, [CanBeNull] string value, bool forceToSet = false)
{
return featureManager.SetAsync(name, value, EditionFeatureValueProvider.ProviderName, editionId.ToString(), forceToSet);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ protected FeatureManagementProvider(IFeatureManagementStore store)
Store = store;
}

public virtual bool Compatible(string providerName)
{
return providerName == Name;
}

public virtual async Task<string> GetOrNullAsync(FeatureDefinition feature, string providerKey)
{
return await Store.GetOrNullAsync(feature.Name, Name, NormalizeProviderKey(providerKey));
Expand All @@ -34,4 +39,4 @@ protected virtual string NormalizeProviderKey(string providerKey)
return providerKey;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,37 @@ public FeatureManager(
true
);
}
public virtual Task<string> GetOrNullAsync(
string name,
string providerName,
string providerKey,

public virtual async Task<string> GetOrNullAsync(
string name,
string providerName,
string providerKey,
bool fallback = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));

return GetOrNullInternalAsync(name, providerName, providerKey, fallback);
return (await GetOrNullInternalAsync(name, providerName, providerKey, fallback)).Value;
}

public virtual async Task<List<FeatureNameValue>> GetAllAsync(
string providerName,
string providerKey,
string providerName,
string providerKey,
bool fallback = true)
{
return (await GetAllWithProviderAsync(providerName, providerKey, fallback))
.Select(x => new FeatureNameValue(x.Name, x.Value)).ToList();
}

public async Task<FeatureNameValueWithGrantedProvider> GetOrNullWithProviderAsync(string name, string providerName, string providerKey, bool fallback = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));

return await GetOrNullInternalAsync(name, providerName, providerKey, fallback);
}

public async Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderAsync(string providerName, string providerKey, bool fallback = true)
{
Check.NotNull(providerName, nameof(providerName));

Expand All @@ -68,42 +82,45 @@ public virtual async Task<List<FeatureNameValue>> GetAllAsync(

if (!providerList.Any())
{
return new List<FeatureNameValue>();
return new List<FeatureNameValueWithGrantedProvider>();
}

var featureValues = new Dictionary<string, FeatureNameValue>();
var featureValues = new Dictionary<string, FeatureNameValueWithGrantedProvider>();

foreach (var feature in featureDefinitions)
{
string value = null;

var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(feature.Name, null);
foreach (var provider in providerList)
{
var providerValue = await provider.GetOrNullAsync(
feature,
provider.Name == providerName ? providerKey : null
);
string pk = null;
if (provider.Compatible(providerName))
{
pk = providerKey;
}

if (providerValue != null)
var value = await provider.GetOrNullAsync(feature, pk);
if (value != null)
{
value = providerValue;
featureNameValueWithGrantedProvider.Value = value;
featureNameValueWithGrantedProvider.Provider = new FeatureValueProviderInfo(provider.Name, pk);
break;
}
}

if (value != null)
if (featureNameValueWithGrantedProvider.Value != null)
{
featureValues[feature.Name] = new FeatureNameValue(feature.Name, value);
featureValues[feature.Name] = featureNameValueWithGrantedProvider;
}
}

return featureValues.Values.ToList();
}

public virtual async Task SetAsync(
string name,
string value,
string providerName,
string providerKey,
string name,
string value,
string providerName,
string providerKey,
bool forceToSet = false)
{
Check.NotNull(name, nameof(name));
Expand All @@ -120,11 +137,11 @@ public virtual async Task SetAsync(
{
return;
}

if (providers.Count > 1 && !forceToSet && value != null)
{
var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
if (fallbackValue == value)
if (fallbackValue.Value == value)
{
//Clear the value if it's same as it's fallback value
value = null;
Expand All @@ -151,10 +168,10 @@ public virtual async Task SetAsync(
}
}

protected virtual async Task<string> GetOrNullInternalAsync(
string name,
string providerName,
string providerKey,
protected virtual async Task<FeatureNameValueWithGrantedProvider> GetOrNullInternalAsync(
string name,
string providerName,
string providerKey,
bool fallback = true) //TODO: Fallback is not used
{
var feature = FeatureDefinitionManager.Get(name);
Expand All @@ -166,21 +183,25 @@ protected virtual async Task<string> GetOrNullInternalAsync(
providers = providers.SkipWhile(c => c.Name != providerName);
}

string value = null;
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(name, null);
foreach (var provider in providers)
{
value = await provider.GetOrNullAsync(
feature,
provider.Name == providerName ? providerKey : null
);
string pk = null;
if (provider.Compatible(providerName))
{
pk = providerKey;
}

var value = await provider.GetOrNullAsync(feature, pk);
if (value != null)
{
featureNameValueWithGrantedProvider.Value = value;
featureNameValueWithGrantedProvider.Provider = new FeatureValueProviderInfo(provider.Name, pk);
break;
}
}

return value;
return featureNameValueWithGrantedProvider;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using JetBrains.Annotations;

namespace Volo.Abp.FeatureManagement
{
[Serializable]
public class FeatureNameValueWithGrantedProvider : NameValue
{
public FeatureValueProviderInfo Provider { get; set; }

public FeatureNameValueWithGrantedProvider([NotNull] string name, string value)
{
Check.NotNull(name, nameof(name));

Name = name;
Value = value;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using JetBrains.Annotations;

namespace Volo.Abp.FeatureManagement
{
[Serializable]
public class FeatureValueProviderInfo
{
public string Name { get; }

public string Key { get; }

public FeatureValueProviderInfo([NotNull]string name, string key)
{
Check.NotNull(name, nameof(name));

Name = name;
Key = key;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ public interface IFeatureManagementProvider
{
string Name { get; }

//TODO: Other better method name.
bool Compatible(string providerName);

Task<string> GetOrNullAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);

Task SetAsync([NotNull] FeatureDefinition feature, [NotNull] string value, [CanBeNull] string providerKey);

Task ClearAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public interface IFeatureManager

Task<List<FeatureNameValue>> GetAllAsync([NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);

Task<FeatureNameValueWithGrantedProvider> GetOrNullWithProviderAsync([NotNull]string name, [NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);

Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderAsync([NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);

Task SetAsync([NotNull] string name, [CanBeNull] string value, [NotNull] string providerName, [CanBeNull] string providerKey, bool forceToSet = false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ public static Task<List<FeatureNameValue>> GetAllForTenantAsync(this IFeatureMan
return featureManager.GetAllAsync(TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
}

public static Task<FeatureNameValueWithGrantedProvider> GetOrNullWithProviderForTenantAsync(this IFeatureManager featureManager, [NotNull] string name, Guid tenantId, bool fallback = true)
{
return featureManager.GetOrNullWithProviderAsync(name, TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
}

public static Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderForTenantAsync(this IFeatureManager featureManager, Guid tenantId, bool fallback = true)
{
return featureManager.GetAllWithProviderAsync(TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
}

public static Task SetForTenantAsync(this IFeatureManager featureManager, Guid tenantId, [NotNull] string name, [CanBeNull] string value, bool forceToSet = false)
{
return featureManager.SetAsync(name, value, TenantFeatureValueProvider.ProviderName, tenantId.ToString(), forceToSet);
Expand Down
Loading

0 comments on commit 88ad0b5

Please sign in to comment.