mirror of https://github.com/abpframework/abp.git
15 changed files with 369 additions and 48 deletions
@ -1,38 +1,51 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using System.Collections.Immutable; |
using Volo.Abp.Localization; |
||||
|
|
||||
namespace Volo.Abp.Features |
namespace Volo.Abp.Features |
||||
{ |
{ |
||||
public class FeatureDefinitionContext : IFeatureDefinitionContext |
public class FeatureDefinitionContext : IFeatureDefinitionContext |
||||
{ |
{ |
||||
protected Dictionary<string, FeatureDefinition> Features { get; } |
internal Dictionary<string, FeatureGroupDefinition> Groups { get; } |
||||
|
|
||||
public FeatureDefinitionContext(Dictionary<string, FeatureDefinition> features) |
public FeatureDefinitionContext() |
||||
{ |
{ |
||||
Features = features; |
Groups = new Dictionary<string, FeatureGroupDefinition>(); |
||||
} |
} |
||||
|
|
||||
public virtual FeatureDefinition GetOrNull(string name) |
public FeatureGroupDefinition AddGroup(string name, ILocalizableString displayName = null) |
||||
{ |
{ |
||||
return Features.GetOrDefault(name); |
Check.NotNull(name, nameof(name)); |
||||
} |
|
||||
|
|
||||
public virtual IReadOnlyList<FeatureDefinition> GetAll() |
if (Groups.ContainsKey(name)) |
||||
{ |
{ |
||||
return Features.Values.ToImmutableList(); |
throw new AbpException($"There is already an existing permission group with name: {name}"); |
||||
|
} |
||||
|
|
||||
|
return Groups[name] = new FeatureGroupDefinition(name, displayName); |
||||
} |
} |
||||
|
|
||||
public virtual void Add(params FeatureDefinition[] definitions) |
public FeatureGroupDefinition GetGroupOrNull(string name) |
||||
{ |
{ |
||||
if (definitions.IsNullOrEmpty()) |
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
if (!Groups.ContainsKey(name)) |
||||
{ |
{ |
||||
return; |
return null; |
||||
} |
} |
||||
|
|
||||
foreach (var definition in definitions) |
return Groups[name]; |
||||
|
} |
||||
|
|
||||
|
public void RemoveGroup(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
if (!Groups.ContainsKey(name)) |
||||
{ |
{ |
||||
Features[definition.Name] = definition; |
throw new AbpException($"Undefined feature group: '{name}'."); |
||||
} |
} |
||||
|
|
||||
|
Groups.Remove(name); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,108 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Features |
||||
|
{ |
||||
|
public class FeatureGroupDefinition |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Unique name of the group.
|
||||
|
/// </summary>
|
||||
|
public string Name { get; } |
||||
|
|
||||
|
public Dictionary<string, object> Properties { get; } |
||||
|
|
||||
|
public ILocalizableString DisplayName |
||||
|
{ |
||||
|
get => _displayName; |
||||
|
set => _displayName = Check.NotNull(value, nameof(value)); |
||||
|
} |
||||
|
private ILocalizableString _displayName; |
||||
|
|
||||
|
public IReadOnlyList<FeatureDefinition> Features => _features.ToImmutableList(); |
||||
|
private readonly List<FeatureDefinition> _features; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets/sets a key-value on the <see cref="Properties"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="name">Name of the property</param>
|
||||
|
/// <returns>
|
||||
|
/// Returns the value in the <see cref="Properties"/> dictionary by given <see cref="name"/>.
|
||||
|
/// Returns null if given <see cref="name"/> is not present in the <see cref="Properties"/> dictionary.
|
||||
|
/// </returns>
|
||||
|
public object this[string name] |
||||
|
{ |
||||
|
get => Properties.GetOrDefault(name); |
||||
|
set => Properties[name] = value; |
||||
|
} |
||||
|
|
||||
|
protected internal FeatureGroupDefinition( |
||||
|
string name, |
||||
|
ILocalizableString displayName = null) |
||||
|
{ |
||||
|
Name = name; |
||||
|
DisplayName = displayName ?? new FixedLocalizableString(Name); |
||||
|
|
||||
|
Properties = new Dictionary<string, object>(); |
||||
|
_features = new List<FeatureDefinition>(); |
||||
|
} |
||||
|
|
||||
|
public virtual FeatureDefinition AddFeature( |
||||
|
string name, |
||||
|
string defaultValue = null, |
||||
|
ILocalizableString displayName = null, |
||||
|
ILocalizableString description = null, |
||||
|
bool isVisibleToClients = true) |
||||
|
{ |
||||
|
var feature = new FeatureDefinition( |
||||
|
name, |
||||
|
defaultValue, |
||||
|
displayName, |
||||
|
description, |
||||
|
isVisibleToClients |
||||
|
); |
||||
|
|
||||
|
_features.Add(feature); |
||||
|
|
||||
|
return feature; |
||||
|
} |
||||
|
|
||||
|
public virtual List<FeatureDefinition> GetFeaturesWithChildren() |
||||
|
{ |
||||
|
var features = new List<FeatureDefinition>(); |
||||
|
|
||||
|
foreach (var feature in _features) |
||||
|
{ |
||||
|
AddFeatureToListRecursively(features, feature); |
||||
|
} |
||||
|
|
||||
|
return features; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets a property in the <see cref="Properties"/> dictionary.
|
||||
|
/// This is a shortcut for nested calls on this object.
|
||||
|
/// </summary>
|
||||
|
public virtual FeatureGroupDefinition WithProperty(string key, object value) |
||||
|
{ |
||||
|
Properties[key] = value; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
private void AddFeatureToListRecursively(List<FeatureDefinition> features, FeatureDefinition feature) |
||||
|
{ |
||||
|
features.Add(feature); |
||||
|
|
||||
|
foreach (var child in feature.Children) |
||||
|
{ |
||||
|
AddFeatureToListRecursively(features, child); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return $"[{nameof(FeatureGroupDefinition)} {Name}]"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,14 @@ |
|||||
namespace Volo.Abp.Features |
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Features |
||||
{ |
{ |
||||
public interface IFeatureDefinitionContext |
public interface IFeatureDefinitionContext |
||||
{ |
{ |
||||
FeatureDefinition GetOrNull(string name); |
FeatureGroupDefinition AddGroup([NotNull] string name, ILocalizableString displayName = null); |
||||
|
|
||||
void Add(params FeatureDefinition[] definitions); |
FeatureGroupDefinition GetGroupOrNull(string name); |
||||
|
|
||||
|
void RemoveGroup(string name); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp2.2</TargetFramework> |
||||
|
<LangVersion>latest</LangVersion> |
||||
|
<AssemblyName>Volo.Abp.Features.Tests</AssemblyName> |
||||
|
<PackageId>Volo.Abp.Features.Tests</PackageId> |
||||
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Features\Volo.Abp.Features.csproj" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace Volo.Abp.Features |
||||
|
{ |
||||
|
public class AbpFeaturesTestBase : AbpIntegratedTest<AbpFeaturesTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.Features |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpFeaturesModule), |
||||
|
typeof(AbpTestBaseModule), |
||||
|
typeof(AbpAutofacModule) |
||||
|
)] |
||||
|
public class AbpFeaturesTestModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Features |
||||
|
{ |
||||
|
public class FeatureDefinitionManager_Tests : AbpFeaturesTestBase |
||||
|
{ |
||||
|
private readonly IFeatureDefinitionManager _featureDefinitionManager; |
||||
|
|
||||
|
public FeatureDefinitionManager_Tests() |
||||
|
{ |
||||
|
_featureDefinitionManager = GetRequiredService<IFeatureDefinitionManager>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Get_Defined_Features() |
||||
|
{ |
||||
|
_featureDefinitionManager.GetOrNull("BooleanTestFeature1").ShouldNotBeNull(); |
||||
|
_featureDefinitionManager.Get("BooleanTestFeature1").Name.ShouldBe("BooleanTestFeature1"); |
||||
|
|
||||
|
_featureDefinitionManager.GetOrNull("IntegerTestFeature1").ShouldNotBeNull(); |
||||
|
_featureDefinitionManager.Get("IntegerTestFeature1").Name.ShouldBe("IntegerTestFeature1"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Not_Get_Undefined_Features() |
||||
|
{ |
||||
|
_featureDefinitionManager.GetOrNull("UndefinedFeature").ShouldBeNull(); |
||||
|
Assert.Throws<AbpException>(() => |
||||
|
{ |
||||
|
_featureDefinitionManager.Get("UndefinedFeature"); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace Volo.Abp.Features |
||||
|
{ |
||||
|
public class TestFeatureDefinitionProvider : FeatureDefinitionProvider |
||||
|
{ |
||||
|
public override void Define(IFeatureDefinitionContext context) |
||||
|
{ |
||||
|
var group = context.AddGroup("Test Group"); |
||||
|
group.AddFeature("BooleanTestFeature1"); |
||||
|
group.AddFeature("IntegerTestFeature1", defaultValue: "1"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue