Browse Source

Merge pull request #994 from colinin/fix-saas-jobs

Fix saas jobs
pull/1010/head
yx lin 1 year ago
committed by GitHub
parent
commit
47a955bd6d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      aspnet-core/LINGYUN.MicroService.SingleProject.sln
  2. 9
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleDbMigrationEventHandler.cs
  3. 2
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/AbpNotificationsApplicationAutoMapperProfile.cs
  4. 2
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/AbpNotificationsDomainAutoMapperProfile.cs
  5. 1
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/UserNotificationInfo.cs
  6. 9
      aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/EfCoreUserNotificationRepository.cs
  7. 49
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs
  8. 12
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs
  9. 4
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json
  10. 4
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json
  11. 14
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Features/SaasFeatureDefinitionProvider.cs

7
aspnet-core/LINGYUN.MicroService.SingleProject.sln

@ -537,6 +537,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.WeChat.Official
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.WeChat.Work.Handlers", "framework\wechat\LINGYUN.Abp.WeChat.Work.Handlers\LINGYUN.Abp.WeChat.Work.Handlers.csproj", "{DB80C55F-8B70-4840-942A-ED021ED88BD6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.MultiTenancy.Saas", "modules\saas\LINGYUN.Abp.MultiTenancy.Saas\LINGYUN.Abp.MultiTenancy.Saas.csproj", "{E3C07A77-EAF9-4A3F-8814-7D2F116C8E26}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1415,6 +1417,10 @@ Global
{DB80C55F-8B70-4840-942A-ED021ED88BD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB80C55F-8B70-4840-942A-ED021ED88BD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB80C55F-8B70-4840-942A-ED021ED88BD6}.Release|Any CPU.Build.0 = Release|Any CPU
{E3C07A77-EAF9-4A3F-8814-7D2F116C8E26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3C07A77-EAF9-4A3F-8814-7D2F116C8E26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3C07A77-EAF9-4A3F-8814-7D2F116C8E26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3C07A77-EAF9-4A3F-8814-7D2F116C8E26}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1677,6 +1683,7 @@ Global
{4634B421-36E6-4169-AA1A-11050902495F} = {D94D6AFE-20BD-4F21-8708-03F5E34F49FC}
{BB2DF96A-6ED8-4F47-948C-230EA2065C4C} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
{DB80C55F-8B70-4840-942A-ED021ED88BD6} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
{E3C07A77-EAF9-4A3F-8814-7D2F116C8E26} = {ECE6E6D7-A4F6-4F50-BC21-AE2EB14A3129}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}

9
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleDbMigrationEventHandler.cs

@ -3,6 +3,7 @@ using LINGYUN.Abp.BackgroundTasks.Internal;
using LINGYUN.Abp.Saas.Tenants;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -43,13 +44,19 @@ public class SingleDbMigrationEventHandler :
IGuidGenerator guidGenerator,
IdentityUserManager identityUserManager,
IdentityRoleManager identityRoleManager,
IPermissionDataSeeder permissionDataSeeder)
IPermissionDataSeeder permissionDataSeeder,
IJobStore jobStore,
IJobScheduler jobScheduler,
IOptions<AbpBackgroundTasksOptions> options)
: base("SingleDbMigrator", currentTenant, unitOfWorkManager, tenantStore, abpDistributedLock, distributedEventBus, loggerFactory)
{
GuidGenerator = guidGenerator;
IdentityUserManager = identityUserManager;
IdentityRoleManager = identityRoleManager;
PermissionDataSeeder = permissionDataSeeder;
JobStore = jobStore;
JobScheduler = jobScheduler;
Options = options.Value;
}
public async virtual Task HandleEventAsync(EntityDeletedEto<TenantEto> eventData)
{

2
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Application/LINGYUN/Abp/Notifications/AbpNotificationsApplicationAutoMapperProfile.cs

@ -8,7 +8,7 @@ public class AbpNotificationsApplicationAutoMapperProfile : Profile
public AbpNotificationsApplicationAutoMapperProfile()
{
CreateMap<UserNotificationInfo, UserNotificationDto>()
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.Id.ToString()))
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.NotificationId.ToString()))
.ForMember(dto => dto.Lifetime, map => map.Ignore())
.ForMember(dto => dto.Data, map => map.MapFrom((src, nfi) =>
{

2
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/AbpNotificationsDomainAutoMapperProfile.cs

@ -28,7 +28,7 @@ public class AbpNotificationsDomainAutoMapperProfile : Profile
}));
CreateMap<UserNotificationInfo, NotificationInfo>()
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.Id.ToString()))
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.NotificationId.ToString()))
.ForMember(dto => dto.Name, map => map.MapFrom(src => src.Name))
.ForMember(dto => dto.Lifetime, map => map.Ignore())
.ForMember(dto => dto.Type, map => map.MapFrom(src => src.Type))

1
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Domain/LINGYUN/Abp/Notifications/UserNotificationInfo.cs

@ -8,6 +8,7 @@ public class UserNotificationInfo
public Guid? TenantId { get; set; }
public string Name { get; set; }
public long Id { get; set; }
public long NotificationId { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public string NotificationTypeName { get; set; }
public DateTime CreationTime { get; set; }

9
aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.EntityFrameworkCore/LINGYUN/Abp/Notifications/EntityFrameworkCore/EfCoreUserNotificationRepository.cs

@ -47,7 +47,8 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
where n.NotificationId.Equals(notificationId)
select new UserNotificationInfo
{
Id = n.NotificationId,
Id = un.Id,
NotificationId = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
@ -89,7 +90,7 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
on un.NotificationId equals n.NotificationId
select new UserNotificationInfo
{
Id = n.NotificationId,
NotificationId = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
@ -121,7 +122,7 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
where un.UserId == userId
select new UserNotificationInfo
{
Id = n.NotificationId,
NotificationId = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
@ -170,7 +171,7 @@ public class EfCoreUserNotificationRepository : EfCoreRepository<INotificationsD
where un.UserId == userId
select new UserNotificationInfo
{
Id = n.NotificationId,
NotificationId = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,

49
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs

@ -1,5 +1,6 @@
using LINGYUN.Abp.Saas.Features;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
@ -8,7 +9,6 @@ using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
@ -20,15 +20,18 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
protected IDistributedEventBus EventBus { get; }
protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; }
protected IConnectionStringChecker ConnectionStringChecker { get; }
public TenantAppService(
ITenantRepository tenantRepository,
ITenantManager tenantManager,
IDistributedEventBus eventBus)
IDistributedEventBus eventBus,
IConnectionStringChecker connectionStringChecker)
{
EventBus = eventBus;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
ConnectionStringChecker = connectionStringChecker;
}
public async virtual Task<TenantDto> GetAsync(Guid id)
@ -80,6 +83,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
if (!input.UseSharedDatabase && !input.DefaultConnectionString.IsNullOrWhiteSpace())
{
await CheckConnectionString(input.DefaultConnectionString);
tenant.SetDefaultConnectionString(input.DefaultConnectionString);
}
@ -87,6 +91,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
{
foreach (var connectionString in input.ConnectionStrings)
{
await CheckConnectionString(connectionString.Value, connectionString.Key);
tenant.SetConnectionString(connectionString.Key, connectionString.Value);
}
}
@ -119,6 +124,7 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
await EventBus.PublishAsync(eto);
});
await CurrentUnitOfWork.SaveChangesAsync();
return ObjectMapper.Map<Tenant, TenantDto>(tenant);
@ -157,12 +163,17 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
}
// 租户删除时查询会失效, 在删除前确认
var strategy = await FeatureChecker.GetAsync(SaasFeatureNames.Tenant.RecycleStrategy, RecycleStrategy.Recycle);
var recycleStrategy = RecycleStrategy.Recycle;
var strategySet = await FeatureChecker.GetOrNullAsync(SaasFeatureNames.Tenant.RecycleStrategy);
if (!strategySet.IsNullOrWhiteSpace() && Enum.TryParse<RecycleStrategy>(strategySet, out var strategy))
{
recycleStrategy = strategy;
}
var eto = new TenantDeletedEto
{
Id = tenant.Id,
Name = tenant.Name,
Strategy = strategy,
Strategy = recycleStrategy,
EntityVersion = tenant.EntityVersion,
DefaultConnectionString = tenant.FindDefaultConnectionString(),
};
@ -259,4 +270,34 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService
await CurrentUnitOfWork.SaveChangesAsync();
}
protected async virtual Task CheckConnectionString(string connectionString, string name = null)
{
try
{
var checkResult = await ConnectionStringChecker.CheckAsync(connectionString);
// 检查连接是否可用
if (!checkResult.Connected)
{
throw name.IsNullOrWhiteSpace()
? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString)
: new BusinessException(AbpSaasErrorCodes.InvalidConnectionString)
.WithData("Name", name);
}
// 默认连接字符串改变不能影响到现有数据库
if (checkResult.DatabaseExists && name.IsNullOrWhiteSpace())
{
throw new BusinessException(AbpSaasErrorCodes.DefaultConnectionStringDatabaseExists);
}
}
catch (Exception e)
{
Logger.LogWarning("An error occurred while checking the validity of the connection string");
Logger.LogWarning(e.Message);
throw name.IsNullOrWhiteSpace()
? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString)
: new BusinessException(AbpSaasErrorCodes.InvalidConnectionString)
.WithData("Name", name);
}
}
}

12
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs

@ -7,4 +7,16 @@ public static class AbpSaasErrorCodes
public const string DuplicateEditionDisplayName = Namespace + ":010001";
public const string DeleteUsedEdition = Namespace + ":010002";
public const string DuplicateTenantName = Namespace + ":020001";
/// <summary>
/// 无效的默认连接字符串
/// </summary>
public const string InvalidDefaultConnectionString = Namespace + ":020101";
/// <summary>
/// 默认连接字符串指向的数据库已经存在
/// </summary>
public const string DefaultConnectionStringDatabaseExists = Namespace + ":020102";
/// <summary>
/// {Name} 的连接字符串无效
/// </summary>
public const string InvalidConnectionString = Namespace + ":020103";
}

4
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json

@ -4,7 +4,9 @@
"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}!",
"Saas:020002": "The database string that cannot be connected!",
"Saas:020101": "The default connection string cannot open a connection to the database!",
"Saas:020102": "The database pointed to by the default connection string already exists!",
"Saas:020103": "Unable to open the database connection pointed to by {Name}!",
"Volo.AbpIo.MultiTenancy:010001": "The tenant is unavailable or restricted!",
"Volo.AbpIo.MultiTenancy:010002": "Tenant unavailable!",
"Menu:Saas": "Saas",

4
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json

@ -4,7 +4,9 @@
"Saas:010001": "已经存在名为 {DisplayName} 的版本!",
"Saas:010002": "试图删除正在使用的版本: {DisplayName}!",
"Saas:020001": "已经存在名为 {Name} 的租户!",
"Saas:020002": "无法连接的数据库字符串!",
"Saas:020101": "无法打开默认连接字符串指向的数据库连接!",
"Saas:020102": "默认连接字符串指向的数据库已经存在!",
"Saas:020103": "无法打开 {Name} 指向的数据库连接!",
"Volo.AbpIo.MultiTenancy:010001": "租户不可用或受限制!",
"Volo.AbpIo.MultiTenancy:010002": "租户不可用!",
"Menu:Saas": "Saas",

14
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Features/SaasFeatureDefinitionProvider.cs

@ -18,22 +18,22 @@ public class SaasFeatureDefinitionProvider : FeatureDefinitionProvider
ItemSource = new StaticSelectionStringValueItemSource(
new LocalizableSelectionStringValueItem
{
Value = RecycleStrategy.Reserve.ToString(),
Value = "0",
DisplayText = new LocalizableStringInfo(
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Reserve")
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Reserve")
},
new LocalizableSelectionStringValueItem
{
Value = RecycleStrategy.Recycle.ToString(),
Value = "1",
DisplayText = new LocalizableStringInfo(
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Recycle")
LocalizationResourceNameAttribute.GetName(typeof(AbpSaasResource)),
"RecycleStrategy:Recycle")
})
};
saas.AddFeature(
name: SaasFeatureNames.Tenant.RecycleStrategy,
defaultValue: RecycleStrategy.Recycle.ToString(),
defaultValue: "1",
displayName: L("Features:RecycleStrategy"),
description: L("Features:RecycleStrategyDesc"),
valueType: selectionValueType,

Loading…
Cancel
Save