diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7073e826e3..8ebcc32bfc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -48,7 +48,7 @@ permissions: jobs: build-test: runs-on: ubuntu-22.04 - timeout-minutes: 40 + timeout-minutes: 50 if: ${{ !github.event.pull_request.draft }} steps: - uses: actions/checkout@v2 diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs index 94822284f5..cdab8e74c8 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/EditionFeatureValueProvider.cs @@ -1,5 +1,7 @@ -using System.Security.Principal; +using System; +using System.Security.Principal; using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; namespace Volo.Abp.Features; @@ -12,15 +14,25 @@ public class EditionFeatureValueProvider : FeatureValueProvider protected ICurrentPrincipalAccessor PrincipalAccessor; - public EditionFeatureValueProvider(IFeatureStore featureStore, ICurrentPrincipalAccessor principalAccessor) + protected ITenantStore TenantStore { get; } + + protected ICurrentTenant CurrentTenant { get; } + + public EditionFeatureValueProvider( + IFeatureStore featureStore, + ICurrentPrincipalAccessor principalAccessor, + ITenantStore tenantStore, + ICurrentTenant currentTenant) : base(featureStore) { PrincipalAccessor = principalAccessor; + TenantStore = tenantStore; + CurrentTenant = currentTenant; } - public override async Task GetOrNullAsync(FeatureDefinition feature) + public async override Task GetOrNullAsync(FeatureDefinition feature) { - var editionId = PrincipalAccessor.Principal?.FindEditionId(); + var editionId = await FindEditionIdAsync(); if (editionId == null) { return null; @@ -28,4 +40,21 @@ public class EditionFeatureValueProvider : FeatureValueProvider return await FeatureStore.GetOrNullAsync(feature.Name, Name, editionId.Value.ToString()); } + + protected virtual async Task FindEditionIdAsync() + { + var editionId = PrincipalAccessor.Principal?.FindEditionId(); + if (editionId != null) + { + return editionId; + } + + if (CurrentTenant.Id == null) + { + return null; + } + + var tenant = await TenantStore.FindAsync(CurrentTenant.Id.Value); + return tenant?.EditionId; + } } diff --git a/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs b/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs index 29b0971708..674bce6e94 100644 --- a/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs +++ b/framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantConfiguration.cs @@ -17,6 +17,8 @@ public class TenantConfiguration public bool IsActive { get; set; } + public Guid? EditionId { get; set; } + public TenantConfiguration() { IsActive = true; @@ -33,11 +35,12 @@ public class TenantConfiguration ConnectionStrings = new ConnectionStrings(); } - public TenantConfiguration(Guid id, [NotNull] string name, [NotNull] string normalizedName) + public TenantConfiguration(Guid id, [NotNull] string name, [NotNull] string normalizedName, Guid? editionId = null) : this(id, name) { Check.NotNull(normalizedName, nameof(normalizedName)); NormalizedName = normalizedName; + EditionId = editionId; } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs index 82c1c98cb9..f9de4cbd1f 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/EditionFeatureManagementProvider.cs @@ -1,7 +1,9 @@ -using System.Security.Principal; +using System; +using System.Security.Principal; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; +using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; namespace Volo.Abp.FeatureManagement; @@ -11,22 +13,58 @@ public class EditionFeatureManagementProvider : FeatureManagementProvider, ITran public override string Name => EditionFeatureValueProvider.ProviderName; protected ICurrentPrincipalAccessor PrincipalAccessor { get; } + protected ITenantStore TenantStore { get; } + protected ICurrentTenant CurrentTenant { get; } + protected string CurrentCompatibleProviderName { get; set; } public EditionFeatureManagementProvider( IFeatureManagementStore store, - ICurrentPrincipalAccessor principalAccessor) + ICurrentPrincipalAccessor principalAccessor, + ITenantStore tenantStore, + ICurrentTenant currentTenant) : base(store) { PrincipalAccessor = principalAccessor; + TenantStore = tenantStore; + CurrentTenant = currentTenant; } - protected override Task NormalizeProviderKeyAsync(string providerKey) + public override bool Compatible(string providerName) { - if (providerKey != null) + CurrentCompatibleProviderName = providerName; + return providerName == TenantFeatureValueProvider.ProviderName || base.Compatible(providerName); + } + + protected async override Task NormalizeProviderKeyAsync(string providerKey) + { + return (await FindEditionIdAsync(providerKey))?.ToString(); + } + + protected virtual async Task FindEditionIdAsync(string providerKey) + { + if (Guid.TryParse(providerKey, out var parsedEditionOrTenantId)) + { + if (CurrentCompatibleProviderName == TenantFeatureValueProvider.ProviderName) + { + var tenant = await TenantStore.FindAsync(parsedEditionOrTenantId); + if (tenant != null) + { + return tenant?.EditionId; + } + } + + return parsedEditionOrTenantId; + } + + if (CurrentTenant.Id.HasValue) { - return Task.FromResult(providerKey); + var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()); + if (tenant != null) + { + return tenant?.EditionId; + } } - return Task.FromResult(PrincipalAccessor.Principal?.FindEditionId()?.ToString("N")); + return PrincipalAccessor.Principal?.FindEditionId(); } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs index 496095c807..6fe1edafc6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/AbpTenantManagementDomainMappingProfile.cs @@ -28,7 +28,8 @@ public class AbpTenantManagementDomainMappingProfile : Profile return connStrings; }); }) - .ForMember(x => x.IsActive, x => x.Ignore()); + .ForMember(x => x.IsActive, x => x.Ignore()) + .ForMember(x => x.EditionId, x => x.Ignore()); CreateMap(); }