From a2905dae7d0439ee1da5984a703f5675ea3314f6 Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Fri, 11 Mar 2022 16:59:52 +0800 Subject: [PATCH] feat(saas): add validation before version changes --- .../Abp/Saas/Editions/EditionAppService.cs | 15 +++++----- .../Abp/Saas/Tenants/TenantAppService.cs | 30 +++++-------------- .../LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs | 1 + .../Abp/Saas/Localization/Resources/en.json | 1 + .../Saas/Localization/Resources/zh-Hans.json | 1 + .../Abp/Saas/Editions/EditionManager.cs | 11 ++++++- .../Abp/Saas/Editions/IEditionRepository.cs | 4 +++ .../Tenants/TenantCacheItemInvalidator.cs | 7 +++-- .../EfCoreEditionRepository.cs | 11 +++++++ 9 files changed, 48 insertions(+), 33 deletions(-) diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Editions/EditionAppService.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Editions/EditionAppService.cs index 002a75667..0fe455926 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Editions/EditionAppService.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Editions/EditionAppService.cs @@ -37,12 +37,9 @@ public class EditionAppService : AbpSaasAppServiceBase, IEditionAppService [Authorize(AbpSaasPermissions.Editions.Delete)] public async virtual Task DeleteAsync(Guid id) { - var edition = await EditionRepository.FindAsync(id); - if (edition == null) - { - return; - } - await EditionRepository.DeleteAsync(edition); + var edition = await EditionRepository.GetAsync(id); + + await EditionManager.DeleteAsync(edition); } public async virtual Task GetAsync(Guid id) @@ -73,7 +70,11 @@ public class EditionAppService : AbpSaasAppServiceBase, IEditionAppService { var edition = await EditionRepository.GetAsync(id, false); - await EditionManager.ChangeDisplayNameAsync(edition, input.DisplayName); + if (!string.Equals(edition.DisplayName, input.DisplayName)) + { + await EditionManager.ChangeDisplayNameAsync(edition, input.DisplayName); + } + input.MapExtraPropertiesTo(edition); await EditionRepository.UpdateAsync(edition); diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs index 5efafc593..123bcfb12 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs @@ -1,5 +1,4 @@ using LINGYUN.Abp.MultiTenancy; -using LINGYUN.Abp.Saas.Editions; using Microsoft.AspNetCore.Authorization; using System; using System.Collections.Generic; @@ -16,19 +15,16 @@ namespace LINGYUN.Abp.Saas.Tenants; public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService { protected IDistributedEventBus EventBus { get; } - protected IEditionRepository EditionRepository { get; } protected ITenantRepository TenantRepository { get; } protected ITenantManager TenantManager { get; } public TenantAppService( ITenantRepository tenantRepository, - IEditionRepository editionRepository, ITenantManager tenantManager, IDistributedEventBus eventBus) { EventBus = eventBus; TenantRepository = tenantRepository; - EditionRepository = editionRepository; TenantManager = tenantManager; } @@ -40,15 +36,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService throw new UserFriendlyException(L["TenantNotFoundById", id]); } - var tenantDto = ObjectMapper.Map(tenant); - if (tenant.EditionId.HasValue) - { - var edition = await EditionRepository.GetAsync(tenant.EditionId.Value); - tenantDto.EditionId = edition.Id; - tenantDto.EditionName = edition.DisplayName; - } - - return tenantDto; + return ObjectMapper.Map(tenant); } public virtual async Task GetAsync(string name) @@ -58,15 +46,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService { throw new UserFriendlyException(L["TenantNotFoundByName", name]); } - var tenantDto = ObjectMapper.Map(tenant); - if (tenant.EditionId.HasValue) - { - var edition = await EditionRepository.GetAsync(tenant.EditionId.Value); - tenantDto.EditionId = edition.Id; - tenantDto.EditionName = edition.DisplayName; - } - - return tenantDto; + return ObjectMapper.Map(tenant); } public virtual async Task> GetListAsync(TenantGetListInput input) @@ -123,7 +103,11 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService { var tenant = await TenantRepository.GetAsync(id, false); - await TenantManager.ChangeNameAsync(tenant, input.Name); + if (!string.Equals(tenant.Name, input.Name)) + { + await TenantManager.ChangeNameAsync(tenant, input.Name); + } + tenant.IsActive = input.IsActive; tenant.EditionId = input.EditionId; input.MapExtraPropertiesTo(tenant); diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs index cf89a3ecf..ec33cb29b 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs @@ -5,5 +5,6 @@ public static class AbpSaasErrorCodes public const string Namespace = "Saas"; public const string DuplicateEditionDisplayName = Namespace + ":010001"; + public const string DeleteUsedEdition = Namespace + ":010002"; public const string DuplicateTenantName = Namespace + ":020001"; } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json index f3757db4c..e747c4e49 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json @@ -2,6 +2,7 @@ "culture": "en", "texts": { "Saas:010001": "Unable to create duplicate editions {DisplayName}!", + "Saas:010002": "Tried to delete the edition in use: {DisplayName}!", "Saas:020001": "Unable to create duplicate tenants {Name}!", "Volo.AbpIo.MultiTenancy:010001": "The tenant is unavailable or restricted!", "Volo.AbpIo.MultiTenancy:010002": "Tenant unavailable!", diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json index d358fdf14..0541d2a09 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json @@ -2,6 +2,7 @@ "culture": "zh-Hans", "texts": { "Saas:010001": "已经存在名为 {DisplayName} 的版本!", + "Saas:010002": "试图删除正在使用的版本: {DisplayName}!", "Saas:020001": "已经存在名为 {Name} 的租户!", "Volo.AbpIo.MultiTenancy:010001": "租户不可用或受限制!", "Volo.AbpIo.MultiTenancy:010002": "租户不可用!", diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/EditionManager.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/EditionManager.cs index 29fc974e2..afb853111 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/EditionManager.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/EditionManager.cs @@ -12,10 +12,19 @@ public class EditionManager : DomainService public EditionManager(IEditionRepository editionRepository) { EditionRepository = editionRepository; + } + public async virtual Task DeleteAsync(Edition edition) + { + if (await EditionRepository.CheckUsedByTenantAsync(edition.Id)) + { + throw new BusinessException(AbpSaasErrorCodes.DeleteUsedEdition) + .WithData(nameof(Edition.DisplayName), edition.DisplayName); + } + await EditionRepository.DeleteAsync(edition); } - public virtual async Task CreateAsync(string displayName) + public async virtual Task CreateAsync(string displayName) { Check.NotNull(displayName, nameof(displayName)); diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/IEditionRepository.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/IEditionRepository.cs index 617cca768..1e7925d78 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/IEditionRepository.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Editions/IEditionRepository.cs @@ -8,6 +8,10 @@ namespace LINGYUN.Abp.Saas.Editions; public interface IEditionRepository : IBasicRepository { + Task CheckUsedByTenantAsync( + Guid id, + CancellationToken cancellationToken = default); + Task FindByDisplayNameAsync( string displayName, CancellationToken cancellationToken = default); diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs index 9f3f98992..c0630ddbf 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/TenantCacheItemInvalidator.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using LINGYUN.Abp.Saas.Editions; +using System.Threading.Tasks; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events; @@ -17,6 +18,8 @@ public class TenantCacheItemInvalidator : ILocalEventHandler eventData) { - await Cache.RemoveAsync(TenantCacheItem.CalculateCacheKey(eventData.Entity.Id, eventData.Entity.Name), considerUow: true); + await Cache.RemoveAsync(TenantCacheItem.CalculateCacheKey(eventData.Entity.Id, eventData.Entity.Name), considerUow: true); + // 同时移除租户版本缓存 + await Cache.RemoveAsync(EditionCacheItem.CalculateCacheKey(eventData.Entity.Id), considerUow: true); } } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.EntityFrameworkCore/LINGYUN/Abp/Saas/EntityFrameworkCore/EfCoreEditionRepository.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.EntityFrameworkCore/LINGYUN/Abp/Saas/EntityFrameworkCore/EfCoreEditionRepository.cs index 7f46ec71e..47f842214 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.EntityFrameworkCore/LINGYUN/Abp/Saas/EntityFrameworkCore/EfCoreEditionRepository.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.EntityFrameworkCore/LINGYUN/Abp/Saas/EntityFrameworkCore/EfCoreEditionRepository.cs @@ -20,6 +20,17 @@ public class EfCoreEditionRepository : EfCoreRepository CheckUsedByTenantAsync( + Guid id, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + var tenantDbSet = dbContext.Set(); + + return await tenantDbSet + .AnyAsync(x => x.EditionId == id, GetCancellationToken(cancellationToken)); + } + public async virtual Task FindByDisplayNameAsync( string displayName, CancellationToken cancellationToken = default)