mirror of https://github.com/abpframework/abp.git
committed by
GitHub
40 changed files with 586 additions and 61 deletions
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,3 @@ |
|||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
[assembly:InternalsVisibleTo("Volo.Abp.GlobalFeatures.Tests")] |
||||
@ -0,0 +1,21 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<AssemblyName>Volo.Abp.GlobalFeatures</AssemblyName> |
||||
|
<PackageId>Volo.Abp.GlobalFeatures</PackageId> |
||||
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class AbpGlobalFeaturesModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public abstract class GlobalFeature |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public GlobalModuleFeatures Module { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public GlobalFeatureManager FeatureManager { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public string FeatureName { get; } |
||||
|
|
||||
|
public bool IsEnabled |
||||
|
{ |
||||
|
get => FeatureManager.IsEnabled(FeatureName); |
||||
|
set => SetEnabled(value); |
||||
|
} |
||||
|
|
||||
|
protected GlobalFeature([NotNull] GlobalModuleFeatures module) |
||||
|
{ |
||||
|
Module = Check.NotNull(module, nameof(module)); |
||||
|
FeatureManager = Module.FeatureManager; |
||||
|
FeatureName = GlobalFeatureNameAttribute.GetName(GetType()); |
||||
|
} |
||||
|
|
||||
|
public virtual void Enable() |
||||
|
{ |
||||
|
FeatureManager.Enable(FeatureName); |
||||
|
} |
||||
|
|
||||
|
public virtual void Disable() |
||||
|
{ |
||||
|
FeatureManager.Disable(FeatureName); |
||||
|
} |
||||
|
|
||||
|
public void SetEnabled(bool isEnabled) |
||||
|
{ |
||||
|
if (isEnabled) |
||||
|
{ |
||||
|
Enable(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
Disable(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalFeatureDictionary : Dictionary<string, GlobalFeature> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalFeatureManager |
||||
|
{ |
||||
|
public static GlobalFeatureManager Instance { get; protected set; } = new GlobalFeatureManager(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A common dictionary to store arbitrary configurations.
|
||||
|
/// </summary>
|
||||
|
[NotNull] |
||||
|
public Dictionary<object, object> Configuration { get; } |
||||
|
|
||||
|
public GlobalModuleFeaturesDictionary Modules { get; } |
||||
|
|
||||
|
protected HashSet<string> EnabledFeatures { get; } |
||||
|
|
||||
|
internal GlobalFeatureManager() |
||||
|
{ |
||||
|
EnabledFeatures = new HashSet<string>(); |
||||
|
Configuration = new Dictionary<object, object>(); |
||||
|
Modules = new GlobalModuleFeaturesDictionary(this); |
||||
|
} |
||||
|
|
||||
|
public virtual bool IsEnabled<TFeature>() |
||||
|
where TFeature : GlobalFeature |
||||
|
{ |
||||
|
return IsEnabled(GlobalFeatureNameAttribute.GetName<TFeature>()); |
||||
|
} |
||||
|
|
||||
|
public virtual bool IsEnabled(string featureName) |
||||
|
{ |
||||
|
return EnabledFeatures.Contains(featureName); |
||||
|
} |
||||
|
|
||||
|
protected internal void Enable(string featureName) |
||||
|
{ |
||||
|
EnabledFeatures.AddIfNotContains(featureName); |
||||
|
} |
||||
|
|
||||
|
protected internal void Disable(string featureName) |
||||
|
{ |
||||
|
EnabledFeatures.Remove(featureName); |
||||
|
} |
||||
|
|
||||
|
public virtual IEnumerable<string> GetEnabledFeatureNames() |
||||
|
{ |
||||
|
return EnabledFeatures; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
[AttributeUsage(AttributeTargets.Class)] |
||||
|
public class GlobalFeatureNameAttribute : Attribute |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string Name { get; } |
||||
|
|
||||
|
public GlobalFeatureNameAttribute([NotNull] string name) |
||||
|
{ |
||||
|
Name = Check.NotNullOrWhiteSpace(name, nameof(name)); |
||||
|
} |
||||
|
|
||||
|
public static string GetName<TFeature>() |
||||
|
where TFeature : GlobalFeature |
||||
|
{ |
||||
|
return GetName(typeof(TFeature)); |
||||
|
} |
||||
|
|
||||
|
[NotNull] |
||||
|
public static string GetName(Type type) |
||||
|
{ |
||||
|
var attribute = type |
||||
|
.GetCustomAttributes<GlobalFeatureNameAttribute>() |
||||
|
.FirstOrDefault(); |
||||
|
|
||||
|
if (attribute == null) |
||||
|
{ |
||||
|
throw new AbpException($"{type.AssemblyQualifiedName} should define the {typeof(GlobalFeatureNameAttribute).FullName} atttribute!"); |
||||
|
} |
||||
|
|
||||
|
return attribute |
||||
|
.As<GlobalFeatureNameAttribute>() |
||||
|
.Name; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public abstract class GlobalModuleFeatures |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public GlobalFeatureManager FeatureManager { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
protected GlobalFeatureDictionary AllFeatures { get; } |
||||
|
|
||||
|
protected GlobalModuleFeatures( |
||||
|
[NotNull] GlobalFeatureManager featureManager) |
||||
|
{ |
||||
|
FeatureManager = Check.NotNull(featureManager, nameof(featureManager)); |
||||
|
AllFeatures = new GlobalFeatureDictionary(); |
||||
|
} |
||||
|
|
||||
|
public virtual void Enable<TFeature>() |
||||
|
where TFeature : GlobalFeature |
||||
|
{ |
||||
|
GetFeature<TFeature>().Enable(); |
||||
|
} |
||||
|
|
||||
|
public virtual void Disable<TFeature>() |
||||
|
where TFeature : GlobalFeature |
||||
|
{ |
||||
|
GetFeature<TFeature>().Disable(); |
||||
|
} |
||||
|
|
||||
|
public virtual void SetEnabled<TFeature>(bool isEnabled) |
||||
|
where TFeature : GlobalFeature |
||||
|
{ |
||||
|
GetFeature<TFeature>().SetEnabled(isEnabled); |
||||
|
} |
||||
|
|
||||
|
public virtual void Enable(string featureName) |
||||
|
{ |
||||
|
GetFeature(featureName).Enable(); |
||||
|
} |
||||
|
|
||||
|
public virtual void Disable(string featureName) |
||||
|
{ |
||||
|
GetFeature(featureName).Disable(); |
||||
|
} |
||||
|
|
||||
|
public virtual void SetEnabled(string featureName, bool isEnabled) |
||||
|
{ |
||||
|
GetFeature(featureName).SetEnabled(isEnabled); |
||||
|
} |
||||
|
|
||||
|
public virtual void EnableAll() |
||||
|
{ |
||||
|
foreach (var feature in AllFeatures.Values) |
||||
|
{ |
||||
|
feature.Enable(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual void DisableAll() |
||||
|
{ |
||||
|
foreach (var feature in AllFeatures.Values) |
||||
|
{ |
||||
|
feature.Disable(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual GlobalFeature GetFeature(string featureName) |
||||
|
{ |
||||
|
var feature = AllFeatures.GetOrDefault(featureName); |
||||
|
if (feature == null) |
||||
|
{ |
||||
|
throw new AbpException($"There is no feature defined by name '{featureName}'."); |
||||
|
} |
||||
|
|
||||
|
return feature; |
||||
|
} |
||||
|
|
||||
|
public virtual TFeature GetFeature<TFeature>() |
||||
|
where TFeature : GlobalFeature |
||||
|
{ |
||||
|
return (TFeature) GetFeature(GlobalFeatureNameAttribute.GetName<TFeature>()); |
||||
|
} |
||||
|
|
||||
|
public virtual IReadOnlyList<GlobalFeature> GetFeatures() |
||||
|
{ |
||||
|
return AllFeatures.Values.ToImmutableList(); |
||||
|
} |
||||
|
|
||||
|
protected void AddFeature(GlobalFeature feature) |
||||
|
{ |
||||
|
AllFeatures[feature.FeatureName] = feature; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalModuleFeaturesDictionary : Dictionary<string, GlobalModuleFeatures> |
||||
|
{ |
||||
|
public GlobalFeatureManager FeatureManager { get; } |
||||
|
|
||||
|
public GlobalModuleFeaturesDictionary( |
||||
|
[NotNull] GlobalFeatureManager featureManager) |
||||
|
{ |
||||
|
FeatureManager = Check.NotNull(featureManager, nameof(featureManager)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.GlobalFeatures\Volo.Abp.GlobalFeatures.csproj" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,23 @@ |
|||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalFeatureManager_Tests |
||||
|
{ |
||||
|
private readonly GlobalFeatureManager _featureManeger; |
||||
|
|
||||
|
public GlobalFeatureManager_Tests() |
||||
|
{ |
||||
|
_featureManeger = new GlobalFeatureManager(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Enable_Feature_By_Name() |
||||
|
{ |
||||
|
_featureManeger.IsEnabled("Feature1").ShouldBeFalse(); |
||||
|
_featureManeger.Enable("Feature1"); |
||||
|
_featureManeger.IsEnabled("Feature1").ShouldBeTrue(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using Volo.Abp.GlobalFeatures; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace Volo.CmsKit |
||||
|
{ |
||||
|
public static class FeatureConfigurer |
||||
|
{ |
||||
|
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); |
||||
|
|
||||
|
public static void Configure() |
||||
|
{ |
||||
|
OneTimeRunner.Run(() => |
||||
|
{ |
||||
|
GlobalFeatureManager.Instance.Modules.CmsKit().EnableAll(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.CmsKit.GlobalFeatures; |
||||
|
|
||||
|
namespace Volo.Abp.GlobalFeatures |
||||
|
{ |
||||
|
public static class GlobalModuleFeaturesDictionaryCmsKitExtensions |
||||
|
{ |
||||
|
public static GlobalCmsKitFeatures CmsKit( |
||||
|
[NotNull] this GlobalModuleFeaturesDictionary modules) |
||||
|
{ |
||||
|
Check.NotNull(modules, nameof(modules)); |
||||
|
|
||||
|
return modules |
||||
|
.GetOrAdd( |
||||
|
GlobalCmsKitFeatures.ModuleName, |
||||
|
_ => new GlobalCmsKitFeatures(modules.FeatureManager) |
||||
|
) |
||||
|
as GlobalCmsKitFeatures; |
||||
|
} |
||||
|
|
||||
|
public static GlobalModuleFeaturesDictionary CmsKit( |
||||
|
[NotNull] this GlobalModuleFeaturesDictionary modules, |
||||
|
[NotNull] Action<GlobalCmsKitFeatures> configureAction) |
||||
|
{ |
||||
|
Check.NotNull(configureAction, nameof(configureAction)); |
||||
|
|
||||
|
configureAction(modules.CmsKit()); |
||||
|
|
||||
|
return modules; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.GlobalFeatures; |
||||
|
|
||||
|
namespace Volo.CmsKit.GlobalFeatures |
||||
|
{ |
||||
|
[GlobalFeatureName(Name)] |
||||
|
public class CommentsFeature : GlobalFeature |
||||
|
{ |
||||
|
public const string Name = "CmsKit.Comments"; |
||||
|
|
||||
|
internal CommentsFeature( |
||||
|
[NotNull] GlobalCmsKitFeatures cmsKit |
||||
|
) : base(cmsKit) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.GlobalFeatures; |
||||
|
|
||||
|
namespace Volo.CmsKit.GlobalFeatures |
||||
|
{ |
||||
|
public class GlobalCmsKitFeatures : GlobalModuleFeatures |
||||
|
{ |
||||
|
public const string ModuleName = "CmsKit"; |
||||
|
|
||||
|
public ReactionsFeature Reactions => GetFeature<ReactionsFeature>(); |
||||
|
|
||||
|
public CommentsFeature Comments => GetFeature<CommentsFeature>(); |
||||
|
|
||||
|
public GlobalCmsKitFeatures([NotNull] GlobalFeatureManager featureManager) |
||||
|
: base(featureManager) |
||||
|
{ |
||||
|
AddFeature(new ReactionsFeature(this)); |
||||
|
AddFeature(new CommentsFeature(this)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.GlobalFeatures; |
||||
|
|
||||
|
namespace Volo.CmsKit.GlobalFeatures |
||||
|
{ |
||||
|
[GlobalFeatureName(Name)] |
||||
|
public class ReactionsFeature : GlobalFeature |
||||
|
{ |
||||
|
public const string Name = "CmsKit.Reactions"; |
||||
|
|
||||
|
internal ReactionsFeature( |
||||
|
[NotNull] GlobalCmsKitFeatures cmsKit |
||||
|
) : base(cmsKit) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,19 +1,10 @@ |
|||||
using Microsoft.EntityFrameworkCore; |
using Volo.Abp.Data; |
||||
using Volo.Abp.Data; |
|
||||
using Volo.Abp.EntityFrameworkCore; |
using Volo.Abp.EntityFrameworkCore; |
||||
using Volo.CmsKit.Comments; |
|
||||
using Volo.CmsKit.Reactions; |
|
||||
using Volo.CmsKit.Users; |
|
||||
|
|
||||
namespace Volo.CmsKit.EntityFrameworkCore |
namespace Volo.CmsKit.EntityFrameworkCore |
||||
{ |
{ |
||||
[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] |
[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] |
||||
public interface ICmsKitDbContext : IEfCoreDbContext |
public interface ICmsKitDbContext : IEfCoreDbContext |
||||
{ |
{ |
||||
DbSet<UserReaction> UserReactions { get; } |
|
||||
|
|
||||
DbSet<Comment> Comments { get; } |
|
||||
|
|
||||
DbSet<CmsUser> CmsUsers { get; set; } |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue