Browse Source

use file-scoped namespacing for featureManagement module

pull/10696/head
Ahmet Çotur 4 years ago
parent
commit
3afa5f1a5c
  1. 43
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs
  2. 23
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureDto.cs
  3. 19
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureGroupDto.cs
  4. 17
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureManagementPermissions.cs
  5. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureManagementRemoteServiceConsts.cs
  6. 33
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeaturePermissionDefinitionProvider.cs
  7. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureProviderDto.cs
  8. 9
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/GetFeatureListResultDto.cs
  9. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/IFeatureAppService.cs
  10. 117
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs
  11. 43
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs
  12. 51
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs
  13. 69
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs
  14. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/UpdateFeatureDto.cs
  15. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/UpdateFeaturesDto.cs
  16. 29
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs
  17. 161
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs
  18. 15
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementAppServiceBase.cs
  19. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementApplicationAutoMapperProfile.cs
  20. 15
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.Server/AbpFeatureManagementBlazorServerModule.cs
  21. 17
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.WebAssembly/AbpFeatureManagementBlazorWebAssemblyModule.cs
  22. 23
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/AbpFeatureManagementBlazorModule.cs
  23. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/AbpFeatureManagementComponentBase.cs
  24. 251
      modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs
  25. 45
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs
  26. 9
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureManagementDomainErrorCodes.cs
  27. 15
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureValueInvalidException.cs
  28. 11
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/AbpFeatureManagementResource.cs
  29. 37
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs
  30. 39
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagementProvider.cs
  31. 35
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagerExtensions.cs
  32. 37
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs
  33. 43
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagerExtensions.cs
  34. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementDbProperties.cs
  35. 21
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementOptions.cs
  36. 69
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs
  37. 169
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs
  38. 315
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs
  39. 23
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValue.cs
  40. 21
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValueWithGrantedProvider.cs
  41. 29
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureStore.cs
  42. 67
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValue.cs
  43. 35
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs
  44. 45
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs
  45. 39
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueConsts.cs
  46. 23
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueProviderInfo.cs
  47. 19
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementProvider.cs
  48. 15
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementStore.cs
  49. 17
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManager.cs
  50. 35
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs
  51. 37
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagementProvider.cs
  52. 43
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagerExtensions.cs
  53. 27
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/AbpFeatureManagementEntityFrameworkCoreModule.cs
  54. 73
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs
  55. 29
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureManagementDbContext.cs
  56. 48
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureManagementDbContextModelCreatingExtensions.cs
  57. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/IFeatureManagementDbContext.cs
  58. 7
      modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/FeaturesClientProxy.cs
  59. 31
      modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiClientModule.cs
  60. 45
      modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs
  61. 41
      modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs
  62. 23
      modules/feature-management/src/Volo.Abp.FeatureManagement.Installer/Volo/Abp/FeatureManagement/AbpFeatureManagementInstallerModule.cs
  63. 29
      modules/feature-management/src/Volo.Abp.FeatureManagement.Installer/Volo/Abp/FeatureManagement/FeatureManagementInstallerPipelineBuilder.cs
  64. 25
      modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/AbpFeatureManagementMongoDbModule.cs
  65. 21
      modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/FeatureManagementMongoDbContext.cs
  66. 23
      modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/FeatureManagementMongoDbContextExtensions.cs
  67. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/IFeatureManagementMongoDbContext.cs
  68. 67
      modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs
  69. 67
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/AbpFeatureManagementWebModule.cs
  70. 13
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/FeatureManagementWebAutoMapperProfile.cs
  71. 115
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs
  72. 27
      modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Properties/launchSettings.json
  73. 95
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs
  74. 9
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureManagementApplicationTestBase.cs
  75. 15
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureManagementApplicationTestModule.cs
  76. 15
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs
  77. 63
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs
  78. 15
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs
  79. 15
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainTestModule.cs
  80. 9
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManagementDomainTestBase.cs
  81. 270
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs
  82. 126
      modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs
  83. 53
      modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo/Abp/FeatureManagement/EntityFrameworkCore/AbpFeatureManagementEntityFrameworkCoreTestModule.cs
  84. 9
      modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureManagementStore_Tests.cs
  85. 7
      modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureValueRepositoryTests.cs
  86. 34
      modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/AbpFeatureManagementMongoDbTestModule.cs
  87. 9
      modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/FeatureManagementStore_Tests.cs
  88. 9
      modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/FeatureValueRepositoryTests.cs
  89. 27
      modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoDbFixture.cs
  90. 13
      modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoTestCollection.cs
  91. 195
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs
  92. 13
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBase.cs
  93. 55
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBaseModule.cs
  94. 9
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestData.cs
  95. 369
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestDataBuilder.cs
  96. 109
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs
  97. 25
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestEditionIds.cs
  98. 93
      modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestFeatureDefinitionProvider.cs

43
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs

@ -8,32 +8,31 @@ using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementDomainSharedModule),
typeof(AbpDddApplicationContractsModule),
typeof(AbpAuthorizationAbstractionsModule),
typeof(AbpJsonModule)
)]
public class AbpFeatureManagementApplicationContractsModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementDomainSharedModule),
typeof(AbpDddApplicationContractsModule),
typeof(AbpAuthorizationAbstractionsModule),
typeof(AbpJsonModule)
)]
public class AbpFeatureManagementApplicationContractsModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureManagementApplicationContractsModule>();
});
options.FileSets.AddEmbedded<AbpFeatureManagementApplicationContractsModule>();
});
Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<NewtonsoftStringValueTypeJsonConverter>();
});
Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<NewtonsoftStringValueTypeJsonConverter>();
});
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter());
});
}
Configure<AbpSystemTextJsonSerializerOptions>(options =>
{
options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter());
});
}
}

23
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureDto.cs

@ -1,23 +1,22 @@
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureDto
{
public class FeatureDto
{
public string Name { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public string DisplayName { get; set; }
public string Value { get; set; }
public string Value { get; set; }
public FeatureProviderDto Provider { get; set; }
public FeatureProviderDto Provider { get; set; }
public string Description { get; set; }
public string Description { get; set; }
public IStringValueType ValueType { get; set; }
public IStringValueType ValueType { get; set; }
public int Depth { get; set; }
public int Depth { get; set; }
public string ParentName { get; set; }
}
public string ParentName { get; set; }
}

19
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureGroupDto.cs

@ -1,18 +1,17 @@
using System.Collections.Generic;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureGroupDto
{
public class FeatureGroupDto
{
public string Name { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public string DisplayName { get; set; }
public List<FeatureDto> Features { get; set; }
public List<FeatureDto> Features { get; set; }
public string GetNormalizedGroupName()
{
return Name.Replace(".", "_");
}
public string GetNormalizedGroupName()
{
return Name.Replace(".", "_");
}
}

17
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureManagementPermissions.cs

@ -1,16 +1,15 @@
using Volo.Abp.Reflection;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementPermissions
{
public class FeatureManagementPermissions
{
public const string GroupName = "FeatureManagement";
public const string GroupName = "FeatureManagement";
public const string ManageHostFeatures = GroupName + ".ManageHostFeatures";
public const string ManageHostFeatures = GroupName + ".ManageHostFeatures";
public static string[] GetAll()
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(FeatureManagementPermissions));
}
public static string[] GetAll()
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(FeatureManagementPermissions));
}
}

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureManagementRemoteServiceConsts.cs

@ -1,9 +1,8 @@
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementRemoteServiceConsts
{
public class FeatureManagementRemoteServiceConsts
{
public const string RemoteServiceName = "AbpFeatureManagement";
public const string RemoteServiceName = "AbpFeatureManagement";
public const string ModuleName = "featureManagement";
}
public const string ModuleName = "featureManagement";
}

33
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeaturePermissionDefinitionProvider.cs

@ -3,26 +3,25 @@ using Volo.Abp.FeatureManagement.Localization;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeaturePermissionDefinitionProvider : PermissionDefinitionProvider
{
public class FeaturePermissionDefinitionProvider : PermissionDefinitionProvider
public override void Define(IPermissionDefinitionContext context)
{
public override void Define(IPermissionDefinitionContext context)
{
var featureManagementGroup = context.AddGroup(
FeatureManagementPermissions.GroupName,
L("Permission:FeatureManagement"),
multiTenancySide: MultiTenancySides.Host);
var featureManagementGroup = context.AddGroup(
FeatureManagementPermissions.GroupName,
L("Permission:FeatureManagement"),
multiTenancySide: MultiTenancySides.Host);
featureManagementGroup.AddPermission(
FeatureManagementPermissions.ManageHostFeatures,
L("Permission:FeatureManagement.ManageHostFeatures"),
multiTenancySide: MultiTenancySides.Host);
}
featureManagementGroup.AddPermission(
FeatureManagementPermissions.ManageHostFeatures,
L("Permission:FeatureManagement.ManageHostFeatures"),
multiTenancySide: MultiTenancySides.Host);
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<AbpFeatureManagementResource>(name);
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<AbpFeatureManagementResource>(name);
}
}

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeatureProviderDto.cs

@ -1,9 +1,8 @@
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureProviderDto
{
public class FeatureProviderDto
{
public string Name { get; set; }
public string Name { get; set; }
public string Key { get; set; }
}
public string Key { get; set; }
}

9
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/GetFeatureListResultDto.cs

@ -1,9 +1,8 @@
using System.Collections.Generic;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class GetFeatureListResultDto
{
public class GetFeatureListResultDto
{
public List<FeatureGroupDto> Groups { get; set; }
}
public List<FeatureGroupDto> Groups { get; set; }
}

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/IFeatureAppService.cs

@ -2,12 +2,11 @@
using JetBrains.Annotations;
using Volo.Abp.Application.Services;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public interface IFeatureAppService : IApplicationService
{
public interface IFeatureAppService : IApplicationService
{
Task<GetFeatureListResultDto> GetAsync([NotNull] string providerName, string providerKey);
Task<GetFeatureListResultDto> GetAsync([NotNull] string providerName, string providerKey);
Task UpdateAsync([NotNull] string providerName, string providerKey, UpdateFeaturesDto input);
}
Task UpdateAsync([NotNull] string providerName, string providerKey, UpdateFeaturesDto input);
}

117
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/NewtonsoftStringValueTypeJsonConverter.cs

@ -7,84 +7,83 @@ using Newtonsoft.Json.Linq;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement.JsonConverters
namespace Volo.Abp.FeatureManagement.JsonConverters;
public class NewtonsoftStringValueTypeJsonConverter : JsonConverter, ITransientDependency
{
public class NewtonsoftStringValueTypeJsonConverter : JsonConverter, ITransientDependency
public override bool CanWrite => false;
public override bool CanConvert(Type objectType)
{
public override bool CanWrite => false;
return objectType == typeof(IStringValueType);
}
public override bool CanConvert(Type objectType)
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("This method should not be called to write (since CanWrite is false).");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartObject)
{
return objectType == typeof(IStringValueType);
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var jsonObject = JObject.Load(reader);
var stringValue = CreateStringValueTypeByName(jsonObject, jsonObject["name"].ToString());
foreach (var o in serializer.Deserialize<Dictionary<string, object>>(
new JsonTextReader(new StringReader(jsonObject["properties"].ToString()))))
{
throw new NotImplementedException("This method should not be called to write (since CanWrite is false).");
stringValue[o.Key] = o.Value;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
stringValue.Validator = CreateValueValidatorByName(jsonObject["validator"], jsonObject["validator"]["name"].ToString());
foreach (var o in serializer.Deserialize<Dictionary<string, object>>(
new JsonTextReader(new StringReader(jsonObject["validator"]["properties"].ToString()))))
{
if (reader.TokenType != JsonToken.StartObject)
{
return null;
}
var jsonObject = JObject.Load(reader);
stringValue.Validator[o.Key] = o.Value;
}
var stringValue = CreateStringValueTypeByName(jsonObject, jsonObject["name"].ToString());
foreach (var o in serializer.Deserialize<Dictionary<string, object>>(
new JsonTextReader(new StringReader(jsonObject["properties"].ToString()))))
{
stringValue[o.Key] = o.Value;
}
return stringValue;
}
stringValue.Validator = CreateValueValidatorByName(jsonObject["validator"], jsonObject["validator"]["name"].ToString());
foreach (var o in serializer.Deserialize<Dictionary<string, object>>(
new JsonTextReader(new StringReader(jsonObject["validator"]["properties"].ToString()))))
protected virtual IStringValueType CreateStringValueTypeByName(JObject jObject, string name)
{
if (name == "SelectionStringValueType")
{
var selectionStringValueType = new SelectionStringValueType();
if (jObject["itemSource"].HasValues)
{
stringValue.Validator[o.Key] = o.Value;
selectionStringValueType.ItemSource = new StaticSelectionStringValueItemSource(jObject["itemSource"]["items"]
.Select(item => new LocalizableSelectionStringValueItem()
{
Value = item["value"].ToString(),
DisplayText = new LocalizableStringInfo(item["displayText"]["resourceName"].ToString(), item["displayText"]["name"].ToString())
}).ToArray());
}
return stringValue;
return selectionStringValueType;
}
protected virtual IStringValueType CreateStringValueTypeByName(JObject jObject, string name)
return name switch
{
if (name == "SelectionStringValueType")
{
var selectionStringValueType = new SelectionStringValueType();
if (jObject["itemSource"].HasValues)
{
selectionStringValueType.ItemSource = new StaticSelectionStringValueItemSource(jObject["itemSource"]["items"]
.Select(item => new LocalizableSelectionStringValueItem()
{
Value = item["value"].ToString(),
DisplayText = new LocalizableStringInfo(item["displayText"]["resourceName"].ToString(), item["displayText"]["name"].ToString())
}).ToArray());
}
return selectionStringValueType;
}
return name switch
{
"FreeTextStringValueType" => new FreeTextStringValueType(),
"ToggleStringValueType" => new ToggleStringValueType(),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
}
"FreeTextStringValueType" => new FreeTextStringValueType(),
"ToggleStringValueType" => new ToggleStringValueType(),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
}
protected virtual IValueValidator CreateValueValidatorByName(JToken jObject, string name)
protected virtual IValueValidator CreateValueValidatorByName(JToken jObject, string name)
{
return name switch
{
return name switch
{
"NULL" => new AlwaysValidValueValidator(),
"BOOLEAN" => new BooleanValueValidator(),
"NUMERIC" => new NumericValueValidator(),
"STRING" => new StringValueValidator(),
_ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!")
};
}
"NULL" => new AlwaysValidValueValidator(),
"BOOLEAN" => new BooleanValueValidator(),
"NUMERIC" => new NumericValueValidator(),
"STRING" => new StringValueValidator(),
_ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!")
};
}
}

43
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/SelectionStringValueItemSourceJsonConverter.cs

@ -4,34 +4,33 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement.JsonConverters
namespace Volo.Abp.FeatureManagement.JsonConverters;
public class SelectionStringValueItemSourceJsonConverter : JsonConverter<ISelectionStringValueItemSource>
{
public class SelectionStringValueItemSourceJsonConverter : JsonConverter<ISelectionStringValueItemSource>
public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
public override ISelectionStringValueItemSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var itemsJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x =>
x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase));
if (itemsJsonProperty.Value.ValueKind == JsonValueKind.Array)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var itemsJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x =>
x.Name.Equals(nameof(ISelectionStringValueItemSource.Items), StringComparison.OrdinalIgnoreCase));
var selectionStringValueItem =
JsonSerializer.Deserialize<LocalizableSelectionStringValueItem[]>(itemsJsonProperty.Value.GetRawText(), newOptions) ??
Array.Empty<LocalizableSelectionStringValueItem>();
if (itemsJsonProperty.Value.ValueKind == JsonValueKind.Array)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
return new StaticSelectionStringValueItemSource(selectionStringValueItem.As<ISelectionStringValueItem[]>());
}
var selectionStringValueItem =
JsonSerializer.Deserialize<LocalizableSelectionStringValueItem[]>(itemsJsonProperty.Value.GetRawText(), newOptions) ??
Array.Empty<LocalizableSelectionStringValueItem>();
throw new JsonException($"Can't to get the {nameof(ISelectionStringValueItemSource.Items)} property of {nameof(ISelectionStringValueItemSource)}!");
return new StaticSelectionStringValueItemSource(selectionStringValueItem.As<ISelectionStringValueItem[]>());
}
public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, value, value.GetType(), newOptions);
}
throw new JsonException($"Can't to get the {nameof(ISelectionStringValueItemSource.Items)} property of {nameof(ISelectionStringValueItemSource)}!");
}
public override void Write(Utf8JsonWriter writer, ISelectionStringValueItemSource value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, value, value.GetType(), newOptions);
}
}

51
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/StringValueTypeJsonConverter.cs

@ -4,38 +4,37 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement.JsonConverters
namespace Volo.Abp.FeatureManagement.JsonConverters;
public class StringValueTypeJsonConverter : JsonConverter<IStringValueType>
{
public class StringValueTypeJsonConverter : JsonConverter<IStringValueType>
public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
public override IStringValueType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase));
if (nameJsonProperty.Value.ValueKind == JsonValueKind.String)
{
var name = nameJsonProperty.Value.GetString();
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(),
new SelectionStringValueItemSourceJsonConverter());
var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IStringValueType.Name), StringComparison.OrdinalIgnoreCase));
if (nameJsonProperty.Value.ValueKind == JsonValueKind.String)
{
var name = nameJsonProperty.Value.GetString();
return name switch
{
"SelectionStringValueType" => JsonSerializer.Deserialize<SelectionStringValueType>(rootElement.GetRawText(), newOptions),
"FreeTextStringValueType" => JsonSerializer.Deserialize<FreeTextStringValueType>(rootElement.GetRawText(), newOptions),
"ToggleStringValueType" => JsonSerializer.Deserialize<ToggleStringValueType>(rootElement.GetRawText(), newOptions),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
}
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ValueValidatorJsonConverter(),
new SelectionStringValueItemSourceJsonConverter());
throw new JsonException($"Can't to get the {nameof(IStringValueType.Name)} property of {nameof(IStringValueType)}!");
return name switch
{
"SelectionStringValueType" => JsonSerializer.Deserialize<SelectionStringValueType>(rootElement.GetRawText(), newOptions),
"FreeTextStringValueType" => JsonSerializer.Deserialize<FreeTextStringValueType>(rootElement.GetRawText(), newOptions),
"ToggleStringValueType" => JsonSerializer.Deserialize<ToggleStringValueType>(rootElement.GetRawText(), newOptions),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
}
public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, value, value.GetType(), newOptions);
}
throw new JsonException($"Can't to get the {nameof(IStringValueType.Name)} property of {nameof(IStringValueType)}!");
}
public override void Write(Utf8JsonWriter writer, IStringValueType value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, value, value.GetType(), newOptions);
}
}

69
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/JsonConverters/ValueValidatorJsonConverter.cs

@ -6,55 +6,54 @@ using System.Text.Json.Serialization;
using Volo.Abp.Json.SystemTextJson.JsonConverters;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement.JsonConverters
namespace Volo.Abp.FeatureManagement.JsonConverters;
public class ValueValidatorJsonConverter : JsonConverter<IValueValidator>
{
public class ValueValidatorJsonConverter : JsonConverter<IValueValidator>
public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
public override IValueValidator Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase));
if (nameJsonProperty.Value.ValueKind == JsonValueKind.String)
{
var rootElement = JsonDocument.ParseValue(ref reader).RootElement;
var valueValidator = CreateValueValidatorByName(nameJsonProperty.Value.GetString());
var nameJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Name), StringComparison.OrdinalIgnoreCase));
if (nameJsonProperty.Value.ValueKind == JsonValueKind.String)
var propertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase));
if (propertiesJsonProperty.Value.ValueKind == JsonValueKind.Object)
{
var valueValidator = CreateValueValidatorByName(nameJsonProperty.Value.GetString());
var propertiesJsonProperty = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals(nameof(IValueValidator.Properties), StringComparison.OrdinalIgnoreCase));
if (propertiesJsonProperty.Value.ValueKind == JsonValueKind.Object)
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter());
var properties = JsonSerializer.Deserialize<IDictionary<string, object>>(propertiesJsonProperty.Value.GetRawText(), newOptions);
if (properties != null && properties.Any())
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this, new ObjectToInferredTypesConverter());
var properties = JsonSerializer.Deserialize<IDictionary<string, object>>(propertiesJsonProperty.Value.GetRawText(), newOptions);
if (properties != null && properties.Any())
foreach (var property in properties)
{
foreach (var property in properties)
{
valueValidator.Properties[property.Key] = property.Value;
}
valueValidator.Properties[property.Key] = property.Value;
}
}
return valueValidator;
}
throw new JsonException($"Can't to get the {nameof(IValueValidator.Name)} property of {nameof(IValueValidator)}!");
return valueValidator;
}
public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, value, value.GetType(), newOptions);
}
throw new JsonException($"Can't to get the {nameof(IValueValidator.Name)} property of {nameof(IValueValidator)}!");
}
protected virtual IValueValidator CreateValueValidatorByName(string name)
public override void Write(Utf8JsonWriter writer, IValueValidator value, JsonSerializerOptions options)
{
var newOptions = JsonSerializerOptionsHelper.Create(options, this);
JsonSerializer.Serialize(writer, value, value.GetType(), newOptions);
}
protected virtual IValueValidator CreateValueValidatorByName(string name)
{
return name switch
{
return name switch
{
"NULL" => new AlwaysValidValueValidator(),
"BOOLEAN" => new BooleanValueValidator(),
"NUMERIC" => new NumericValueValidator(),
"STRING" => new StringValueValidator(),
_ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!")
};
}
"NULL" => new AlwaysValidValueValidator(),
"BOOLEAN" => new BooleanValueValidator(),
"NUMERIC" => new NumericValueValidator(),
"STRING" => new StringValueValidator(),
_ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!")
};
}
}

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/UpdateFeatureDto.cs

@ -1,9 +1,8 @@
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class UpdateFeatureDto
{
public class UpdateFeatureDto
{
public string Name { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
public string Value { get; set; }
}

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/UpdateFeaturesDto.cs

@ -1,9 +1,8 @@
using System.Collections.Generic;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class UpdateFeaturesDto
{
public class UpdateFeaturesDto
{
public List<UpdateFeatureDto> Features { get; set; }
}
}
public List<UpdateFeatureDto> Features { get; set; }
}

29
modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs

@ -3,23 +3,22 @@ using Volo.Abp.Application;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementDomainModule),
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpAutoMapperModule),
typeof(AbpDddApplicationModule)
)]
public class AbpFeatureManagementApplicationModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementDomainModule),
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpAutoMapperModule),
typeof(AbpDddApplicationModule)
)]
public class AbpFeatureManagementApplicationModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
context.Services.AddAutoMapperObjectMapper<AbpFeatureManagementApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
context.Services.AddAutoMapperObjectMapper<AbpFeatureManagementApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<FeatureManagementApplicationAutoMapperProfile>(validate: true);
});
}
options.AddProfile<FeatureManagementApplicationAutoMapperProfile>(validate: true);
});
}
}

161
modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs

@ -1,124 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Authorize]
public class FeatureAppService : FeatureManagementAppServiceBase, IFeatureAppService
{
[Authorize]
public class FeatureAppService : FeatureManagementAppServiceBase, IFeatureAppService
protected FeatureManagementOptions Options { get; }
protected IFeatureManager FeatureManager { get; }
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
public FeatureAppService(IFeatureManager featureManager,
IFeatureDefinitionManager featureDefinitionManager,
IOptions<FeatureManagementOptions> options)
{
protected FeatureManagementOptions Options { get; }
protected IFeatureManager FeatureManager { get; }
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
FeatureManager = featureManager;
FeatureDefinitionManager = featureDefinitionManager;
Options = options.Value;
}
public FeatureAppService(IFeatureManager featureManager,
IFeatureDefinitionManager featureDefinitionManager,
IOptions<FeatureManagementOptions> options)
{
FeatureManager = featureManager;
FeatureDefinitionManager = featureDefinitionManager;
Options = options.Value;
}
public virtual async Task<GetFeatureListResultDto> GetAsync([NotNull] string providerName, string providerKey)
{
await CheckProviderPolicy(providerName, providerKey);
public virtual async Task<GetFeatureListResultDto> GetAsync([NotNull] string providerName, string providerKey)
var result = new GetFeatureListResultDto
{
await CheckProviderPolicy(providerName, providerKey);
Groups = new List<FeatureGroupDto>()
};
var result = new GetFeatureListResultDto
foreach (var group in FeatureDefinitionManager.GetGroups())
{
var groupDto = new FeatureGroupDto
{
Groups = new List<FeatureGroupDto>()
Name = group.Name,
DisplayName = group.DisplayName.Localize(StringLocalizerFactory),
Features = new List<FeatureDto>()
};
foreach (var group in FeatureDefinitionManager.GetGroups())
foreach (var featureDefinition in group.GetFeaturesWithChildren())
{
var groupDto = new FeatureGroupDto
if (providerName == TenantFeatureValueProvider.ProviderName &&
CurrentTenant.Id == null &&
providerKey == null &&
!featureDefinition.IsAvailableToHost)
{
Name = group.Name,
DisplayName = group.DisplayName.Localize(StringLocalizerFactory),
Features = new List<FeatureDto>()
};
continue;
}
foreach (var featureDefinition in group.GetFeaturesWithChildren())
var feature = await FeatureManager.GetOrNullWithProviderAsync(featureDefinition.Name, providerName, providerKey);
groupDto.Features.Add(new FeatureDto
{
if (providerName == TenantFeatureValueProvider.ProviderName &&
CurrentTenant.Id == null &&
providerKey == null &&
!featureDefinition.IsAvailableToHost)
Name = featureDefinition.Name,
DisplayName = featureDefinition.DisplayName?.Localize(StringLocalizerFactory),
ValueType = featureDefinition.ValueType,
Description = featureDefinition.Description?.Localize(StringLocalizerFactory),
ParentName = featureDefinition.Parent?.Name,
Value = feature.Value,
Provider = new FeatureProviderDto
{
continue;
Name = feature.Provider?.Name,
Key = feature.Provider?.Key
}
});
}
var feature = await FeatureManager.GetOrNullWithProviderAsync(featureDefinition.Name, providerName, providerKey);
groupDto.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 = feature.Value,
Provider = new FeatureProviderDto
{
Name = feature.Provider?.Name,
Key = feature.Provider?.Key
}
});
}
SetFeatureDepth(groupDto.Features, providerName, providerKey);
SetFeatureDepth(groupDto.Features, providerName, providerKey);
result.Groups.Add(groupDto);
}
result.Groups.Add(groupDto);
}
return result;
}
return result;
}
public virtual async Task UpdateAsync([NotNull] string providerName, string providerKey, UpdateFeaturesDto input)
{
await CheckProviderPolicy(providerName, providerKey);
public virtual async Task UpdateAsync([NotNull] string providerName, string providerKey, UpdateFeaturesDto input)
foreach (var feature in input.Features)
{
await CheckProviderPolicy(providerName, providerKey);
foreach (var feature in input.Features)
{
await FeatureManager.SetAsync(feature.Name, feature.Value, providerName, providerKey);
}
await FeatureManager.SetAsync(feature.Name, feature.Value, providerName, providerKey);
}
}
protected virtual void SetFeatureDepth(List<FeatureDto> features, string providerName, string providerKey,
FeatureDto parentFeature = null, int depth = 0)
protected virtual void SetFeatureDepth(List<FeatureDto> features, string providerName, string providerKey,
FeatureDto parentFeature = null, int depth = 0)
{
foreach (var feature in features)
{
foreach (var feature in features)
if ((parentFeature == null && feature.ParentName == null) || (parentFeature != null && parentFeature.Name == feature.ParentName))
{
if ((parentFeature == null && feature.ParentName == null) || (parentFeature != null && parentFeature.Name == feature.ParentName))
{
feature.Depth = depth;
SetFeatureDepth(features, providerName, providerKey, feature, depth + 1);
}
feature.Depth = depth;
SetFeatureDepth(features, providerName, providerKey, feature, depth + 1);
}
}
}
protected virtual async Task CheckProviderPolicy(string providerName, string providerKey)
protected virtual async Task CheckProviderPolicy(string providerName, string providerKey)
{
string policyName;
if (providerName == TenantFeatureValueProvider.ProviderName && CurrentTenant.Id == null && providerKey == null)
{
string policyName;
if (providerName == TenantFeatureValueProvider.ProviderName && CurrentTenant.Id == null && providerKey == null )
{
policyName = "FeatureManagement.ManageHostFeatures";
}
else
policyName = "FeatureManagement.ManageHostFeatures";
}
else
{
policyName = Options.ProviderPolicies.GetOrDefault(providerName);
if (policyName.IsNullOrEmpty())
{
policyName = Options.ProviderPolicies.GetOrDefault(providerName);
if (policyName.IsNullOrEmpty())
{
throw new AbpException($"No policy defined to get/set permissions for the provider '{providerName}'. Use {nameof(FeatureManagementOptions)} to map the policy.");
}
throw new AbpException($"No policy defined to get/set permissions for the provider '{providerName}'. Use {nameof(FeatureManagementOptions)} to map the policy.");
}
await AuthorizationService.CheckAsync(policyName);
}
await AuthorizationService.CheckAsync(policyName);
}
}

15
modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementAppServiceBase.cs

@ -1,14 +1,13 @@
using Volo.Abp.Application.Services;
using Volo.Abp.FeatureManagement.Localization;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class FeatureManagementAppServiceBase : ApplicationService
{
public abstract class FeatureManagementAppServiceBase : ApplicationService
protected FeatureManagementAppServiceBase()
{
protected FeatureManagementAppServiceBase()
{
ObjectMapperContext = typeof(AbpFeatureManagementApplicationModule);
LocalizationResource = typeof(AbpFeatureManagementResource);
}
ObjectMapperContext = typeof(AbpFeatureManagementApplicationModule);
LocalizationResource = typeof(AbpFeatureManagementResource);
}
}
}

13
modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementApplicationAutoMapperProfile.cs

@ -1,12 +1,11 @@
using AutoMapper;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementApplicationAutoMapperProfile : Profile
{
public class FeatureManagementApplicationAutoMapperProfile : Profile
public FeatureManagementApplicationAutoMapperProfile()
{
public FeatureManagementApplicationAutoMapperProfile()
{
}
}
}
}

15
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.Server/AbpFeatureManagementBlazorServerModule.cs

@ -1,14 +1,13 @@
using Volo.Abp.AspNetCore.Components.Server.Theming;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement.Blazor.Server
namespace Volo.Abp.FeatureManagement.Blazor.Server;
[DependsOn(
typeof(AbpFeatureManagementBlazorModule),
typeof(AbpAspNetCoreComponentsServerThemingModule)
)]
public class AbpFeatureManagementBlazorServerModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementBlazorModule),
typeof(AbpAspNetCoreComponentsServerThemingModule)
)]
public class AbpFeatureManagementBlazorServerModule : AbpModule
{
}
}

17
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.WebAssembly/AbpFeatureManagementBlazorWebAssemblyModule.cs

@ -1,14 +1,13 @@
using Volo.Abp.AspNetCore.Components.WebAssembly.Theming;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement.Blazor.WebAssembly
namespace Volo.Abp.FeatureManagement.Blazor.WebAssembly;
[DependsOn(
typeof(AbpFeatureManagementBlazorModule),
typeof(AbpAspNetCoreComponentsWebAssemblyThemingModule),
typeof(AbpFeatureManagementHttpApiClientModule)
)]
public class AbpFeatureManagementBlazorWebAssemblyModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementBlazorModule),
typeof(AbpAspNetCoreComponentsWebAssemblyThemingModule),
typeof(AbpFeatureManagementHttpApiClientModule)
)]
public class AbpFeatureManagementBlazorWebAssemblyModule : AbpModule
{
}
}

23
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/AbpFeatureManagementBlazorModule.cs

@ -3,16 +3,15 @@ using Volo.Abp.AutoMapper;
using Volo.Abp.Features;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement.Blazor
namespace Volo.Abp.FeatureManagement.Blazor;
[DependsOn(
typeof(AbpAspNetCoreComponentsWebThemingModule),
typeof(AbpAutoMapperModule),
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpFeaturesModule)
)]
public class AbpFeatureManagementBlazorModule : AbpModule
{
[DependsOn(
typeof(AbpAspNetCoreComponentsWebThemingModule),
typeof(AbpAutoMapperModule),
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpFeaturesModule)
)]
public class AbpFeatureManagementBlazorModule : AbpModule
{
}
}
}

13
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/AbpFeatureManagementComponentBase.cs

@ -1,13 +1,12 @@
using Volo.Abp.AspNetCore.Components;
using Volo.Abp.FeatureManagement.Localization;
namespace Volo.Abp.FeatureManagement.Blazor
namespace Volo.Abp.FeatureManagement.Blazor;
public abstract class AbpFeatureManagementComponentBase : AbpComponentBase
{
public abstract class AbpFeatureManagementComponentBase : AbpComponentBase
protected AbpFeatureManagementComponentBase()
{
protected AbpFeatureManagementComponentBase()
{
LocalizationResource = typeof(AbpFeatureManagementResource);
}
LocalizationResource = typeof(AbpFeatureManagementResource);
}
}
}

251
modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs

@ -13,196 +13,195 @@ using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement.Blazor.Components
namespace Volo.Abp.FeatureManagement.Blazor.Components;
public partial class FeatureManagementModal
{
public partial class FeatureManagementModal
{
[Inject] protected IFeatureAppService FeatureAppService { get; set; }
[Inject] protected IFeatureAppService FeatureAppService { get; set; }
[Inject] protected IUiMessageService UiMessageService { get; set; }
[Inject] protected IUiMessageService UiMessageService { get; set; }
[Inject] protected IStringLocalizerFactory HtmlLocalizerFactory { get; set; }
[Inject] protected IStringLocalizerFactory HtmlLocalizerFactory { get; set; }
[Inject] protected IOptions<AbpLocalizationOptions> LocalizationOptions { get; set; }
[Inject] protected IOptions<AbpLocalizationOptions> LocalizationOptions { get; set; }
[Inject] private ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; }
[Inject] private ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; }
protected Modal Modal;
protected Modal Modal;
protected string ProviderName;
protected string ProviderKey;
protected string ProviderName;
protected string ProviderKey;
protected string SelectedTabName;
protected string SelectedTabName;
protected List<FeatureGroupDto> Groups { get; set; }
protected List<FeatureGroupDto> Groups { get; set; }
protected Dictionary<string, bool> ToggleValues;
protected Dictionary<string, bool> ToggleValues;
protected Dictionary<string, string> SelectionStringValues;
protected Dictionary<string, string> SelectionStringValues;
public virtual async Task OpenAsync([NotNull]string providerName, string providerKey = null)
public virtual async Task OpenAsync([NotNull] string providerName, string providerKey = null)
{
try
{
try
{
ProviderName = providerName;
ProviderKey = providerKey;
ProviderName = providerName;
ProviderKey = providerKey;
ToggleValues = new Dictionary<string, bool>();
SelectionStringValues = new Dictionary<string, string>();
ToggleValues = new Dictionary<string, bool>();
SelectionStringValues = new Dictionary<string, string>();
Groups = (await FeatureAppService.GetAsync(ProviderName, ProviderKey))?.Groups;
Groups = (await FeatureAppService.GetAsync(ProviderName, ProviderKey))?.Groups;
Groups ??= new List<FeatureGroupDto>();
Groups ??= new List<FeatureGroupDto>();
if (Groups.Any())
{
SelectedTabName = GetNormalizedGroupName(Groups.First().Name);
}
if (Groups.Any())
{
SelectedTabName = GetNormalizedGroupName(Groups.First().Name);
}
foreach (var featureGroupDto in Groups)
foreach (var featureGroupDto in Groups)
{
foreach (var featureDto in featureGroupDto.Features)
{
foreach (var featureDto in featureGroupDto.Features)
if (featureDto.ValueType is ToggleStringValueType)
{
if (featureDto.ValueType is ToggleStringValueType)
{
ToggleValues.Add(featureDto.Name, bool.Parse(featureDto.Value));
}
if (featureDto.ValueType is SelectionStringValueType)
{
SelectionStringValues.Add(featureDto.Name, featureDto.Value);
}
ToggleValues.Add(featureDto.Name, bool.Parse(featureDto.Value));
}
}
await InvokeAsync(Modal.Show);
}
catch (Exception ex)
{
await HandleErrorAsync(ex);
if (featureDto.ValueType is SelectionStringValueType)
{
SelectionStringValues.Add(featureDto.Name, featureDto.Value);
}
}
}
}
public virtual Task CloseModal()
await InvokeAsync(Modal.Show);
}
catch (Exception ex)
{
return InvokeAsync(Modal.Hide);
await HandleErrorAsync(ex);
}
}
protected virtual async Task SaveAsync()
public virtual Task CloseModal()
{
return InvokeAsync(Modal.Hide);
}
protected virtual async Task SaveAsync()
{
try
{
try
var features = new UpdateFeaturesDto
{
var features = new UpdateFeaturesDto
Features = Groups.SelectMany(g => g.Features).Select(f => new UpdateFeatureDto
{
Features = Groups.SelectMany(g => g.Features).Select(f => new UpdateFeatureDto
{
Name = f.Name,
Value = f.ValueType is ToggleStringValueType ? ToggleValues[f.Name].ToString() :
f.ValueType is SelectionStringValueType ? SelectionStringValues[f.Name] : f.Value
}).ToList()
};
Name = f.Name,
Value = f.ValueType is ToggleStringValueType ? ToggleValues[f.Name].ToString() :
f.ValueType is SelectionStringValueType ? SelectionStringValues[f.Name] : f.Value
}).ToList()
};
await FeatureAppService.UpdateAsync(ProviderName, ProviderKey, features);
await FeatureAppService.UpdateAsync(ProviderName, ProviderKey, features);
await CurrentApplicationConfigurationCacheResetService.ResetAsync();
await CurrentApplicationConfigurationCacheResetService.ResetAsync();
await InvokeAsync(Modal.Hide);
}
catch (Exception ex)
{
await HandleErrorAsync(ex);
}
await InvokeAsync(Modal.Hide);
}
protected virtual string GetNormalizedGroupName(string name)
catch (Exception ex)
{
return "FeatureGroup_" + name.Replace(".", "_");
await HandleErrorAsync(ex);
}
}
protected virtual string GetNormalizedGroupName(string name)
{
return "FeatureGroup_" + name.Replace(".", "_");
}
protected virtual string GetFeatureStyles(FeatureDto feature)
{
return $"margin-left: {feature.Depth * 20}px";
}
protected virtual bool IsDisabled(string providerName)
{
return providerName != ProviderName && providerName != DefaultValueFeatureValueProvider.ProviderName;
}
protected virtual string GetFeatureStyles(FeatureDto feature)
protected virtual async Task OnFeatureValueChangedAsync(string value, FeatureDto feature)
{
if (feature?.ValueType?.Validator.IsValid(value) == true)
{
return $"margin-left: {feature.Depth * 20}px";
feature.Value = value;
}
protected virtual bool IsDisabled(string providerName)
else
{
return providerName != ProviderName && providerName != DefaultValueFeatureValueProvider.ProviderName;
await UiMessageService.Warn(L["Volo.Abp.FeatureManagement:InvalidFeatureValue", feature.DisplayName]);
}
}
protected virtual Task OnSelectedValueChangedAsync(bool value, FeatureDto feature)
{
ToggleValues[feature.Name] = value;
protected virtual async Task OnFeatureValueChangedAsync(string value, FeatureDto feature)
if (value)
{
if (feature?.ValueType?.Validator.IsValid(value) == true)
{
feature.Value = value;
}
else
{
await UiMessageService.Warn(L["Volo.Abp.FeatureManagement:InvalidFeatureValue", feature.DisplayName]);
}
CheckParents(feature.ParentName);
}
protected virtual Task OnSelectedValueChangedAsync(bool value, FeatureDto feature)
else
{
ToggleValues[feature.Name] = value;
UncheckChildren(feature.Name);
}
if (value)
{
CheckParents(feature.ParentName);
}
else
{
UncheckChildren(feature.Name);
}
return Task.CompletedTask;
}
return Task.CompletedTask;
protected virtual void CheckParents(string parentName)
{
if (parentName.IsNullOrWhiteSpace())
{
return;
}
protected virtual void CheckParents(string parentName)
foreach (var featureGroupDto in Groups)
{
if (parentName.IsNullOrWhiteSpace())
foreach (var featureDto in featureGroupDto.Features)
{
return;
}
foreach (var featureGroupDto in Groups)
{
foreach (var featureDto in featureGroupDto.Features)
if (featureDto.Name == parentName && ToggleValues.ContainsKey(featureDto.Name))
{
if (featureDto.Name == parentName && ToggleValues.ContainsKey(featureDto.Name))
{
ToggleValues[featureDto.Name] = true;
CheckParents(featureDto.ParentName);
}
ToggleValues[featureDto.Name] = true;
CheckParents(featureDto.ParentName);
}
}
}
}
protected virtual void UncheckChildren(string featureName)
protected virtual void UncheckChildren(string featureName)
{
foreach (var featureGroupDto in Groups)
{
foreach (var featureGroupDto in Groups)
foreach (var featureDto in featureGroupDto.Features)
{
foreach (var featureDto in featureGroupDto.Features)
if (featureDto.ParentName == featureName && ToggleValues.ContainsKey(featureDto.Name))
{
if (featureDto.ParentName == featureName && ToggleValues.ContainsKey(featureDto.Name))
{
ToggleValues[featureDto.Name] = false;
UncheckChildren(featureDto.Name);
}
ToggleValues[featureDto.Name] = false;
UncheckChildren(featureDto.Name);
}
}
}
}
protected virtual IStringLocalizer CreateStringLocalizer(string resourceName)
{
var resource = LocalizationOptions.Value.Resources.Values.FirstOrDefault(x => x.ResourceName == resourceName);
return HtmlLocalizerFactory.Create(resource != null ? resource.ResourceType : LocalizationOptions.Value.DefaultResourceType);
}
protected virtual IStringLocalizer CreateStringLocalizer(string resourceName)
{
var resource = LocalizationOptions.Value.Resources.Values.FirstOrDefault(x => x.ResourceName == resourceName);
return HtmlLocalizerFactory.Create(resource != null ? resource.ResourceType : LocalizationOptions.Value.DefaultResourceType);
}
protected virtual Task ClosingModal(ModalClosingEventArgs eventArgs)
{
eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing;
protected virtual Task ClosingModal(ModalClosingEventArgs eventArgs)
{
eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing;
return Task.CompletedTask;
}
return Task.CompletedTask;
}
}

45
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs

@ -6,33 +6,32 @@ using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpValidationModule)
)]
public class AbpFeatureManagementDomainSharedModule : AbpModule
{
[DependsOn(
typeof(AbpValidationModule)
)]
public class AbpFeatureManagementDomainSharedModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureManagementDomainSharedModule>();
});
options.FileSets.AddEmbedded<AbpFeatureManagementDomainSharedModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpFeatureManagementResource>("en")
.AddBaseTypes(
typeof(AbpValidationResource)
).AddVirtualJson("Volo/Abp/FeatureManagement/Localization/Domain");
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpFeatureManagementResource>("en")
.AddBaseTypes(
typeof(AbpValidationResource)
).AddVirtualJson("Volo/Abp/FeatureManagement/Localization/Domain");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Abp.FeatureManagement", typeof(AbpFeatureManagementResource));
});
}
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Abp.FeatureManagement", typeof(AbpFeatureManagementResource));
});
}
}

9
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureManagementDomainErrorCodes.cs

@ -1,9 +1,6 @@
using System;
namespace Volo.Abp.FeatureManagement;
namespace Volo.Abp.FeatureManagement
public static class FeatureManagementDomainErrorCodes
{
public static class FeatureManagementDomainErrorCodes
{
public const string FeatureValueInvalid = "Volo.Abp.FeatureManagement:InvalidFeatureValue";
}
public const string FeatureValueInvalid = "Volo.Abp.FeatureManagement:InvalidFeatureValue";
}

15
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureValueInvalidException.cs

@ -1,14 +1,13 @@
using System;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Serializable]
public class FeatureValueInvalidException : BusinessException
{
[Serializable]
public class FeatureValueInvalidException : BusinessException
public FeatureValueInvalidException(string name) :
base(FeatureManagementDomainErrorCodes.FeatureValueInvalid)
{
public FeatureValueInvalidException(string name) :
base(FeatureManagementDomainErrorCodes.FeatureValueInvalid)
{
WithData("0", name);
}
WithData("0", name);
}
}

11
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/AbpFeatureManagementResource.cs

@ -1,10 +1,9 @@
using Volo.Abp.Localization;
namespace Volo.Abp.FeatureManagement.Localization
namespace Volo.Abp.FeatureManagement.Localization;
[LocalizationResourceName("AbpFeatureManagement")]
public class AbpFeatureManagementResource
{
[LocalizationResourceName("AbpFeatureManagement")]
public class AbpFeatureManagementResource
{
}
}

37
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs

@ -4,31 +4,30 @@ using Volo.Abp.Features;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementDomainSharedModule),
typeof(AbpFeaturesModule),
typeof(AbpCachingModule)
)]
public class AbpFeatureManagementDomainModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementDomainSharedModule),
typeof(AbpFeaturesModule),
typeof(AbpCachingModule)
)]
public class AbpFeatureManagementDomainModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
Configure<FeatureManagementOptions>(options =>
{
Configure<FeatureManagementOptions>(options =>
{
options.Providers.Add<DefaultValueFeatureManagementProvider>();
options.Providers.Add<EditionFeatureManagementProvider>();
options.Providers.Add<DefaultValueFeatureManagementProvider>();
options.Providers.Add<EditionFeatureManagementProvider>();
//TODO: Should be moved to the Tenant Management module
options.Providers.Add<TenantFeatureManagementProvider>();
options.ProviderPolicies[TenantFeatureValueProvider.ProviderName] = "AbpTenantManagement.Tenants.ManageFeatures";
});
options.ProviderPolicies[TenantFeatureValueProvider.ProviderName] = "AbpTenantManagement.Tenants.ManageFeatures";
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("AbpFeatureManagement", typeof(AbpFeatureManagementResource));
});
}
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("AbpFeatureManagement", typeof(AbpFeatureManagementResource));
});
}
}

39
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagementProvider.cs

@ -2,30 +2,29 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class DefaultValueFeatureManagementProvider : IFeatureManagementProvider, ISingletonDependency
{
public class DefaultValueFeatureManagementProvider : IFeatureManagementProvider, ISingletonDependency
{
public string Name => DefaultValueFeatureValueProvider.ProviderName;
public string Name => DefaultValueFeatureValueProvider.ProviderName;
public bool Compatible(string providerName)
{
return providerName == Name;
}
public bool Compatible(string providerName)
{
return providerName == Name;
}
public virtual Task<string> GetOrNullAsync(FeatureDefinition feature, string providerKey)
{
return Task.FromResult(feature.DefaultValue);
}
public virtual Task<string> GetOrNullAsync(FeatureDefinition feature, string providerKey)
{
return Task.FromResult(feature.DefaultValue);
}
public virtual Task SetAsync(FeatureDefinition feature, string value, string providerKey)
{
throw new AbpException($"Can not set default value of a feature. It is only possible while defining the feature in a {typeof(IFeatureDefinitionProvider)} implementation.");
}
public virtual Task SetAsync(FeatureDefinition feature, string value, string providerKey)
{
throw new AbpException($"Can not set default value of a feature. It is only possible while defining the feature in a {typeof(IFeatureDefinitionProvider)} implementation.");
}
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.");
}
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.");
}
}

35
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagerExtensions.cs

@ -3,28 +3,27 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public static class DefaultValueFeatureManagerExtensions
{
public static class DefaultValueFeatureManagerExtensions
public static Task<string> GetOrNullDefaultAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true)
{
public static Task<string> GetOrNullDefaultAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true)
{
return featureManager.GetOrNullAsync(name, DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}
return featureManager.GetOrNullAsync(name, DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}
public static Task<List<FeatureNameValue>> GetAllDefaultAsync(this IFeatureManager featureManager, bool fallback = true)
{
return featureManager.GetAllAsync(DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}
public static Task<List<FeatureNameValue>> GetAllDefaultAsync(this IFeatureManager featureManager, bool fallback = true)
{
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<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);
}
public static Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderAsync(this IFeatureManager featureManager, bool fallback = true)
{
return featureManager.GetAllWithProviderAsync(DefaultValueFeatureValueProvider.ProviderName, null, fallback);
}
}

37
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs

@ -4,30 +4,29 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.Security.Claims;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class EditionFeatureManagementProvider : FeatureManagementProvider, ITransientDependency
{
public class EditionFeatureManagementProvider : FeatureManagementProvider, ITransientDependency
{
public override string Name => EditionFeatureValueProvider.ProviderName;
public override string Name => EditionFeatureValueProvider.ProviderName;
protected ICurrentPrincipalAccessor PrincipalAccessor { get; }
protected ICurrentPrincipalAccessor PrincipalAccessor { get; }
public EditionFeatureManagementProvider(
IFeatureManagementStore store,
ICurrentPrincipalAccessor principalAccessor)
: base(store)
{
PrincipalAccessor = principalAccessor;
}
public EditionFeatureManagementProvider(
IFeatureManagementStore store,
ICurrentPrincipalAccessor principalAccessor)
: base(store)
{
PrincipalAccessor = principalAccessor;
}
protected override Task<string> NormalizeProviderKeyAsync(string providerKey)
protected override Task<string> NormalizeProviderKeyAsync(string providerKey)
{
if (providerKey != null)
{
if (providerKey != null)
{
return Task.FromResult(providerKey);
}
return Task.FromResult(PrincipalAccessor.Principal?.FindEditionId()?.ToString("N"));
return Task.FromResult(providerKey);
}
return Task.FromResult(PrincipalAccessor.Principal?.FindEditionId()?.ToString("N"));
}
}

43
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagerExtensions.cs

@ -4,33 +4,32 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public static class EditionFeatureManagerExtensions
{
public static class EditionFeatureManagerExtensions
public static Task<string> GetOrNullForEditionAsync(this IFeatureManager featureManager, [NotNull] string name, Guid editionId, bool fallback = true)
{
public static Task<string> GetOrNullForEditionAsync(this IFeatureManager featureManager, [NotNull] string name, Guid editionId, bool fallback = true)
{
return featureManager.GetOrNullAsync(name, EditionFeatureValueProvider.ProviderName, editionId.ToString(), fallback);
}
return featureManager.GetOrNullAsync(name, EditionFeatureValueProvider.ProviderName, editionId.ToString(), fallback);
}
public static Task<List<FeatureNameValue>> GetAllForEditionAsync(this IFeatureManager featureManager, Guid editionId, bool fallback = true)
{
return featureManager.GetAllAsync(EditionFeatureValueProvider.ProviderName, editionId.ToString(), fallback);
}
public static Task<List<FeatureNameValue>> GetAllForEditionAsync(this IFeatureManager featureManager, Guid editionId, bool fallback = true)
{
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<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<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);
}
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);
}
}

13
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementDbProperties.cs

@ -1,13 +1,12 @@
using Volo.Abp.Data;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public static class FeatureManagementDbProperties
{
public static class FeatureManagementDbProperties
{
public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix;
public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix;
public static string DbSchema { get; set; } = AbpCommonDbProperties.DbSchema;
public static string DbSchema { get; set; } = AbpCommonDbProperties.DbSchema;
public const string ConnectionStringName = "AbpFeatureManagement";
}
public const string ConnectionStringName = "AbpFeatureManagement";
}

21
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementOptions.cs

@ -1,18 +1,17 @@
using System.Collections.Generic;
using Volo.Abp.Collections;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementOptions
{
public class FeatureManagementOptions
{
public ITypeList<IFeatureManagementProvider> Providers { get; }
public ITypeList<IFeatureManagementProvider> Providers { get; }
public Dictionary<string, string> ProviderPolicies { get; }
public Dictionary<string, string> ProviderPolicies { get; }
public FeatureManagementOptions()
{
Providers = new TypeList<IFeatureManagementProvider>();
ProviderPolicies = new Dictionary<string, string>();
}
public FeatureManagementOptions()
{
Providers = new TypeList<IFeatureManagementProvider>();
ProviderPolicies = new Dictionary<string, string>();
}
}
}

69
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs

@ -1,42 +1,41 @@
using System.Threading.Tasks;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class FeatureManagementProvider : IFeatureManagementProvider
{
public abstract class FeatureManagementProvider : IFeatureManagementProvider
public abstract string Name { get; }
protected IFeatureManagementStore Store { get; }
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, await NormalizeProviderKeyAsync(providerKey));
}
public virtual async Task SetAsync(FeatureDefinition feature, string value, string providerKey)
{
await Store.SetAsync(feature.Name, value, Name, await NormalizeProviderKeyAsync(providerKey));
}
public virtual async Task ClearAsync(FeatureDefinition feature, string providerKey)
{
await Store.DeleteAsync(feature.Name, Name, await NormalizeProviderKeyAsync(providerKey));
}
protected virtual Task<string> NormalizeProviderKeyAsync(string providerKey)
{
public abstract string Name { get; }
protected IFeatureManagementStore Store { get; }
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, await NormalizeProviderKeyAsync(providerKey));
}
public virtual async Task SetAsync(FeatureDefinition feature, string value, string providerKey)
{
await Store.SetAsync(feature.Name, value, Name, await NormalizeProviderKeyAsync(providerKey));
}
public virtual async Task ClearAsync(FeatureDefinition feature, string providerKey)
{
await Store.DeleteAsync(feature.Name, Name, await NormalizeProviderKeyAsync(providerKey));
}
protected virtual Task<string> NormalizeProviderKeyAsync(string providerKey)
{
return Task.FromResult(providerKey);
}
return Task.FromResult(providerKey);
}
}

169
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs

@ -7,115 +7,114 @@ using Volo.Abp.Features;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementStore : IFeatureManagementStore, ITransientDependency
{
public class FeatureManagementStore : IFeatureManagementStore, ITransientDependency
protected IDistributedCache<FeatureValueCacheItem> Cache { get; }
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
protected IFeatureValueRepository FeatureValueRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public FeatureManagementStore(
IFeatureValueRepository featureValueRepository,
IGuidGenerator guidGenerator,
IDistributedCache<FeatureValueCacheItem> cache,
IFeatureDefinitionManager featureDefinitionManager)
{
protected IDistributedCache<FeatureValueCacheItem> Cache { get; }
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
protected IFeatureValueRepository FeatureValueRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public FeatureManagementStore(
IFeatureValueRepository featureValueRepository,
IGuidGenerator guidGenerator,
IDistributedCache<FeatureValueCacheItem> cache,
IFeatureDefinitionManager featureDefinitionManager)
FeatureValueRepository = featureValueRepository;
GuidGenerator = guidGenerator;
Cache = cache;
FeatureDefinitionManager = featureDefinitionManager;
}
[UnitOfWork]
public virtual async Task<string> GetOrNullAsync(string name, string providerName, string providerKey)
{
var cacheItem = await GetCacheItemAsync(name, providerName, providerKey);
return cacheItem.Value;
}
[UnitOfWork]
public virtual async Task SetAsync(string name, string value, string providerName, string providerKey)
{
var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey);
if (featureValue == null)
{
FeatureValueRepository = featureValueRepository;
GuidGenerator = guidGenerator;
Cache = cache;
FeatureDefinitionManager = featureDefinitionManager;
featureValue = new FeatureValue(GuidGenerator.Create(), name, value, providerName, providerKey);
await FeatureValueRepository.InsertAsync(featureValue);
}
[UnitOfWork]
public virtual async Task<string> GetOrNullAsync(string name, string providerName, string providerKey)
else
{
var cacheItem = await GetCacheItemAsync(name, providerName, providerKey);
return cacheItem.Value;
featureValue.Value = value;
await FeatureValueRepository.UpdateAsync(featureValue);
}
[UnitOfWork]
public virtual async Task SetAsync(string name, string value, string providerName, string providerKey)
{
var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey);
if (featureValue == null)
{
featureValue = new FeatureValue(GuidGenerator.Create(), name, value, providerName, providerKey);
await FeatureValueRepository.InsertAsync(featureValue);
}
else
{
featureValue.Value = value;
await FeatureValueRepository.UpdateAsync(featureValue);
}
await Cache.SetAsync(CalculateCacheKey(name, providerName, providerKey), new FeatureValueCacheItem(featureValue?.Value), considerUow: true);
}
await Cache.SetAsync(CalculateCacheKey(name, providerName, providerKey), new FeatureValueCacheItem(featureValue?.Value), considerUow: true);
[UnitOfWork]
public virtual async Task DeleteAsync(string name, string providerName, string providerKey)
{
var featureValues = await FeatureValueRepository.FindAllAsync(name, providerName, providerKey);
foreach (var featureValue in featureValues)
{
await FeatureValueRepository.DeleteAsync(featureValue);
await Cache.RemoveAsync(CalculateCacheKey(name, providerName, providerKey), considerUow: true);
}
}
[UnitOfWork]
public virtual async Task DeleteAsync(string name, string providerName, string providerKey)
protected virtual async Task<FeatureValueCacheItem> GetCacheItemAsync(string name, string providerName, string providerKey)
{
var cacheKey = CalculateCacheKey(name, providerName, providerKey);
var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true);
if (cacheItem != null)
{
var featureValues = await FeatureValueRepository.FindAllAsync(name, providerName, providerKey);
foreach (var featureValue in featureValues)
{
await FeatureValueRepository.DeleteAsync(featureValue);
await Cache.RemoveAsync(CalculateCacheKey(name, providerName, providerKey), considerUow: true);
}
return cacheItem;
}
protected virtual async Task<FeatureValueCacheItem> GetCacheItemAsync(string name, string providerName, string providerKey)
{
var cacheKey = CalculateCacheKey(name, providerName, providerKey);
var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true);
cacheItem = new FeatureValueCacheItem(null);
if (cacheItem != null)
{
return cacheItem;
}
await SetCacheItemsAsync(providerName, providerKey, name, cacheItem);
cacheItem = new FeatureValueCacheItem(null);
return cacheItem;
}
await SetCacheItemsAsync(providerName, providerKey, name, cacheItem);
private async Task SetCacheItemsAsync(
string providerName,
string providerKey,
string currentName,
FeatureValueCacheItem currentCacheItem)
{
var featureDefinitions = FeatureDefinitionManager.GetAll();
var featuresDictionary = (await FeatureValueRepository.GetListAsync(providerName, providerKey))
.ToDictionary(s => s.Name, s => s.Value);
return cacheItem;
}
var cacheItems = new List<KeyValuePair<string, FeatureValueCacheItem>>();
private async Task SetCacheItemsAsync(
string providerName,
string providerKey,
string currentName,
FeatureValueCacheItem currentCacheItem)
foreach (var featureDefinition in featureDefinitions)
{
var featureDefinitions = FeatureDefinitionManager.GetAll();
var featuresDictionary = (await FeatureValueRepository.GetListAsync(providerName, providerKey))
.ToDictionary(s => s.Name, s => s.Value);
var featureValue = featuresDictionary.GetOrDefault(featureDefinition.Name);
var cacheItems = new List<KeyValuePair<string, FeatureValueCacheItem>>();
cacheItems.Add(
new KeyValuePair<string, FeatureValueCacheItem>(
CalculateCacheKey(featureDefinition.Name, providerName, providerKey),
new FeatureValueCacheItem(featureValue)
)
);
foreach (var featureDefinition in featureDefinitions)
if (featureDefinition.Name == currentName)
{
var featureValue = featuresDictionary.GetOrDefault(featureDefinition.Name);
cacheItems.Add(
new KeyValuePair<string, FeatureValueCacheItem>(
CalculateCacheKey(featureDefinition.Name, providerName, providerKey),
new FeatureValueCacheItem(featureValue)
)
);
if (featureDefinition.Name == currentName)
{
currentCacheItem.Value = featureValue;
}
currentCacheItem.Value = featureValue;
}
await Cache.SetManyAsync(cacheItems, considerUow: true);
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return FeatureValueCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
await Cache.SetManyAsync(cacheItems, considerUow: true);
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return FeatureValueCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
}

315
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs

@ -8,209 +8,208 @@ using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManager : IFeatureManager, ISingletonDependency
{
public class FeatureManager : IFeatureManager, ISingletonDependency
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
protected List<IFeatureManagementProvider> Providers => _lazyProviders.Value;
protected FeatureManagementOptions Options { get; }
protected IStringLocalizerFactory StringLocalizerFactory { get; }
private readonly Lazy<List<IFeatureManagementProvider>> _lazyProviders;
public FeatureManager(
IOptions<FeatureManagementOptions> options,
IServiceProvider serviceProvider,
IFeatureDefinitionManager featureDefinitionManager,
IStringLocalizerFactory stringLocalizerFactory)
{
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
protected List<IFeatureManagementProvider> Providers => _lazyProviders.Value;
protected FeatureManagementOptions Options { get; }
protected IStringLocalizerFactory StringLocalizerFactory { get; }
private readonly Lazy<List<IFeatureManagementProvider>> _lazyProviders;
public FeatureManager(
IOptions<FeatureManagementOptions> options,
IServiceProvider serviceProvider,
IFeatureDefinitionManager featureDefinitionManager,
IStringLocalizerFactory stringLocalizerFactory)
{
FeatureDefinitionManager = featureDefinitionManager;
StringLocalizerFactory = stringLocalizerFactory;
Options = options.Value;
//TODO: Instead, use IHybridServiceScopeFactory and create a scope..?
_lazyProviders = new Lazy<List<IFeatureManagementProvider>>(
() => Options
.Providers
.Select(c => serviceProvider.GetRequiredService(c) as IFeatureManagementProvider)
.ToList(),
true
);
}
FeatureDefinitionManager = featureDefinitionManager;
StringLocalizerFactory = stringLocalizerFactory;
Options = options.Value;
//TODO: Instead, use IHybridServiceScopeFactory and create a scope..?
_lazyProviders = new Lazy<List<IFeatureManagementProvider>>(
() => Options
.Providers
.Select(c => serviceProvider.GetRequiredService(c) as IFeatureManagementProvider)
.ToList(),
true
);
}
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));
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 (await GetOrNullInternalAsync(name, providerName, providerKey, fallback)).Value;
}
return (await GetOrNullInternalAsync(name, providerName, providerKey, fallback)).Value;
}
public virtual async Task<List<FeatureNameValue>> GetAllAsync(
string providerName,
string providerKey,
bool fallback = true)
{
return (await GetAllWithProviderAsync(providerName, providerKey, fallback))
.Select(x => new FeatureNameValue(x.Name, x.Value)).ToList();
}
public virtual async Task<List<FeatureNameValue>> GetAllAsync(
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));
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);
}
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));
public async Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderAsync(string providerName,
string providerKey, bool fallback = true)
{
Check.NotNull(providerName, nameof(providerName));
var featureDefinitions = FeatureDefinitionManager.GetAll();
var providers = Enumerable.Reverse(Providers).SkipWhile(c => c.Name != providerName);
var featureDefinitions = FeatureDefinitionManager.GetAll();
var providers = Enumerable.Reverse(Providers).SkipWhile(c => c.Name != providerName);
if (!fallback)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
if (!fallback)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
var providerList = providers.ToList();
if (!providerList.Any())
{
return new List<FeatureNameValueWithGrantedProvider>();
}
var providerList = providers.ToList();
if (!providerList.Any())
{
return new List<FeatureNameValueWithGrantedProvider>();
}
var featureValues = new Dictionary<string, FeatureNameValueWithGrantedProvider>();
var featureValues = new Dictionary<string, FeatureNameValueWithGrantedProvider>();
foreach (var feature in featureDefinitions)
foreach (var feature in featureDefinitions)
{
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(feature.Name, null);
foreach (var provider in providerList)
{
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(feature.Name, null);
foreach (var provider in providerList)
string pk = null;
if (provider.Compatible(providerName))
{
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;
}
pk = providerKey;
}
if (featureNameValueWithGrantedProvider.Value != null)
var value = await provider.GetOrNullAsync(feature, pk);
if (value != null)
{
featureValues[feature.Name] = featureNameValueWithGrantedProvider;
featureNameValueWithGrantedProvider.Value = value;
featureNameValueWithGrantedProvider.Provider = new FeatureValueProviderInfo(provider.Name, pk);
break;
}
}
return featureValues.Values.ToList();
if (featureNameValueWithGrantedProvider.Value != null)
{
featureValues[feature.Name] = featureNameValueWithGrantedProvider;
}
}
public virtual async Task SetAsync(
string name,
string value,
string providerName,
string providerKey,
bool forceToSet = false)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));
return featureValues.Values.ToList();
}
var feature = FeatureDefinitionManager.Get(name);
public virtual async Task SetAsync(
string name,
string value,
string providerName,
string providerKey,
bool forceToSet = false)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));
if (feature?.ValueType?.Validator.IsValid(value) == false)
{
throw new FeatureValueInvalidException(feature.DisplayName.Localize(StringLocalizerFactory));
}
var feature = FeatureDefinitionManager.Get(name);
var providers = Enumerable
.Reverse(Providers)
.SkipWhile(p => p.Name != providerName)
.ToList();
if (feature?.ValueType?.Validator.IsValid(value) == false)
{
throw new FeatureValueInvalidException(feature.DisplayName.Localize(StringLocalizerFactory));
}
if (!providers.Any())
{
return;
}
var providers = Enumerable
.Reverse(Providers)
.SkipWhile(p => p.Name != providerName)
.ToList();
if (providers.Count > 1 && !forceToSet && value != null)
if (!providers.Any())
{
return;
}
if (providers.Count > 1 && !forceToSet && value != null)
{
var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
if (fallbackValue.Value == value)
{
var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
if (fallbackValue.Value == value)
{
//Clear the value if it's same as it's fallback value
value = null;
}
//Clear the value if it's same as it's fallback value
value = null;
}
}
providers = providers
.TakeWhile(p => p.Name == providerName)
.ToList(); //Getting list for case of there are more than one provider with same providerName
providers = providers
.TakeWhile(p => p.Name == providerName)
.ToList(); //Getting list for case of there are more than one provider with same providerName
if (value == null)
if (value == null)
{
foreach (var provider in providers)
{
foreach (var provider in providers)
{
await provider.ClearAsync(feature, providerKey);
}
await provider.ClearAsync(feature, providerKey);
}
else
}
else
{
foreach (var provider in providers)
{
foreach (var provider in providers)
{
await provider.SetAsync(feature, value, providerKey);
}
await provider.SetAsync(feature, value, providerKey);
}
}
}
protected virtual async Task<FeatureNameValueWithGrantedProvider> GetOrNullInternalAsync(
string name,
string providerName,
string providerKey,
bool fallback = true) //TODO: Fallback is not used
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);
var providers = Enumerable
.Reverse(Providers);
if (providerName != null)
{
var feature = FeatureDefinitionManager.Get(name);
var providers = Enumerable
.Reverse(Providers);
providers = providers.SkipWhile(c => c.Name != providerName);
}
if (providerName != null)
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(name, null);
foreach (var provider in providers)
{
string pk = null;
if (provider.Compatible(providerName))
{
providers = providers.SkipWhile(c => c.Name != providerName);
pk = providerKey;
}
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(name, null);
foreach (var provider in providers)
var value = await provider.GetOrNullAsync(feature, pk);
if (value != 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;
}
featureNameValueWithGrantedProvider.Value = value;
featureNameValueWithGrantedProvider.Provider = new FeatureValueProviderInfo(provider.Name, pk);
break;
}
return featureNameValueWithGrantedProvider;
}
return featureNameValueWithGrantedProvider;
}
}

23
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValue.cs

@ -1,19 +1,18 @@
using System;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Serializable]
public class FeatureNameValue : NameValue
{
[Serializable]
public class FeatureNameValue : NameValue
public FeatureNameValue()
{
public FeatureNameValue()
{
}
}
public FeatureNameValue(string name, string value)
{
Name = name;
Value = value;
}
public FeatureNameValue(string name, string value)
{
Name = name;
Value = value;
}
}
}

21
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValueWithGrantedProvider.cs

@ -1,19 +1,18 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Serializable]
public class FeatureNameValueWithGrantedProvider : NameValue
{
[Serializable]
public class FeatureNameValueWithGrantedProvider : NameValue
{
public FeatureValueProviderInfo Provider { get; set; }
public FeatureValueProviderInfo Provider { get; set; }
public FeatureNameValueWithGrantedProvider([NotNull] string name, string value)
{
Check.NotNull(name, nameof(name));
public FeatureNameValueWithGrantedProvider([NotNull] string name, string value)
{
Check.NotNull(name, nameof(name));
Name = name;
Value = value;
}
Name = name;
Value = value;
}
}

29
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureStore.cs

@ -2,23 +2,22 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureStore : IFeatureStore, ITransientDependency
{
public class FeatureStore : IFeatureStore, ITransientDependency
{
protected IFeatureManagementStore FeatureManagementStore { get; }
protected IFeatureManagementStore FeatureManagementStore { get; }
public FeatureStore(IFeatureManagementStore featureManagementStore)
{
FeatureManagementStore = featureManagementStore;
}
public FeatureStore(IFeatureManagementStore featureManagementStore)
{
FeatureManagementStore = featureManagementStore;
}
public virtual Task<string> GetOrNullAsync(
string name,
string providerName,
string providerKey)
{
return FeatureManagementStore.GetOrNullAsync(name, providerName, providerKey);
}
public virtual Task<string> GetOrNullAsync(
string name,
string providerName,
string providerKey)
{
return FeatureManagementStore.GetOrNullAsync(name, providerName, providerKey);
}
}

67
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValue.cs

@ -2,41 +2,40 @@
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureValue : Entity<Guid>, IAggregateRoot<Guid>
{
public class FeatureValue : Entity<Guid>, IAggregateRoot<Guid>
[NotNull]
public virtual string Name { get; protected set; }
[NotNull]
public virtual string Value { get; internal set; }
[NotNull]
public virtual string ProviderName { get; protected set; }
[CanBeNull]
public virtual string ProviderKey { get; protected set; }
protected FeatureValue()
{
[NotNull]
public virtual string Name { get; protected set; }
[NotNull]
public virtual string Value { get; internal set; }
[NotNull]
public virtual string ProviderName { get; protected set; }
[CanBeNull]
public virtual string ProviderKey { get; protected set; }
protected FeatureValue()
{
}
public FeatureValue(
Guid id,
[NotNull] string name,
[NotNull] string value,
[NotNull] string providerName,
[CanBeNull] string providerKey)
{
Check.NotNull(name, nameof(name));
Id = id;
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
Value = Check.NotNullOrWhiteSpace(value, nameof(value));
ProviderName = Check.NotNullOrWhiteSpace(providerName, nameof(providerName));
ProviderKey = providerKey;
}
}
public FeatureValue(
Guid id,
[NotNull] string name,
[NotNull] string value,
[NotNull] string providerName,
[CanBeNull] string providerKey)
{
Check.NotNull(name, nameof(name));
Id = id;
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
Value = Check.NotNullOrWhiteSpace(value, nameof(value));
ProviderName = Check.NotNullOrWhiteSpace(providerName, nameof(providerName));
ProviderKey = providerKey;
}
}

35
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs

@ -1,27 +1,26 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Serializable]
[IgnoreMultiTenancy]
public class FeatureValueCacheItem
{
[Serializable]
[IgnoreMultiTenancy]
public class FeatureValueCacheItem
{
public string Value { get; set; }
public string Value { get; set; }
public FeatureValueCacheItem()
{
public FeatureValueCacheItem()
{
}
}
public FeatureValueCacheItem(string value)
{
Value = value;
}
public FeatureValueCacheItem(string value)
{
Value = value;
}
public static string CalculateCacheKey(string name, string providerName, string providerKey)
{
return "pn:" + providerName + ",pk:" + providerKey + ",n:" + name;
}
public static string CalculateCacheKey(string name, string providerName, string providerKey)
{
return "pn:" + providerName + ",pk:" + providerKey + ",n:" + name;
}
}
}

45
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs

@ -4,33 +4,32 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureValueCacheItemInvalidator :
ILocalEventHandler<EntityChangedEventData<FeatureValue>>,
ITransientDependency
{
public class FeatureValueCacheItemInvalidator :
ILocalEventHandler<EntityChangedEventData<FeatureValue>>,
ITransientDependency
{
protected IDistributedCache<FeatureValueCacheItem> Cache { get; }
protected IDistributedCache<FeatureValueCacheItem> Cache { get; }
public FeatureValueCacheItemInvalidator(IDistributedCache<FeatureValueCacheItem> cache)
{
Cache = cache;
}
public FeatureValueCacheItemInvalidator(IDistributedCache<FeatureValueCacheItem> cache)
{
Cache = cache;
}
public virtual async Task HandleEventAsync(EntityChangedEventData<FeatureValue> eventData)
{
var cacheKey = CalculateCacheKey(
eventData.Entity.Name,
eventData.Entity.ProviderName,
eventData.Entity.ProviderKey
);
public virtual async Task HandleEventAsync(EntityChangedEventData<FeatureValue> eventData)
{
var cacheKey = CalculateCacheKey(
eventData.Entity.Name,
eventData.Entity.ProviderName,
eventData.Entity.ProviderKey
);
await Cache.RemoveAsync(cacheKey, considerUow: true);
}
await Cache.RemoveAsync(cacheKey, considerUow: true);
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return FeatureValueCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return FeatureValueCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
}

39
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueConsts.cs

@ -1,25 +1,24 @@
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public static class FeatureValueConsts
{
public static class FeatureValueConsts
{
/// <summary>
/// Default value: 128
/// </summary>
public static int MaxNameLength { get; set;} = 128;
/// <summary>
/// Default value: 128
/// </summary>
public static int MaxNameLength { get; set; } = 128;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxProviderNameLength { get; set;} = 64;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxProviderNameLength { get; set; } = 64;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxProviderKeyLength { get; set;} = 64;
/// <summary>
/// Default value: 64
/// </summary>
public static int MaxProviderKeyLength { get; set; } = 64;
/// <summary>
/// Default value: 128
/// </summary>
public static int MaxValueLength { get; set;} = 128;
}
/// <summary>
/// Default value: 128
/// </summary>
public static int MaxValueLength { get; set; } = 128;
}

23
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueProviderInfo.cs

@ -1,21 +1,20 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Serializable]
public class FeatureValueProviderInfo
{
[Serializable]
public class FeatureValueProviderInfo
{
public string Name { get; }
public string Name { get; }
public string Key { get; }
public string Key { get; }
public FeatureValueProviderInfo([NotNull]string name, string key)
{
Check.NotNull(name, nameof(name));
public FeatureValueProviderInfo([NotNull] string name, string key)
{
Check.NotNull(name, nameof(name));
Name = name;
Key = key;
}
Name = name;
Key = key;
}
}

19
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementProvider.cs

@ -2,19 +2,18 @@
using JetBrains.Annotations;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public interface IFeatureManagementProvider
{
public interface IFeatureManagementProvider
{
string Name { get; }
string Name { get; }
//TODO: Other better method name.
bool Compatible(string providerName);
//TODO: Other better method name.
bool Compatible(string providerName);
Task<string> GetOrNullAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
Task<string> GetOrNullAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
Task SetAsync([NotNull] FeatureDefinition feature, [NotNull] string value, [CanBeNull] string providerKey);
Task SetAsync([NotNull] FeatureDefinition feature, [NotNull] string value, [CanBeNull] string providerKey);
Task ClearAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
}
Task ClearAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
}

15
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementStore.cs

@ -1,13 +1,12 @@
using System.Threading.Tasks;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public interface IFeatureManagementStore
{
public interface IFeatureManagementStore
{
Task<string> GetOrNullAsync(string name, string providerName, string providerKey);
Task<string> GetOrNullAsync(string name, string providerName, string providerKey);
Task SetAsync(string name, string value, string providerName, string providerKey);
Task SetAsync(string name, string value, string providerName, string providerKey);
Task DeleteAsync(string name, string providerName, string providerKey);
}
}
Task DeleteAsync(string name, string providerName, string providerKey);
}

17
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManager.cs

@ -2,18 +2,17 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public interface IFeatureManager
{
public interface IFeatureManager
{
Task<string> GetOrNullAsync([NotNull]string name, [NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
Task<string> GetOrNullAsync([NotNull] string name, [NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
Task<List<FeatureNameValue>> GetAllAsync([NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
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<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<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);
}
Task SetAsync([NotNull] string name, [CanBeNull] string value, [NotNull] string providerName, [CanBeNull] string providerKey, bool forceToSet = false);
}

35
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs

@ -4,25 +4,24 @@ using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public interface IFeatureValueRepository : IBasicRepository<FeatureValue, Guid>
{
public interface IFeatureValueRepository : IBasicRepository<FeatureValue, Guid>
{
Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
}
Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
}

37
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagementProvider.cs

@ -3,30 +3,29 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class TenantFeatureManagementProvider : FeatureManagementProvider, ITransientDependency
{
public class TenantFeatureManagementProvider : FeatureManagementProvider, ITransientDependency
{
public override string Name => TenantFeatureValueProvider.ProviderName;
public override string Name => TenantFeatureValueProvider.ProviderName;
protected ICurrentTenant CurrentTenant { get; }
protected ICurrentTenant CurrentTenant { get; }
public TenantFeatureManagementProvider(
IFeatureManagementStore store,
ICurrentTenant currentTenant)
: base(store)
{
CurrentTenant = currentTenant;
}
public TenantFeatureManagementProvider(
IFeatureManagementStore store,
ICurrentTenant currentTenant)
: base(store)
{
CurrentTenant = currentTenant;
}
protected override Task<string> NormalizeProviderKeyAsync(string providerKey)
protected override Task<string> NormalizeProviderKeyAsync(string providerKey)
{
if (providerKey != null)
{
if (providerKey != null)
{
return Task.FromResult(providerKey);
}
return Task.FromResult(CurrentTenant.Id?.ToString());
return Task.FromResult(providerKey);
}
return Task.FromResult(CurrentTenant.Id?.ToString());
}
}

43
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagerExtensions.cs

@ -4,33 +4,32 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public static class TenantFeatureManagerExtensions
{
public static class TenantFeatureManagerExtensions
public static Task<string> GetOrNullForTenantAsync(this IFeatureManager featureManager, [NotNull] string name, Guid tenantId, bool fallback = true)
{
public static Task<string> GetOrNullForTenantAsync(this IFeatureManager featureManager, [NotNull] string name, Guid tenantId, bool fallback = true)
{
return featureManager.GetOrNullAsync(name, TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
}
return featureManager.GetOrNullAsync(name, TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
}
public static Task<List<FeatureNameValue>> GetAllForTenantAsync(this IFeatureManager featureManager, Guid tenantId, bool fallback = true)
{
return featureManager.GetAllAsync(TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
}
public static Task<List<FeatureNameValue>> GetAllForTenantAsync(this IFeatureManager featureManager, Guid tenantId, bool fallback = true)
{
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<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<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);
}
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);
}
}

27
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/AbpFeatureManagementEntityFrameworkCoreModule.cs

@ -2,22 +2,21 @@
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
[DependsOn(
typeof(AbpFeatureManagementDomainModule),
typeof(AbpEntityFrameworkCoreModule)
)]
public class AbpFeatureManagementEntityFrameworkCoreModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementDomainModule),
typeof(AbpEntityFrameworkCoreModule)
)]
public class AbpFeatureManagementEntityFrameworkCoreModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
context.Services.AddAbpDbContext<FeatureManagementDbContext>(options =>
{
context.Services.AddAbpDbContext<FeatureManagementDbContext>(options =>
{
options.AddDefaultRepositories<IFeatureManagementDbContext>();
options.AddDefaultRepositories<IFeatureManagementDbContext>();
options.AddRepository<FeatureValue, EfCoreFeatureValueRepository>();
});
}
options.AddRepository<FeatureValue, EfCoreFeatureValueRepository>();
});
}
}
}

73
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs

@ -7,47 +7,46 @@ using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
public class EfCoreFeatureValueRepository : EfCoreRepository<IFeatureManagementDbContext, FeatureValue, Guid>, IFeatureValueRepository
{
public class EfCoreFeatureValueRepository : EfCoreRepository<IFeatureManagementDbContext, FeatureValue, Guid>, IFeatureValueRepository
public EfCoreFeatureValueRepository(IDbContextProvider<IFeatureManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
public EfCoreFeatureValueRepository(IDbContextProvider<IFeatureManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
public virtual async Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, GetCancellationToken(cancellationToken));
}
public virtual async Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, GetCancellationToken(cancellationToken));
}
public async Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.Where(
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.Where(
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.Where(
s => s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.Where(
s => s.ProviderName == providerName && s.ProviderKey == providerKey
).ToListAsync(GetCancellationToken(cancellationToken));
}
}

29
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureManagementDbContext.cs

@ -3,25 +3,24 @@ using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public class FeatureManagementDbContext : AbpDbContext<FeatureManagementDbContext>, IFeatureManagementDbContext
{
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public class FeatureManagementDbContext : AbpDbContext<FeatureManagementDbContext>, IFeatureManagementDbContext
{
public DbSet<FeatureValue> FeatureValues { get; set; }
public DbSet<FeatureValue> FeatureValues { get; set; }
public FeatureManagementDbContext(DbContextOptions<FeatureManagementDbContext> options)
: base(options)
{
public FeatureManagementDbContext(DbContextOptions<FeatureManagementDbContext> options)
: base(options)
{
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigureFeatureManagement();
}
builder.ConfigureFeatureManagement();
}
}

48
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureManagementDbContextModelCreatingExtensions.cs

@ -1,38 +1,36 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
public static class FeatureManagementDbContextModelCreatingExtensions
{
public static class FeatureManagementDbContextModelCreatingExtensions
public static void ConfigureFeatureManagement(
this ModelBuilder builder)
{
public static void ConfigureFeatureManagement(
this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
Check.NotNull(builder, nameof(builder));
if (builder.IsTenantOnlyDatabase())
{
return;
}
if (builder.IsTenantOnlyDatabase())
{
return;
}
builder.Entity<FeatureValue>(b =>
{
b.ToTable(FeatureManagementDbProperties.DbTablePrefix + "FeatureValues", FeatureManagementDbProperties.DbSchema);
builder.Entity<FeatureValue>(b =>
{
b.ToTable(FeatureManagementDbProperties.DbTablePrefix + "FeatureValues", FeatureManagementDbProperties.DbSchema);
b.ConfigureByConvention();
b.ConfigureByConvention();
b.Property(x => x.Name).HasMaxLength(FeatureValueConsts.MaxNameLength).IsRequired();
b.Property(x => x.Value).HasMaxLength(FeatureValueConsts.MaxValueLength).IsRequired();
b.Property(x => x.ProviderName).HasMaxLength(FeatureValueConsts.MaxProviderNameLength);
b.Property(x => x.ProviderKey).HasMaxLength(FeatureValueConsts.MaxProviderKeyLength);
b.Property(x => x.Name).HasMaxLength(FeatureValueConsts.MaxNameLength).IsRequired();
b.Property(x => x.Value).HasMaxLength(FeatureValueConsts.MaxValueLength).IsRequired();
b.Property(x => x.ProviderName).HasMaxLength(FeatureValueConsts.MaxProviderNameLength);
b.Property(x => x.ProviderKey).HasMaxLength(FeatureValueConsts.MaxProviderKeyLength);
b.HasIndex(x => new { x.Name, x.ProviderName, x.ProviderKey }).IsUnique(true);
b.HasIndex(x => new { x.Name, x.ProviderName, x.ProviderKey }).IsUnique(true);
b.ApplyObjectExtensionMappings();
});
b.ApplyObjectExtensionMappings();
});
builder.TryConfigureObjectExtensions<FeatureManagementDbContext>();
}
builder.TryConfigureObjectExtensions<FeatureManagementDbContext>();
}
}

13
modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/IFeatureManagementDbContext.cs

@ -3,12 +3,11 @@ using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public interface IFeatureManagementDbContext : IEfCoreDbContext
{
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public interface IFeatureManagementDbContext : IEfCoreDbContext
{
DbSet<FeatureValue> FeatureValues { get; }
}
DbSet<FeatureValue> FeatureValues { get; }
}

7
modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/FeaturesClientProxy.cs

@ -1,8 +1,7 @@
// This file is part of FeaturesClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace Volo.Abp.FeatureManagement.ClientProxies
namespace Volo.Abp.FeatureManagement.ClientProxies;
public partial class FeaturesClientProxy
{
public partial class FeaturesClientProxy
{
}
}

31
modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiClientModule.cs

@ -3,24 +3,23 @@ using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpHttpClientModule))]
public class AbpFeatureManagementHttpApiClientModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpHttpClientModule))]
public class AbpFeatureManagementHttpApiClientModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddStaticHttpClientProxies(
typeof(AbpFeatureManagementApplicationContractsModule).Assembly,
FeatureManagementRemoteServiceConsts.RemoteServiceName
);
context.Services.AddStaticHttpClientProxies(
typeof(AbpFeatureManagementApplicationContractsModule).Assembly,
FeatureManagementRemoteServiceConsts.RemoteServiceName
);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureManagementHttpApiClientModule>();
});
}
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureManagementHttpApiClientModule>();
});
}
}

45
modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/AbpFeatureManagementHttpApiModule.cs

@ -8,34 +8,33 @@ using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.FeatureManagement.JsonConverters;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))]
public class AbpFeatureManagementHttpApiModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))]
public class AbpFeatureManagementHttpApiModule : AbpModule
public override void PreConfigureServices(ServiceConfigurationContext context)
{
public override void PreConfigureServices(ServiceConfigurationContext context)
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFeatureManagementHttpApiModule).Assembly);
});
}
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFeatureManagementHttpApiModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AbpFeatureManagementResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
options.Resources
.Get<AbpFeatureManagementResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
Configure<JsonOptions>(options =>
{
options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter());
});
}
Configure<JsonOptions>(options =>
{
options.JsonSerializerOptions.Converters.AddIfNotContains(new StringValueTypeJsonConverter());
});
}
}

41
modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs

@ -2,30 +2,29 @@
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)]
[Area(FeatureManagementRemoteServiceConsts.ModuleName)]
[Route("api/feature-management/features")]
public class FeaturesController : AbpControllerBase, IFeatureAppService
{
[RemoteService(Name = FeatureManagementRemoteServiceConsts.RemoteServiceName)]
[Area(FeatureManagementRemoteServiceConsts.ModuleName)]
[Route("api/feature-management/features")]
public class FeaturesController : AbpControllerBase, IFeatureAppService
{
protected IFeatureAppService FeatureAppService { get; }
protected IFeatureAppService FeatureAppService { get; }
public FeaturesController(IFeatureAppService featureAppService)
{
FeatureAppService = featureAppService;
}
public FeaturesController(IFeatureAppService featureAppService)
{
FeatureAppService = featureAppService;
}
[HttpGet]
public virtual Task<GetFeatureListResultDto> GetAsync(string providerName, string providerKey)
{
return FeatureAppService.GetAsync(providerName, providerKey);
}
[HttpGet]
public virtual Task<GetFeatureListResultDto> GetAsync(string providerName, string providerKey)
{
return FeatureAppService.GetAsync(providerName, providerKey);
}
[HttpPut]
public virtual Task UpdateAsync(string providerName, string providerKey, UpdateFeaturesDto input)
{
return FeatureAppService.UpdateAsync(providerName, providerKey, input);
}
[HttpPut]
public virtual Task UpdateAsync(string providerName, string providerKey, UpdateFeaturesDto input)
{
return FeatureAppService.UpdateAsync(providerName, providerKey, input);
}
}

23
modules/feature-management/src/Volo.Abp.FeatureManagement.Installer/Volo/Abp/FeatureManagement/AbpFeatureManagementInstallerModule.cs

@ -2,20 +2,19 @@
using Volo.Abp.Studio;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpStudioModuleInstallerModule),
typeof(AbpVirtualFileSystemModule)
)]
public class AbpFeatureManagementInstallerModule : AbpModule
{
[DependsOn(
typeof(AbpStudioModuleInstallerModule),
typeof(AbpVirtualFileSystemModule)
)]
public class AbpFeatureManagementInstallerModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureManagementInstallerModule>();
});
}
options.FileSets.AddEmbedded<AbpFeatureManagementInstallerModule>();
});
}
}

29
modules/feature-management/src/Volo.Abp.FeatureManagement.Installer/Volo/Abp/FeatureManagement/FeatureManagementInstallerPipelineBuilder.cs

@ -3,22 +3,21 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Studio.ModuleInstalling;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IModuleInstallingPipelineBuilder))]
public class FeatureManagementInstallerPipelineBuilder : ModuleInstallingPipelineBuilderBase, IModuleInstallingPipelineBuilder, ITransientDependency
{
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IModuleInstallingPipelineBuilder))]
public class FeatureManagementInstallerPipelineBuilder : ModuleInstallingPipelineBuilderBase, IModuleInstallingPipelineBuilder, ITransientDependency
public async Task<ModuleInstallingPipeline> BuildAsync(ModuleInstallingContext context)
{
public async Task<ModuleInstallingPipeline> BuildAsync(ModuleInstallingContext context)
{
context.AddEfCoreConfigurationMethodDeclaration(
new EfCoreConfigurationMethodDeclaration(
"Volo.Abp.FeatureManagement.EntityFrameworkCore",
"ConfigureFeatureManagement"
)
);
return GetBasePipeline(context);
}
context.AddEfCoreConfigurationMethodDeclaration(
new EfCoreConfigurationMethodDeclaration(
"Volo.Abp.FeatureManagement.EntityFrameworkCore",
"ConfigureFeatureManagement"
)
);
return GetBasePipeline(context);
}
}

25
modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/AbpFeatureManagementMongoDbModule.cs

@ -2,22 +2,21 @@
using Volo.Abp.Modularity;
using Volo.Abp.MongoDB;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[DependsOn(
typeof(AbpFeatureManagementDomainModule),
typeof(AbpMongoDbModule)
)]
public class AbpFeatureManagementMongoDbModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementDomainModule),
typeof(AbpMongoDbModule)
)]
public class AbpFeatureManagementMongoDbModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
context.Services.AddMongoDbContext<FeatureManagementMongoDbContext>(options =>
{
context.Services.AddMongoDbContext<FeatureManagementMongoDbContext>(options =>
{
options.AddDefaultRepositories<IFeatureManagementMongoDbContext>();
options.AddDefaultRepositories<IFeatureManagementMongoDbContext>();
options.AddRepository<FeatureValue, MongoFeatureValueRepository>();
});
}
options.AddRepository<FeatureValue, MongoFeatureValueRepository>();
});
}
}

21
modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/FeatureManagementMongoDbContext.cs

@ -3,19 +3,18 @@ using Volo.Abp.Data;
using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public class FeatureManagementMongoDbContext : AbpMongoDbContext, IFeatureManagementMongoDbContext
{
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public class FeatureManagementMongoDbContext : AbpMongoDbContext, IFeatureManagementMongoDbContext
{
public IMongoCollection<FeatureValue> FeatureValues => Collection<FeatureValue>();
public IMongoCollection<FeatureValue> FeatureValues => Collection<FeatureValue>();
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
modelBuilder.ConfigureFeatureManagement();
}
modelBuilder.ConfigureFeatureManagement();
}
}

23
modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/FeatureManagementMongoDbContextExtensions.cs

@ -1,18 +1,17 @@
using Volo.Abp.MongoDB;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
public static class FeatureManagementMongoDbContextExtensions
{
public static class FeatureManagementMongoDbContextExtensions
public static void ConfigureFeatureManagement(
this IMongoModelBuilder builder)
{
public static void ConfigureFeatureManagement(
this IMongoModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
Check.NotNull(builder, nameof(builder));
builder.Entity<FeatureValue>(b =>
{
b.CollectionName = FeatureManagementDbProperties.DbTablePrefix + "FeatureValues";
});
}
builder.Entity<FeatureValue>(b =>
{
b.CollectionName = FeatureManagementDbProperties.DbTablePrefix + "FeatureValues";
});
}
}
}

13
modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/IFeatureManagementMongoDbContext.cs

@ -3,12 +3,11 @@ using Volo.Abp.Data;
using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public interface IFeatureManagementMongoDbContext : IAbpMongoDbContext
{
[IgnoreMultiTenancy]
[ConnectionStringName(FeatureManagementDbProperties.ConnectionStringName)]
public interface IFeatureManagementMongoDbContext : IAbpMongoDbContext
{
IMongoCollection<FeatureValue> FeatureValues { get; }
}
IMongoCollection<FeatureValue> FeatureValues { get; }
}

67
modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs

@ -7,45 +7,44 @@ using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
public class MongoFeatureValueRepository : MongoDbRepository<IFeatureManagementMongoDbContext, FeatureValue, Guid>, IFeatureValueRepository
{
public class MongoFeatureValueRepository : MongoDbRepository<IFeatureManagementMongoDbContext, FeatureValue, Guid>, IFeatureValueRepository
public MongoFeatureValueRepository(IMongoDbContextProvider<IFeatureManagementMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
public MongoFeatureValueRepository(IMongoDbContextProvider<IFeatureManagementMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
public virtual async Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, GetCancellationToken(cancellationToken));
}
public virtual async Task<FeatureValue> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.OrderBy(x => x.Id)
.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey, GetCancellationToken(cancellationToken));
}
public async Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<FeatureValue>> FindAllAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<FeatureValue>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(GetCancellationToken(cancellationToken));
}
}

67
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/AbpFeatureManagementWebModule.cs

@ -8,50 +8,49 @@ using Volo.Abp.Http.ProxyScripting.Generators.JQuery;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcUiThemeSharedModule),
typeof(AbpAutoMapperModule)
)]
public class AbpFeatureManagementWebModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcUiThemeSharedModule),
typeof(AbpAutoMapperModule)
)]
public class AbpFeatureManagementWebModule : AbpModule
public override void PreConfigureServices(ServiceConfigurationContext context)
{
public override void PreConfigureServices(ServiceConfigurationContext context)
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(typeof(AbpFeatureManagementResource), typeof(AbpFeatureManagementWebModule).Assembly);
});
options.AddAssemblyResource(typeof(AbpFeatureManagementResource), typeof(AbpFeatureManagementWebModule).Assembly);
});
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFeatureManagementWebModule).Assembly);
});
}
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpFeatureManagementWebModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpFeatureManagementWebModule>();
});
options.FileSets.AddEmbedded<AbpFeatureManagementWebModule>();
});
context.Services.AddAutoMapperObjectMapper<AbpFeatureManagementWebModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<FeatureManagementWebAutoMapperProfile>(validate: true);
});
context.Services.AddAutoMapperObjectMapper<AbpFeatureManagementWebModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<FeatureManagementWebAutoMapperProfile>(validate: true);
});
Configure<RazorPagesOptions>(options =>
{
Configure<RazorPagesOptions>(options =>
{
//Configure authorization.
});
Configure<DynamicJavaScriptProxyOptions>(options =>
{
options.DisableModule(FeatureManagementRemoteServiceConsts.ModuleName);
});
}
Configure<DynamicJavaScriptProxyOptions>(options =>
{
options.DisableModule(FeatureManagementRemoteServiceConsts.ModuleName);
});
}
}

13
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/FeatureManagementWebAutoMapperProfile.cs

@ -1,12 +1,11 @@
using AutoMapper;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementWebAutoMapperProfile : Profile
{
public class FeatureManagementWebAutoMapperProfile : Profile
public FeatureManagementWebAutoMapperProfile()
{
public FeatureManagementWebAutoMapperProfile()
{
//Create mappings.
}
//Create mappings.
}
}
}

115
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml.cs

@ -9,86 +9,85 @@ using Volo.Abp.EventBus.Local;
using Volo.Abp.Features;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement.Web.Pages.FeatureManagement
namespace Volo.Abp.FeatureManagement.Web.Pages.FeatureManagement;
public class FeatureManagementModal : AbpPageModel
{
public class FeatureManagementModal : AbpPageModel
{
[Required]
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ProviderName { get; set; }
[Required]
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ProviderName { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ProviderKey { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
public string ProviderKey { get; set; }
[BindProperty]
public List<FeatureGroupViewModel> FeatureGroups { get; set; }
[BindProperty]
public List<FeatureGroupViewModel> FeatureGroups { get; set; }
public GetFeatureListResultDto FeatureListResultDto { get; set; }
public GetFeatureListResultDto FeatureListResultDto { get; set; }
protected IFeatureAppService FeatureAppService { get; }
protected IFeatureAppService FeatureAppService { get; }
protected ILocalEventBus LocalEventBus { get; }
protected ILocalEventBus LocalEventBus { get; }
public FeatureManagementModal(
IFeatureAppService featureAppService,
ILocalEventBus localEventBus)
{
ObjectMapperContext = typeof(AbpFeatureManagementWebModule);
public FeatureManagementModal(
IFeatureAppService featureAppService,
ILocalEventBus localEventBus)
{
ObjectMapperContext = typeof(AbpFeatureManagementWebModule);
FeatureAppService = featureAppService;
LocalEventBus = localEventBus;
}
FeatureAppService = featureAppService;
LocalEventBus = localEventBus;
}
public virtual async Task<IActionResult> OnGetAsync()
{
ValidateModel();
public virtual async Task<IActionResult> OnGetAsync()
{
ValidateModel();
FeatureListResultDto = await FeatureAppService.GetAsync(ProviderName, ProviderKey);
FeatureListResultDto = await FeatureAppService.GetAsync(ProviderName, ProviderKey);
return Page();
}
return Page();
}
public virtual async Task<IActionResult> OnPostAsync()
public virtual async Task<IActionResult> OnPostAsync()
{
var features = new UpdateFeaturesDto
{
var features = new UpdateFeaturesDto
Features = FeatureGroups.SelectMany(g => g.Features).Select(f => new UpdateFeatureDto
{
Features = FeatureGroups.SelectMany(g => g.Features).Select(f => new UpdateFeatureDto
{
Name = f.Name,
Value = f.Type == nameof(ToggleStringValueType) ? f.BoolValue.ToString() : f.Value
}).ToList()
};
Name = f.Name,
Value = f.Type == nameof(ToggleStringValueType) ? f.BoolValue.ToString() : f.Value
}).ToList()
};
await FeatureAppService.UpdateAsync(ProviderName, ProviderKey, features);
await FeatureAppService.UpdateAsync(ProviderName, ProviderKey, features);
await LocalEventBus.PublishAsync(
new CurrentApplicationConfigurationCacheResetEventData()
);
await LocalEventBus.PublishAsync(
new CurrentApplicationConfigurationCacheResetEventData()
);
return NoContent();
}
return NoContent();
}
public virtual bool IsDisabled(string providerName)
{
return providerName != ProviderName && providerName != DefaultValueFeatureValueProvider.ProviderName;
}
public virtual bool IsDisabled(string providerName)
{
return providerName != ProviderName && providerName != DefaultValueFeatureValueProvider.ProviderName;
}
public class FeatureGroupViewModel
{
public List<FeatureViewModel> Features { get; set; }
}
public class FeatureGroupViewModel
{
public List<FeatureViewModel> Features { get; set; }
}
public class FeatureViewModel
{
public string Name { get; set; }
public class FeatureViewModel
{
public string Name { get; set; }
public string Value { get; set; }
public string Value { get; set; }
public bool BoolValue { get; set; }
public bool BoolValue { get; set; }
public string Type { get; set; }
}
public string Type { get; set; }
}
}

27
modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Properties/launchSettings.json

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50650/",
"sslPort": 44341
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.FeatureManagement.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

95
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs

@ -9,71 +9,70 @@ using Volo.Abp.Features;
using Volo.Abp.Users;
using Xunit;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureAppService_Tests : FeatureManagementApplicationTestBase
{
public class FeatureAppService_Tests : FeatureManagementApplicationTestBase
{
private readonly IFeatureAppService _featureAppService;
private readonly IFeatureValueRepository _featureValueRepository;
private ICurrentUser _currentUser;
private readonly FeatureManagementTestData _testData;
private readonly IFeatureAppService _featureAppService;
private readonly IFeatureValueRepository _featureValueRepository;
private ICurrentUser _currentUser;
private readonly FeatureManagementTestData _testData;
public FeatureAppService_Tests()
{
_featureAppService = GetRequiredService<IFeatureAppService>();
_featureValueRepository = GetRequiredService<IFeatureValueRepository>();
_testData = GetRequiredService<FeatureManagementTestData>();
}
public FeatureAppService_Tests()
{
_featureAppService = GetRequiredService<IFeatureAppService>();
_featureValueRepository = GetRequiredService<IFeatureValueRepository>();
_testData = GetRequiredService<FeatureManagementTestData>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
_currentUser = Substitute.For<ICurrentUser>();
services.AddSingleton(_currentUser);
}
protected override void AfterAddApplication(IServiceCollection services)
{
_currentUser = Substitute.For<ICurrentUser>();
services.AddSingleton(_currentUser);
}
[Fact]
public async Task GetAsync()
{
Login(_testData.User1Id);
[Fact]
public async Task GetAsync()
{
Login(_testData.User1Id);
var featureList = await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
var featureList = await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
featureList.ShouldNotBeNull();
featureList.Groups.SelectMany(g =>g .Features).ShouldContain(feature => feature.Name == TestFeatureDefinitionProvider.SocialLogins);
}
featureList.ShouldNotBeNull();
featureList.Groups.SelectMany(g => g.Features).ShouldContain(feature => feature.Name == TestFeatureDefinitionProvider.SocialLogins);
}
[Fact]
public async Task UpdateAsync()
{
Login(_testData.User1Id);
[Fact]
public async Task UpdateAsync()
{
Login(_testData.User1Id);
await _featureAppService.UpdateAsync(EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString(), new UpdateFeaturesDto()
await _featureAppService.UpdateAsync(EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString(), new UpdateFeaturesDto()
{
Features = new List<UpdateFeatureDto>()
{
Features = new List<UpdateFeatureDto>()
{
new UpdateFeatureDto()
{
Name = TestFeatureDefinitionProvider.SocialLogins,
Value = false.ToString().ToLowerInvariant()
}
}
});
}
});
(await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).Groups.SelectMany(g => g.Features).Any(x =>
x.Name == TestFeatureDefinitionProvider.SocialLogins &&
x.Value == false.ToString().ToLowerInvariant())
.ShouldBeTrue();
(await _featureAppService.GetAsync(EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).Groups.SelectMany(g => g.Features).Any(x =>
x.Name == TestFeatureDefinitionProvider.SocialLogins &&
x.Value == false.ToString().ToLowerInvariant())
.ShouldBeTrue();
}
}
private void Login(Guid userId)
{
_currentUser.Id.Returns(userId);
_currentUser.IsAuthenticated.Returns(true);
}
private void Login(Guid userId)
{
_currentUser.Id.Returns(userId);
_currentUser.IsAuthenticated.Returns(true);
}
}

9
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureManagementApplicationTestBase.cs

@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.FeatureManagement;
namespace Volo.Abp.FeatureManagement
public class FeatureManagementApplicationTestBase : FeatureManagementTestBase<FeatureManagementApplicationTestModule>
{
public class FeatureManagementApplicationTestBase : FeatureManagementTestBase<FeatureManagementApplicationTestModule>
{
}
}

15
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureManagementApplicationTestModule.cs

@ -1,13 +1,12 @@
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpFeatureManagementDomainTestModule)
)]
public class FeatureManagementApplicationTestModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpFeatureManagementDomainTestModule)
)]
public class FeatureManagementApplicationTestModule : AbpModule
{
}
}

15
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/NewtonsoftStringValueJsonConverter_Tests.cs

@ -1,16 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Json;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class NewtonsoftStringValueJsonConverter_Tests : StringValueJsonConverter_Tests
{
public class NewtonsoftStringValueJsonConverter_Tests : StringValueJsonConverter_Tests
protected override void AfterAddApplication(IServiceCollection services)
{
protected override void AfterAddApplication(IServiceCollection services)
services.PreConfigure<AbpJsonOptions>(options =>
{
services.PreConfigure<AbpJsonOptions>(options =>
{
options.UseHybridSerializer = true;
});
}
options.UseHybridSerializer = true;
});
}
}

63
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs

@ -5,23 +5,23 @@ using Volo.Abp.Json;
using Volo.Abp.Validation.StringValues;
using Xunit;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class StringValueJsonConverter_Tests : FeatureManagementApplicationTestBase
{
public abstract class StringValueJsonConverter_Tests : FeatureManagementApplicationTestBase
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IJsonSerializer _jsonSerializer;
public StringValueJsonConverter_Tests()
{
_jsonSerializer = GetRequiredService<IJsonSerializer>();
}
public StringValueJsonConverter_Tests()
{
_jsonSerializer = GetRequiredService<IJsonSerializer>();
}
[Fact]
public void Should_Serialize_And_Deserialize()
[Fact]
public void Should_Serialize_And_Deserialize()
{
var featureListDto = new GetFeatureListResultDto
{
var featureListDto = new GetFeatureListResultDto
{
Groups = new List<FeatureGroupDto>
Groups = new List<FeatureGroupDto>
{
new FeatureGroupDto
{
@ -71,30 +71,29 @@ namespace Volo.Abp.FeatureManagement
}
}
}
};
};
var serialized = _jsonSerializer.Serialize(featureListDto, indented: true);
var serialized = _jsonSerializer.Serialize(featureListDto, indented: true);
var featureListDto2 = _jsonSerializer.Deserialize<GetFeatureListResultDto>(serialized);
var featureListDto2 = _jsonSerializer.Deserialize<GetFeatureListResultDto>(serialized);
featureListDto2.ShouldNotBeNull();
featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType<FreeTextStringValueType>();
featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType<BooleanValueValidator>();
featureListDto2.ShouldNotBeNull();
featureListDto2.Groups[0].Features[0].ValueType.ShouldBeOfType<FreeTextStringValueType>();
featureListDto2.Groups[0].Features[0].ValueType.Validator.ShouldBeOfType<BooleanValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.ShouldBeOfType<SelectionStringValueType>();
featureListDto2.Groups[0].Features[1].ValueType.Validator.ShouldBeOfType<AlwaysValidValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldBeOfType<LocalizableSelectionStringValueItem[]>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldContain(x =>
x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" &&
x.DisplayText.Name == "TestName");
featureListDto2.Groups[0].Features[1].ValueType.ShouldBeOfType<SelectionStringValueType>();
featureListDto2.Groups[0].Features[1].ValueType.Validator.ShouldBeOfType<AlwaysValidValueValidator>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldBeOfType<LocalizableSelectionStringValueItem[]>();
featureListDto2.Groups[0].Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldContain(x =>
x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" &&
x.DisplayText.Name == "TestName");
featureListDto2.Groups[0].Features[2].ValueType.ShouldBeOfType<ToggleStringValueType>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType<NumericValueValidator>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MaxValue.ShouldBe(1000);
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MinValue.ShouldBe(10);
featureListDto2.Groups[0].Features[2].ValueType.ShouldBeOfType<ToggleStringValueType>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.ShouldBeOfType<NumericValueValidator>();
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MaxValue.ShouldBe(1000);
featureListDto2.Groups[0].Features[2].ValueType.Validator.As<NumericValueValidator>().MinValue.ShouldBe(10);
featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName");
featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey");
}
featureListDto2.Groups[0].Features[3].Provider.Name.ShouldBe("FeatureName");
featureListDto2.Groups[0].Features[3].Provider.Key.ShouldBe("FeatureKey");
}
}

15
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/SystemTextJsonStringValueJsonConverter_Tests.cs

@ -1,16 +1,15 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Json;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class SystemTextJsonStringValueJsonConverter_Tests : StringValueJsonConverter_Tests
{
public class SystemTextJsonStringValueJsonConverter_Tests : StringValueJsonConverter_Tests
protected override void AfterAddApplication(IServiceCollection services)
{
protected override void AfterAddApplication(IServiceCollection services)
services.PreConfigure<AbpJsonOptions>(options =>
{
services.PreConfigure<AbpJsonOptions>(options =>
{
options.UseHybridSerializer = false;
});
}
options.UseHybridSerializer = false;
});
}
}

15
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainTestModule.cs

@ -1,13 +1,12 @@
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpFeatureManagementEntityFrameworkCoreTestModule)
)]
public class AbpFeatureManagementDomainTestModule : AbpModule
{
[DependsOn(
typeof(AbpFeatureManagementEntityFrameworkCoreTestModule)
)]
public class AbpFeatureManagementDomainTestModule : AbpModule
{
}
}

9
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManagementDomainTestBase.cs

@ -1,7 +1,6 @@
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class FeatureManagementDomainTestBase : FeatureManagementTestBase<AbpFeatureManagementDomainTestModule>
{
public abstract class FeatureManagementDomainTestBase : FeatureManagementTestBase<AbpFeatureManagementDomainTestModule>
{
}
}
}

270
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs

@ -1,158 +1,156 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
using Xunit;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManager_Tests : FeatureManagementDomainTestBase
{
public class FeatureManager_Tests : FeatureManagementDomainTestBase
private readonly IFeatureManager _featureManager;
private readonly ICurrentTenant _currentTenant;
private readonly IFeatureChecker _featureChecker;
public FeatureManager_Tests()
{
private readonly IFeatureManager _featureManager;
private readonly ICurrentTenant _currentTenant;
private readonly IFeatureChecker _featureChecker;
_featureManager = GetRequiredService<IFeatureManager>();
_featureChecker = GetRequiredService<IFeatureChecker>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
public FeatureManager_Tests()
{
_featureManager = GetRequiredService<IFeatureManager>();
_featureChecker = GetRequiredService<IFeatureChecker>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
[Fact]
public async Task Should_Get_A_FeatureValue_For_A_Provider()
{
//Default values
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.SocialLogins
)).ShouldBeNull();
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.DailyAnalysis
)).ShouldBe(false.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.ProjectCount
)).ShouldBe("1");
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.BackupCount
)).ShouldBe("0");
//"Enterprise" edition values
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.SocialLogins,
TestEditionIds.Enterprise
)).ShouldBe(true.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.DailyAnalysis,
TestEditionIds.Enterprise
)).ShouldBe(false.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.ProjectCount,
TestEditionIds.Enterprise
)).ShouldBe("3");
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.BackupCount,
TestEditionIds.Enterprise
)).ShouldBe("5");
//"Ultimate" edition values
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.SocialLogins,
TestEditionIds.Ultimate
)).ShouldBe(true.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.DailyAnalysis,
TestEditionIds.Ultimate
)).ShouldBe(true.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.ProjectCount,
TestEditionIds.Ultimate
)).ShouldBe("10");
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.BackupCount,
TestEditionIds.Ultimate
)).ShouldBe("10");
}
[Fact]
public async Task Should_Get_A_FeatureValue_For_A_Provider()
[Fact]
public async Task Should_Change_Feature_Value_And_Refresh_Cache()
{
var tenantId = Guid.NewGuid();
//It is "False" at the beginning
using (_currentTenant.Change(tenantId))
{
//Default values
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.SocialLogins
)).ShouldBeNull();
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.DailyAnalysis
)).ShouldBe(false.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.ProjectCount
)).ShouldBe("1");
(await _featureManager.GetOrNullDefaultAsync(
TestFeatureDefinitionProvider.BackupCount
)).ShouldBe("0");
//"Enterprise" edition values
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.SocialLogins,
TestEditionIds.Enterprise
)).ShouldBe(true.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.DailyAnalysis,
TestEditionIds.Enterprise
)).ShouldBe(false.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.ProjectCount,
TestEditionIds.Enterprise
)).ShouldBe("3");
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.BackupCount,
TestEditionIds.Enterprise
)).ShouldBe("5");
//"Ultimate" edition values
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.SocialLogins,
TestEditionIds.Ultimate
)).ShouldBe(true.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.DailyAnalysis,
TestEditionIds.Ultimate
)).ShouldBe(true.ToString().ToLowerInvariant());
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.ProjectCount,
TestEditionIds.Ultimate
)).ShouldBe("10");
(await _featureManager.GetOrNullForEditionAsync(
TestFeatureDefinitionProvider.BackupCount,
TestEditionIds.Ultimate
)).ShouldBe("10");
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse();
}
[Fact]
public async Task Should_Change_Feature_Value_And_Refresh_Cache()
//Set to "True" by host for the tenant
using (_currentTenant.Change(null))
{
var tenantId = Guid.NewGuid();
//It is "False" at the beginning
using (_currentTenant.Change(tenantId))
{
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse();
}
//Set to "True" by host for the tenant
using (_currentTenant.Change(null))
{
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse();
await _featureManager.SetForTenantAsync(tenantId, TestFeatureDefinitionProvider.SocialLogins, "True");
(await _featureManager.GetOrNullForTenantAsync(TestFeatureDefinitionProvider.SocialLogins, tenantId)).ShouldBe("True");
}
//Now, it should be "True"
using (_currentTenant.Change(tenantId))
{
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeTrue();
}
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeFalse();
await _featureManager.SetForTenantAsync(tenantId, TestFeatureDefinitionProvider.SocialLogins, "True");
(await _featureManager.GetOrNullForTenantAsync(TestFeatureDefinitionProvider.SocialLogins, tenantId)).ShouldBe("True");
}
[Fact]
public async Task Should_Get_FeatureValues_With_Provider_For_A_Provider()
//Now, it should be "True"
using (_currentTenant.Change(tenantId))
{
var featureNameValueWithGrantedProviders = await _featureManager.GetAllWithProviderAsync(
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.SocialLogins
&& x.Value == true.ToString().ToLowerInvariant() &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.EmailSupport &&
x.Value == true.ToString().ToLowerInvariant() &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
//Default Value
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.DailyAnalysis &&
x.Value == false.ToString().ToLowerInvariant() &&
x.Provider.Name == DefaultValueFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.UserCount &&
x.Value == "20" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.ProjectCount &&
x.Value == "3" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.BackupCount &&
x.Value == "5" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
(await _featureChecker.IsEnabledAsync(TestFeatureDefinitionProvider.SocialLogins)).ShouldBeTrue();
}
}
[Fact]
public async Task Should_Get_FeatureValues_With_Provider_For_A_Provider()
{
var featureNameValueWithGrantedProviders = await _featureManager.GetAllWithProviderAsync(
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.SocialLogins
&& x.Value == true.ToString().ToLowerInvariant() &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.EmailSupport &&
x.Value == true.ToString().ToLowerInvariant() &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
//Default Value
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.DailyAnalysis &&
x.Value == false.ToString().ToLowerInvariant() &&
x.Provider.Name == DefaultValueFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.UserCount &&
x.Value == "20" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.ProjectCount &&
x.Value == "3" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
featureNameValueWithGrantedProviders.ShouldContain(x =>
x.Name == TestFeatureDefinitionProvider.BackupCount &&
x.Value == "5" &&
x.Provider.Name == EditionFeatureValueProvider.ProviderName);
}
}

126
modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator_Tests.cs

@ -1,32 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Caching;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Settings;
using Xunit;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureValueCacheItemInvalidator_Tests : FeatureManagementTestBase<AbpFeatureManagementDomainTestModule>
{
public class FeatureValueCacheItemInvalidator_Tests : FeatureManagementTestBase<AbpFeatureManagementDomainTestModule>
private IDistributedCache<FeatureValueCacheItem> _cache;
private IFeatureValueRepository _featureValueRepository;
private IFeatureManagementStore _featureManagementStore;
private ICurrentTenant _currentTenant;
public FeatureValueCacheItemInvalidator_Tests()
{
private IDistributedCache<FeatureValueCacheItem> _cache;
private IFeatureValueRepository _featureValueRepository;
private IFeatureManagementStore _featureManagementStore;
private ICurrentTenant _currentTenant;
public FeatureValueCacheItemInvalidator_Tests()
{
_cache = GetRequiredService<IDistributedCache<FeatureValueCacheItem>>();
_featureValueRepository = GetRequiredService<IFeatureValueRepository>();
_featureManagementStore = GetRequiredService<IFeatureManagementStore>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
_cache = GetRequiredService<IDistributedCache<FeatureValueCacheItem>>();
_featureValueRepository = GetRequiredService<IFeatureValueRepository>();
_featureManagementStore = GetRequiredService<IFeatureManagementStore>();
_currentTenant = GetRequiredService<ICurrentTenant>();
}
[Fact]
public async Task Cache_Should_Invalidator_WhenFeatureChanged()
{
// Arrange cache feature.
(await _featureManagementStore.GetOrNullAsync(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
).ShouldNotBeNull();
var feature = await _featureValueRepository.FindAsync(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
);
[Fact]
public async Task Cache_Should_Invalidator_WhenFeatureChanged()
// Act
await _featureValueRepository.DeleteAsync(feature);
// Assert
(await _cache.GetAsync(
FeatureValueCacheItem.CalculateCacheKey(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
)
).ShouldBeNull();
}
[Fact]
public async Task Cache_Should_Invalidator_WhenSettingChanged_Between_Tenant_And_Host()
{
var tenantId = Guid.NewGuid();
using (_currentTenant.Change(tenantId))
{
// Arrange cache feature.
(await _featureManagementStore.GetOrNullAsync(
@ -35,17 +68,19 @@ namespace Volo.Abp.FeatureManagement
TestEditionIds.Regular.ToString()
)
).ShouldNotBeNull();
}
var feature = await _featureValueRepository.FindAsync(
TestFeatureDefinitionProvider.SocialLogins,
using (_currentTenant.Change(null))
{
await _featureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins,
false.ToString(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
);
// Act
await _featureValueRepository.DeleteAsync(feature);
TestEditionIds.Regular.ToString());
}
// Assert
using (_currentTenant.Change(tenantId))
{
// Arrange cache feature.
(await _cache.GetAsync(
FeatureValueCacheItem.CalculateCacheKey(
TestFeatureDefinitionProvider.SocialLogins,
@ -55,44 +90,5 @@ namespace Volo.Abp.FeatureManagement
)
).ShouldBeNull();
}
[Fact]
public async Task Cache_Should_Invalidator_WhenSettingChanged_Between_Tenant_And_Host()
{
var tenantId = Guid.NewGuid();
using (_currentTenant.Change(tenantId))
{
// Arrange cache feature.
(await _featureManagementStore.GetOrNullAsync(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
).ShouldNotBeNull();
}
using (_currentTenant.Change(null))
{
await _featureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins,
false.ToString(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
}
using (_currentTenant.Change(tenantId))
{
// Arrange cache feature.
(await _cache.GetAsync(
FeatureValueCacheItem.CalculateCacheKey(
TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
)
).ShouldBeNull();
}
}
}
}

53
modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo/Abp/FeatureManagement/EntityFrameworkCore/AbpFeatureManagementEntityFrameworkCoreTestModule.cs

@ -6,38 +6,37 @@ using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Sqlite;
using Volo.Abp.Modularity;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
[DependsOn(
typeof(FeatureManagementTestBaseModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqliteModule)
)]
public class AbpFeatureManagementEntityFrameworkCoreTestModule : AbpModule
{
[DependsOn(
typeof(FeatureManagementTestBaseModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqliteModule)
)]
public class AbpFeatureManagementEntityFrameworkCoreTestModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var sqliteConnection = CreateDatabaseAndGetConnection();
var sqliteConnection = CreateDatabaseAndGetConnection();
Configure<AbpDbContextOptions>(options =>
Configure<AbpDbContextOptions>(options =>
{
options.Configure(abpDbContextConfigurationContext =>
{
options.Configure(abpDbContextConfigurationContext =>
{
abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection);
});
abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection);
});
}
private static SqliteConnection CreateDatabaseAndGetConnection()
{
var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
});
}
private static SqliteConnection CreateDatabaseAndGetConnection()
{
var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
new FeatureManagementDbContext(
new DbContextOptionsBuilder<FeatureManagementDbContext>().UseSqlite(connection).Options
).GetService<IRelationalDatabaseCreator>().CreateTables();
new FeatureManagementDbContext(
new DbContextOptionsBuilder<FeatureManagementDbContext>().UseSqlite(connection).Options
).GetService<IRelationalDatabaseCreator>().CreateTables();
return connection;
}
return connection;
}
}

9
modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureManagementStore_Tests.cs

@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
public class FeatureManagementStore_Tests : FeatureManagementStore_Tests<AbpFeatureManagementEntityFrameworkCoreTestModule>
{
public class FeatureManagementStore_Tests : FeatureManagementStore_Tests<AbpFeatureManagementEntityFrameworkCoreTestModule>
{
}
}

7
modules/feature-management/test/Volo.Abp.FeatureManagement.EntityFrameworkCore.Tests/Volo/Abp/FeatureManagement/EntityFrameworkCore/FeatureValueRepositoryTests.cs

@ -1,7 +1,6 @@
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore
namespace Volo.Abp.FeatureManagement.EntityFrameworkCore;
public class FeatureValueRepositoryTests : FeatureValueRepository_Tests<AbpFeatureManagementEntityFrameworkCoreTestModule>
{
public class FeatureValueRepositoryTests : FeatureValueRepository_Tests<AbpFeatureManagementEntityFrameworkCoreTestModule>
{
}
}

34
modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/AbpFeatureManagementMongoDbTestModule.cs

@ -1,27 +1,25 @@
using System;
using Volo.Abp.Data;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[DependsOn(
typeof(FeatureManagementTestBaseModule),
typeof(AbpFeatureManagementMongoDbModule)
)]
public class AbpFeatureManagementMongoDbTestModule : AbpModule
{
[DependsOn(
typeof(FeatureManagementTestBaseModule),
typeof(AbpFeatureManagementMongoDbModule)
)]
public class AbpFeatureManagementMongoDbTestModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var stringArray = MongoDbFixture.ConnectionString.Split('?');
var connectionString = stringArray[0].EnsureEndsWith('/') +
"Db_" +
Guid.NewGuid().ToString("N") + "/?" + stringArray[1];
var stringArray = MongoDbFixture.ConnectionString.Split('?');
var connectionString = stringArray[0].EnsureEndsWith('/') +
"Db_" +
Guid.NewGuid().ToString("N") + "/?" + stringArray[1];
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = connectionString;
});
}
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = connectionString;
});
}
}

9
modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/FeatureManagementStore_Tests.cs

@ -1,10 +1,9 @@
using Xunit;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[Collection(MongoTestCollection.Name)]
public class FeatureManagementStore_Tests : FeatureManagementStore_Tests<AbpFeatureManagementMongoDbTestModule>
{
[Collection(MongoTestCollection.Name)]
public class FeatureManagementStore_Tests : FeatureManagementStore_Tests<AbpFeatureManagementMongoDbTestModule>
{
}
}

9
modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/FeatureValueRepositoryTests.cs

@ -1,10 +1,9 @@
using Xunit;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[Collection(MongoTestCollection.Name)]
public class FeatureValueRepositoryTests : FeatureValueRepository_Tests<AbpFeatureManagementMongoDbTestModule>
{
[Collection(MongoTestCollection.Name)]
public class FeatureValueRepositoryTests : FeatureValueRepository_Tests<AbpFeatureManagementMongoDbTestModule>
{
}
}

27
modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoDbFixture.cs

@ -1,22 +1,21 @@
using System;
using Mongo2Go;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
public class MongoDbFixture : IDisposable
{
public class MongoDbFixture : IDisposable
{
private static readonly MongoDbRunner MongoDbRunner;
public static readonly string ConnectionString;
private static readonly MongoDbRunner MongoDbRunner;
public static readonly string ConnectionString;
static MongoDbFixture()
{
MongoDbRunner = MongoDbRunner.Start(singleNodeReplSet: true, singleNodeReplSetWaitTimeout: 20);
ConnectionString = MongoDbRunner.ConnectionString;
}
static MongoDbFixture()
{
MongoDbRunner = MongoDbRunner.Start(singleNodeReplSet: true, singleNodeReplSetWaitTimeout: 20);
ConnectionString = MongoDbRunner.ConnectionString;
}
public void Dispose()
{
MongoDbRunner?.Dispose();
}
public void Dispose()
{
MongoDbRunner?.Dispose();
}
}

13
modules/feature-management/test/Volo.Abp.FeatureManagement.MongoDB.Tests/Volo/Abp/FeatureManagement/MongoDB/MongoTestCollection.cs

@ -1,10 +1,9 @@
using Xunit;
namespace Volo.Abp.FeatureManagement.MongoDB
namespace Volo.Abp.FeatureManagement.MongoDB;
[CollectionDefinition(Name)]
public class MongoTestCollection : ICollectionFixture<MongoDbFixture>
{
[CollectionDefinition(Name)]
public class MongoTestCollection : ICollectionFixture<MongoDbFixture>
{
public const string Name = "MongoDB Collection";
}
}
public const string Name = "MongoDB Collection";
}

195
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementStore_Tests.cs

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Features;
@ -8,103 +6,127 @@ using Volo.Abp.Modularity;
using Volo.Abp.Uow;
using Xunit;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class FeatureManagementStore_Tests<TStartupModule> : FeatureManagementTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
public abstract class FeatureManagementStore_Tests<TStartupModule> : FeatureManagementTestBase<TStartupModule>
where TStartupModule : IAbpModule
private IFeatureManagementStore FeatureManagementStore { get; set; }
private IFeatureValueRepository FeatureValueRepository { get; set; }
private IUnitOfWorkManager UnitOfWorkManager { get; set; }
protected FeatureManagementStore_Tests()
{
private IFeatureManagementStore FeatureManagementStore { get; set; }
private IFeatureValueRepository FeatureValueRepository { get; set; }
private IUnitOfWorkManager UnitOfWorkManager { get; set; }
FeatureManagementStore = GetRequiredService<IFeatureManagementStore>();
FeatureValueRepository = GetRequiredService<IFeatureValueRepository>();
UnitOfWorkManager = GetRequiredService<IUnitOfWorkManager>();
}
protected FeatureManagementStore_Tests()
{
FeatureManagementStore = GetRequiredService<IFeatureManagementStore>();
FeatureValueRepository = GetRequiredService<IFeatureValueRepository>();
UnitOfWorkManager = GetRequiredService<IUnitOfWorkManager>();
}
[Fact]
public async Task GetOrNullAsync()
{
// Act
(await FeatureManagementStore.GetOrNullAsync(Guid.NewGuid().ToString(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
}
[Fact]
public async Task GetOrNullAsync()
{
// Act
(await FeatureManagementStore.GetOrNullAsync(Guid.NewGuid().ToString(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
[Fact]
public async Task Should_Get_Null_Where_Feature_Deleted()
{
// Arrange
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
// Act
await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
// Assert
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
}
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
}
[Fact]
public async Task SetAsync()
{
// Arrange
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).Value.ShouldBe(true.ToString().ToLowerInvariant());
// Act
await FeatureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins,
false.ToString().ToUpperInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
// Assert
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).Value.ShouldBe(false.ToString().ToUpperInvariant());
}
[Fact]
public async Task Should_Get_Null_Where_Feature_Deleted()
[Fact]
public async Task Set_In_UnitOfWork_Should_Be_Consistent()
{
using (UnitOfWorkManager.Begin())
{
// Arrange
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
// Act
await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins,
await FeatureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins,
false.ToString().ToUpperInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
// Assert
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
TestEditionIds.Regular.ToString())).ShouldBe(false.ToString().ToUpperInvariant());
}
}
[Fact]
public async Task SetAsync()
{
// Arrange
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).Value.ShouldBe(true.ToString().ToLowerInvariant());
[Fact]
public async Task DeleteAsync()
{
// Arrange
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
// Act
await FeatureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins,
false.ToString().ToUpperInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
// Act
await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
// Assert
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).Value.ShouldBe(false.ToString().ToUpperInvariant());
}
[Fact]
public async Task Set_In_UnitOfWork_Should_Be_Consistent()
{
using (UnitOfWorkManager.Begin())
{
// Arrange
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
// Act
await FeatureManagementStore.SetAsync(TestFeatureDefinitionProvider.SocialLogins,
false.ToString().ToUpperInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
// Assert
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBe(false.ToString().ToUpperInvariant());
}
}
// Assert
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
}
[Fact]
public async Task DeleteAsync()
[Fact]
public async Task Delete_In_UnitOfWork_Should_Be_Consistent()
{
using (var uow = UnitOfWorkManager.Begin())
{
// Arrange
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
@ -113,37 +135,12 @@ namespace Volo.Abp.FeatureManagement
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
await uow.SaveChangesAsync();
// Assert
(await FeatureValueRepository.FindAsync(TestFeatureDefinitionProvider.SocialLogins,
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
}
[Fact]
public async Task Delete_In_UnitOfWork_Should_Be_Consistent()
{
using (var uow = UnitOfWorkManager.Begin())
{
// Arrange
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldNotBeNull();
// Act
await FeatureManagementStore.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString());
await uow.SaveChangesAsync();
// Assert
(await FeatureManagementStore.GetOrNullAsync(TestFeatureDefinitionProvider.SocialLogins,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString())).ShouldBeNull();
}
}
}
}

13
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBase.cs

@ -1,14 +1,13 @@
using Volo.Abp.Modularity;
using Volo.Abp.Testing;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class FeatureManagementTestBase<TStartupModule> : AbpIntegratedTest<TStartupModule>
where TStartupModule : IAbpModule
{
public abstract class FeatureManagementTestBase<TStartupModule> : AbpIntegratedTest<TStartupModule>
where TStartupModule : IAbpModule
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
options.UseAutofac();
}
}

55
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestBaseModule.cs

@ -5,43 +5,42 @@ using Volo.Abp.Features;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpTestBaseModule),
typeof(AbpAuthorizationModule),
typeof(AbpFeatureManagementDomainModule)
)]
public class FeatureManagementTestBaseModule : AbpModule
{
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpTestBaseModule),
typeof(AbpAuthorizationModule),
typeof(AbpFeatureManagementDomainModule)
)]
public class FeatureManagementTestBaseModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAlwaysAllowAuthorization();
}
context.Services.AddAlwaysAllowAuthorization();
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);
}
public override void PostConfigureServices(ServiceConfigurationContext context)
public override void PostConfigureServices(ServiceConfigurationContext context)
{
context.Services.Configure<FeatureManagementOptions>(options =>
{
context.Services.Configure<FeatureManagementOptions>(options =>
{
//TODO: Any value can pass. After completing the permission unit test, look at it again.
options.ProviderPolicies[EditionFeatureValueProvider.ProviderName] = EditionFeatureValueProvider.ProviderName;
});
}
});
}
private static void SeedTestData(ApplicationInitializationContext context)
private static void SeedTestData(ApplicationInitializationContext context)
{
using (var scope = context.ServiceProvider.CreateScope())
{
using (var scope = context.ServiceProvider.CreateScope())
{
AsyncHelper.RunSync(() => scope.ServiceProvider
.GetRequiredService<FeatureManagementTestDataBuilder>()
.BuildAsync());
}
AsyncHelper.RunSync(() => scope.ServiceProvider
.GetRequiredService<FeatureManagementTestDataBuilder>()
.BuildAsync());
}
}
}

9
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestData.cs

@ -1,10 +1,9 @@
using System;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementTestData : ISingletonDependency
{
public class FeatureManagementTestData : ISingletonDependency
{
public Guid User1Id { get; } = Guid.NewGuid();
}
public Guid User1Id { get; } = Guid.NewGuid();
}

369
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureManagementTestDataBuilder.cs

@ -3,191 +3,190 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
using Volo.Abp.Guids;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class FeatureManagementTestDataBuilder : ITransientDependency
{
public class FeatureManagementTestDataBuilder : ITransientDependency
private readonly IFeatureValueRepository _featureValueRepository;
private readonly IGuidGenerator _guidGenerator;
private readonly FeatureManagementTestData _testData;
public FeatureManagementTestDataBuilder(
IGuidGenerator guidGenerator,
FeatureManagementTestData testData,
IFeatureValueRepository featureValueRepository)
{
_guidGenerator = guidGenerator;
_testData = testData;
_featureValueRepository = featureValueRepository;
}
public async Task BuildAsync()
{
private readonly IFeatureValueRepository _featureValueRepository;
private readonly IGuidGenerator _guidGenerator;
private readonly FeatureManagementTestData _testData;
public FeatureManagementTestDataBuilder(
IGuidGenerator guidGenerator,
FeatureManagementTestData testData,
IFeatureValueRepository featureValueRepository)
{
_guidGenerator = guidGenerator;
_testData = testData;
_featureValueRepository = featureValueRepository;
}
public async Task BuildAsync()
{
#region "Regular" edition features
//SocialLogins
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.SocialLogins,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
);
//UserCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.UserCount,
"10",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
);
//ProjectCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.ProjectCount,
"1",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
);
#endregion
#region "Enterprise" edition features
//SocialLogins
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.SocialLogins,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//EmailSupport
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.EmailSupport,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//UserCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.UserCount,
"20",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//ProjectCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.ProjectCount,
"3",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//BackupCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.BackupCount,
"5",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
#endregion
#region "Ultimate" edition features
//SocialLogins
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.SocialLogins,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//EmailSupport
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.EmailSupport,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//EmailSupport
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.DailyAnalysis,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//UserCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.UserCount,
"100",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//ProjectCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.ProjectCount,
"10",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//BackupCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.BackupCount,
"10",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
#endregion
}
#region "Regular" edition features
//SocialLogins
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.SocialLogins,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
);
//UserCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.UserCount,
"10",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
);
//ProjectCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.ProjectCount,
"1",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Regular.ToString()
)
);
#endregion
#region "Enterprise" edition features
//SocialLogins
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.SocialLogins,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//EmailSupport
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.EmailSupport,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//UserCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.UserCount,
"20",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//ProjectCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.ProjectCount,
"3",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
//BackupCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.BackupCount,
"5",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
)
);
#endregion
#region "Ultimate" edition features
//SocialLogins
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.SocialLogins,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//EmailSupport
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.EmailSupport,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//EmailSupport
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.DailyAnalysis,
true.ToString().ToLowerInvariant(),
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//UserCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.UserCount,
"100",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//ProjectCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.ProjectCount,
"10",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
//BackupCount
await _featureValueRepository.InsertAsync(
new FeatureValue(
_guidGenerator.Create(),
TestFeatureDefinitionProvider.BackupCount,
"10",
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Ultimate.ToString()
)
);
#endregion
}
}
}

109
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs

@ -4,73 +4,72 @@ using Volo.Abp.Features;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public abstract class FeatureValueRepository_Tests<TStartupModule> : FeatureManagementTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
public abstract class FeatureValueRepository_Tests<TStartupModule> : FeatureManagementTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
protected IFeatureValueRepository Repository { get; set; }
protected IFeatureValueRepository Repository { get; set; }
protected FeatureValueRepository_Tests()
{
Repository = GetRequiredService<IFeatureValueRepository>();
}
protected FeatureValueRepository_Tests()
{
Repository = GetRequiredService<IFeatureValueRepository>();
}
[Fact]
public async Task FindAsync()
{
//feature value does exists
[Fact]
public async Task FindAsync()
{
//feature value does exists
var featureValue = await Repository.FindAsync(
TestFeatureDefinitionProvider.ProjectCount,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
var featureValue = await Repository.FindAsync(
TestFeatureDefinitionProvider.ProjectCount,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
featureValue.ShouldNotBeNull();
featureValue.Value.ShouldBe("3");
featureValue.ShouldNotBeNull();
featureValue.Value.ShouldBe("3");
//feature value does not exists
featureValue = await Repository.FindAsync(
TestFeatureDefinitionProvider.ProjectCount,
EditionFeatureValueProvider.ProviderName,
"undefined-edition-id"
);
//feature value does not exists
featureValue = await Repository.FindAsync(
TestFeatureDefinitionProvider.ProjectCount,
EditionFeatureValueProvider.ProviderName,
"undefined-edition-id"
);
featureValue.ShouldBeNull();
}
featureValue.ShouldBeNull();
}
[Fact]
public async Task FindAllAsync()
{
var featureValues = await Repository.FindAllAsync(
TestFeatureDefinitionProvider.ProjectCount,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
[Fact]
public async Task FindAllAsync()
{
var featureValues = await Repository.FindAllAsync(
TestFeatureDefinitionProvider.ProjectCount,
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
featureValues.Count.ShouldBe(1);
}
featureValues.Count.ShouldBe(1);
}
[Fact]
public async Task GetListAsync()
{
var featureValues = await Repository.GetListAsync(
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
[Fact]
public async Task GetListAsync()
{
var featureValues = await Repository.GetListAsync(
EditionFeatureValueProvider.ProviderName,
TestEditionIds.Enterprise.ToString()
);
featureValues.Count.ShouldBeGreaterThan(0);
featureValues.Count.ShouldBeGreaterThan(0);
featureValues.ShouldContain(
fv => fv.Name == TestFeatureDefinitionProvider.SocialLogins &&
fv.Value == "true"
);
featureValues.ShouldContain(
fv => fv.Name == TestFeatureDefinitionProvider.SocialLogins &&
fv.Value == "true"
);
featureValues.ShouldContain(
fv => fv.Name == TestFeatureDefinitionProvider.ProjectCount &&
fv.Value == "3"
);
}
featureValues.ShouldContain(
fv => fv.Name == TestFeatureDefinitionProvider.ProjectCount &&
fv.Value == "3"
);
}
}

25
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestEditionIds.cs

@ -1,18 +1,17 @@
using System;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public static class TestEditionIds
{
public static class TestEditionIds
{
public static Guid Regular { get; }
public static Guid Enterprise { get; }
public static Guid Ultimate { get; }
public static Guid Regular { get; }
public static Guid Enterprise { get; }
public static Guid Ultimate { get; }
static TestEditionIds()
{
Regular = Guid.Parse("532599ab-c0c0-4345-a04a-e322867b6e15");
Enterprise = Guid.Parse("27e50758-1feb-436a-be4f-cae8519e0cb2");
Ultimate = Guid.Parse("6ea78c22-be32-497e-aaba-a2332c564c5e");
}
static TestEditionIds()
{
Regular = Guid.Parse("532599ab-c0c0-4345-a04a-e322867b6e15");
Enterprise = Guid.Parse("27e50758-1feb-436a-be4f-cae8519e0cb2");
Ultimate = Guid.Parse("6ea78c22-be32-497e-aaba-a2332c564c5e");
}
}
}

93
modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/TestFeatureDefinitionProvider.cs

@ -1,54 +1,53 @@
using Volo.Abp.Features;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement;
public class TestFeatureDefinitionProvider : FeatureDefinitionProvider
{
public class TestFeatureDefinitionProvider : FeatureDefinitionProvider
public const string SocialLogins = "SocialLogins";
public const string EmailSupport = "EmailSupport";
public const string DailyAnalysis = "DailyAnalysis";
public const string UserCount = "UserCount";
public const string ProjectCount = "ProjectCount";
public const string BackupCount = "BackupCount";
public override void Define(IFeatureDefinitionContext context)
{
public const string SocialLogins = "SocialLogins";
public const string EmailSupport = "EmailSupport";
public const string DailyAnalysis = "DailyAnalysis";
public const string UserCount = "UserCount";
public const string ProjectCount = "ProjectCount";
public const string BackupCount = "BackupCount";
public override void Define(IFeatureDefinitionContext context)
{
var group = context.AddGroup("TestGroup");
group.AddFeature(
SocialLogins,
valueType: new ToggleStringValueType()
);
group.AddFeature(
EmailSupport,
valueType: new ToggleStringValueType()
);
group.AddFeature(
DailyAnalysis,
defaultValue: false.ToString().ToLowerInvariant(), //Optional, it is already false by default
valueType: new ToggleStringValueType()
);
group.AddFeature(
UserCount,
defaultValue: "1",
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1000))
);
group.AddFeature(
ProjectCount,
defaultValue: "1",
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10))
);
group.AddFeature(
BackupCount,
defaultValue: "0",
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 10))
);
}
var group = context.AddGroup("TestGroup");
group.AddFeature(
SocialLogins,
valueType: new ToggleStringValueType()
);
group.AddFeature(
EmailSupport,
valueType: new ToggleStringValueType()
);
group.AddFeature(
DailyAnalysis,
defaultValue: false.ToString().ToLowerInvariant(), //Optional, it is already false by default
valueType: new ToggleStringValueType()
);
group.AddFeature(
UserCount,
defaultValue: "1",
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1000))
);
group.AddFeature(
ProjectCount,
defaultValue: "1",
valueType: new FreeTextStringValueType(new NumericValueValidator(1, 10))
);
group.AddFeature(
BackupCount,
defaultValue: "0",
valueType: new FreeTextStringValueType(new NumericValueValidator(0, 10))
);
}
}

Loading…
Cancel
Save