diff --git a/aspnet-core/configuration/AuthServer.Host/appsettings.Development.json b/aspnet-core/configuration/AuthServer.Host/appsettings.Development.json new file mode 100644 index 000000000..aa82f1d34 --- /dev/null +++ b/aspnet-core/configuration/AuthServer.Host/appsettings.Development.json @@ -0,0 +1,141 @@ +{ + "App": { + "SelfUrl": "http://localhost:44385/", + "CorsOrigins": "http://localhost:4200,http://localhost:9528,http://127.0.0.1:63898" + }, + "AppSelfUrl": "http://localhost:44385/", + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=IdentityServer;User Id=root;Password=123456", + "AbpIdentity": "Server=127.0.0.1;Database=IdentityServer;User Id=root;Password=123456", + "AbpIdentityServer": "Server=127.0.0.1;Database=IdentityServer;User Id=root;Password=123456", + "AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" + }, + "Identity": { + "Password": { + "RequiredLength": 6, + "RequiredUniqueChars": 0, + "RequireNonAlphanumeric": false, + "RequireLowercase": false, + "RequireUppercase": false, + "RequireDigit": false + }, + "Lockout": { + "AllowedForNewUsers": false, + "LockoutDuration": 5, + "MaxFailedAccessAttempts": 5 + }, + "SignIn": { + "RequireConfirmedEmail": false, + "RequireConfirmedPhoneNumber": false + } + }, + "CAP": { + "EventBus": { + "DefaultGroup": "AuthServer", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "admin", + "ExchangeName": "LINGYUN.AbpApplication", + "VirtualHost": "multi.service.test" + } + }, + "RedisCache": { + "ConnectString": "127.0.0.1", + "RedisPrefix": "AuthServer" + }, + "AuthServer": { + "Authority": "http://localhost:44385/", + "ApiName": "auth-service" + }, + "WeChat": { + "Auth": { + "AppId": "微信AppId", + "AppSecret": "微信AppSecret" + }, + "Signature": { + "RequestPath": "微信开发者中心填写的验证地址", + "Token": "微信开发者中心填写的Token" + } + }, + "IdentityServer": { + "Clients": { + "AuthManagement": { + "ClientId": "auth-management", + "RootUrl": "http://localhost:44313/" + }, + "AuthVueAdmin": { + "ClientId": "vue-admin-element" + }, + "AuthApiGateway": { + "ClientId": "apigateway-host-client" + } + } + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "DotNetCore": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/configuration/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json new file mode 100644 index 000000000..74da04c9c --- /dev/null +++ b/aspnet-core/configuration/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json @@ -0,0 +1,110 @@ +{ + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=Messages;User Id=root;Password=123456", + "MessageService": "Server=127.0.0.1;Database=Messages;User Id=root;Password=123456", + "AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" + }, + "RedisCache": { + "RedisPrefix": "Platform_Test_Cache", + "ConnectString": "127.0.0.1" + }, + "AuthServer": { + "Authority": "http://localhost:44385/", + "ApiName": "auth-service" + }, + "Hangfire": { + "MySql": { + "Connection": "Server=127.0.0.1;Database=Messages;User Id=root;Password=123456;Allow User Variables=true", + "TablePrefix": "AppHangfire" + } + }, + "WeChat": { + "Auth": { + "AppId": "你自己的微信AppId", + "AppSecret": "你自己的微信AppSecret" + } + }, + "Notifications": { + "WeChat": { + "WeApp": { + "DefaultWeAppState": "formal" + } + } + }, + "CAP": { + "EventBus": { + "DefaultGroup": "MessageService", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "admin", + "ExchangeName": "LINGYUN.AbpApplication", + "VirtualHost": "multi.service.test" + } + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft.EntityFrameworkCore": "Debug", + "System": "Warning", + "Microsoft": "Warning" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/configuration/LINGYUN.ApiGateway.Host/appsettings.Development.json b/aspnet-core/configuration/LINGYUN.ApiGateway.Host/appsettings.Development.json new file mode 100644 index 000000000..dd7fb47b7 --- /dev/null +++ b/aspnet-core/configuration/LINGYUN.ApiGateway.Host/appsettings.Development.json @@ -0,0 +1,102 @@ +{ + "ApiGateway": { + "AppId": "TEST-APP"//这里是用于Ocelot主机去API服务器获取参数的标识,指定需要获取什么类型的网关配置 + }, + "RemoteServices": { + "ApiGateway": { + "BaseUrl": "http://localhost:30001/",//Ocelot Api代理地址,参见Volo.Abp.HttpClient + "IdentityClient": "apigateway-host-client" + } + }, + "IdentityClients": {//这里是用于Ocelot主机去API服务器获取参数授权用的,参见Volo.Abp.HttpClient.IdentityModel + "apigateway-host-client": { + "Authority": "http://localhost:44385", + "RequireHttps": false, + "GrantType": "client_credentials", + "ClientId": "apigateway-host-client", + "Scope": "apigateway-service", + "ClientSecret": "1q2w3e*", + "UserName": "ocelotHost", + "UserPassword": "Ocelot1." + } + }, + "EnabledDynamicOcelot": true, + "CAP": { + "EventBus": { + "DefaultGroup": "ApiGateway-Host", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "admin", + "ExchangeName": "LINGYUN.ApiGateway", + "VirtualHost": "multi.service.test" + } + }, + "AuthServer": { + "Host": "http://localhost:44385/",//填写你的IdentityServer服务器地址 + "ApiName": "apigateway-service",//填写你的IdentityServer服务器注册的ApiName + "ApiSecret": "defj98734htgrb90365D23"//填写你的IdentityServer服务器注册的ApiSecret + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "System": "Warning", + "Microsoft": "Warning" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/configuration/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json new file mode 100644 index 000000000..e5e3214da --- /dev/null +++ b/aspnet-core/configuration/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json @@ -0,0 +1,91 @@ +{ + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=ApiGateway;User Id=root;Password=123456", + "ApiGateway": "Server=127.0.0.1;Database=ApiGateway;User Id=root;Password=123456", + "AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" + }, + "RedisCache": { + "RedisPrefix": "ApiGateway_Test_Cache", + "ConnectString": "127.0.0.1" + }, + "CAP": { + "EventBus": { + "DefaultGroup": "ApiGateway-Admin", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "admin", + "ExchangeName": "LINGYUN.ApiGateway", + "VirtualHost": "multi.service.test" + } + }, + "AuthServer": { + "Host": "http://localhost:44385/", + "ApiName": "apigateway-service", + "ApiSecret": "defj98734htgrb90365D23" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "System": "Warning", + "Microsoft": "Warning" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/configuration/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json new file mode 100644 index 000000000..00787b7a2 --- /dev/null +++ b/aspnet-core/configuration/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json @@ -0,0 +1,133 @@ +{ + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpIdentity": "Server=127.0.0.1;Database=IdentityServer;User Id=root;Password=123456", + "AbpIdentityServer": "Server=127.0.0.1;Database=IdentityServer;User Id=root;Password=123456", + "AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" + }, + "Location": { + "Baidu": { + "AccessKey": "你自己的百度地图WebAPI Key", + "ExtensionsRoad": true, + "ExtensionsTown": true, + "ExtensionsPoi": "1", + "VisableErrorToClient": true + } + }, + "Aliyun": { + "Sms": { + "RegionId": "cn-hangzhou", + "Domain": "dysmsapi.aliyuncs.com", + "Version": "2017-05-25", + "AccessKeyId": "你自己的阿里云Sms服务Key", + "AccessKeySecret": "你自己的阿里云Sms服务KeySecret", + "DefaultSignName": "你自己的阿里云Sms服务签名", + "DefaultTemplateCode": "你自己的阿里云Sms服务模板", + "DeveloperPhoneNumber": "你自己的手机号码,用于开发模式统一接收短信的手机号", + "VisableErrorToClient": true + } + }, + "Identity": { + "Password": { + "RequiredLength": 6, + "RequiredUniqueChars": 0, + "RequireNonAlphanumeric": false, + "RequireLowercase": false, + "RequireUppercase": false, + "RequireDigit": false + }, + "Lockout": { + "AllowedForNewUsers": false, + "LockoutDuration": 5, + "MaxFailedAccessAttempts": 5 + }, + "SignIn": { + "RequireConfirmedEmail": false, + "RequireConfirmedPhoneNumber": false + } + }, + "CAP": { + "EventBus": { + "DefaultGroup": "Platform", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "admin", + "ExchangeName": "LINGYUN.AbpApplication", + "VirtualHost": "multi.service.test" + } + }, + "RedisCache": { + "RedisPrefix": "Platform_Test_Cache", + "ConnectString": "127.0.0.1" + }, + "AuthServer": { + "Authority": "http://localhost:44385/", + "ApiName": "auth-service" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft.EntityFrameworkCore": "Debug", + "System": "Warning", + "Microsoft": "Warning" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId" ], + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/RegisterVerifyDto.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/PhoneNumberRegisterDto.cs similarity index 95% rename from aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/RegisterVerifyDto.cs rename to aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/PhoneNumberRegisterDto.cs index 5de7157a2..cc12568bf 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/RegisterVerifyDto.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/PhoneNumberRegisterDto.cs @@ -4,7 +4,7 @@ using Volo.Abp.Identity; namespace LINGYUN.Abp.Account { - public class RegisterVerifyDto + public class PhoneNumberRegisterDto { [Required] [Phone] diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/WeChatRegisterDto.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/WeChatRegisterDto.cs new file mode 100644 index 000000000..a0863e0d4 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/WeChatRegisterDto.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Auditing; +using Volo.Abp.Identity; + +namespace LINGYUN.Abp.Account +{ + public class WeChatRegisterDto + { + [Required] + public string Code { get; set; } + + [DisableAuditing] + [DataType(DataType.Password)] + [Required] + [StringLength(IdentityUserConsts.MaxPasswordLength)] + public string Password { get; set; } + + [StringLength(IdentityUserConsts.MaxNameLength)] + public string Name { get; set; } + + [StringLength(IdentityUserConsts.MaxUserNameLength)] + public string UserName { get; set; } + + [EmailAddress] + [StringLength(IdentityUserConsts.MaxEmailLength)] + public string EmailAddress { get; set; } + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs index eee5ab984..d0aa0cd5d 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs @@ -6,7 +6,9 @@ namespace LINGYUN.Abp.Account { public interface IAccountAppService : IApplicationService { - Task RegisterAsync(RegisterVerifyDto input); + Task RegisterAsync(PhoneNumberRegisterDto input); + + Task RegisterAsync(WeChatRegisterDto input); Task ResetPasswordAsync(PasswordResetDto passwordReset); diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj index a10c5a38b..a9070efaf 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj @@ -11,6 +11,7 @@ + diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs index a0c4d6f9f..c765eb16e 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs @@ -1,11 +1,13 @@ -using Volo.Abp.Modularity; +using LINGYUN.Abp.WeChat.Authorization; +using Volo.Abp.Modularity; namespace LINGYUN.Abp.Account { [DependsOn( typeof(AbpAccountDomainModule), typeof(Volo.Abp.Account.AbpAccountApplicationModule), - typeof(AbpAccountApplicationContractsModule))] + typeof(AbpAccountApplicationContractsModule), + typeof(AbpWeChatAuthorizationModule))] public class AbpAccountApplicationModule : AbpModule { diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs index e73ac96ac..e1c531a04 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Identity; +using LINGYUN.Abp.WeChat.Authorization; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Caching.Distributed; using System; using System.Threading.Tasks; @@ -8,7 +9,6 @@ using Volo.Abp.Caching; using Volo.Abp.Identity; using Volo.Abp.Settings; using Volo.Abp.Sms; -using Volo.Abp.Uow; namespace LINGYUN.Abp.Account { @@ -17,6 +17,8 @@ namespace LINGYUN.Abp.Account /// public class AccountAppService : ApplicationService, IAccountAppService { + private IWeChatOpenIdFinder _weChatOpenIdFinder; + protected IWeChatOpenIdFinder WeChatOpenIdFinder => LazyGetRequiredService(ref _weChatOpenIdFinder); protected ISmsSender SmsSender { get; } protected IdentityUserManager UserManager { get; } protected IdentityUserStore UserStore { get; } @@ -39,6 +41,32 @@ namespace LINGYUN.Abp.Account PhoneNumberTokenProvider = phoneNumberTokenProvider; LocalizationResource = typeof(Localization.AccountResource); } + + public virtual async Task RegisterAsync(WeChatRegisterDto input) + { + await CheckSelfRegistrationAsync(); + + var wehchatOpenId = await WeChatOpenIdFinder.FindAsync(input.Code); + + var user = await UserManager.FindByLoginAsync("WeChat", wehchatOpenId.OpenId); + if (user == null) + { + var userName = input.UserName ?? wehchatOpenId.OpenId; + var userEmail = input.EmailAddress ?? $"{userName}@{new Random().Next(1000, 99999)}.com";//如果邮件地址不验证,随意写入一个 + + user = new IdentityUser(GuidGenerator.Create(), userName, userEmail, CurrentTenant.Id) + { + Name = input.Name ?? userName + }; + (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); + + (await UserManager.AddDefaultRolesAsync(user)).CheckErrors(); + + var userLogin = new UserLoginInfo("WeChat", wehchatOpenId.OpenId, "微信认证登录"); + (await UserManager.AddLoginAsync(user, userLogin)).CheckErrors(); + } + return ObjectMapper.Map(user); + } /// /// 用户注册 /// @@ -49,7 +77,7 @@ namespace LINGYUN.Abp.Account /// 如果没有此手机号的缓存记录或验证码不匹配,抛出验证码无效的异常 /// 用户注册成功,清除缓存的验证码记录 /// - public virtual async Task RegisterAsync(RegisterVerifyDto input) + public virtual async Task RegisterAsync(PhoneNumberRegisterDto input) { var phoneVerifyCacheKey = NormalizeCacheKey(input.PhoneNumber); diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/en.json b/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/en.json index d94881919..758961ad5 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/en.json +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/en.json @@ -14,6 +14,7 @@ "Description:PhoneVerifyCodeExpiration": "The valid time for the user to send SMS verification code, unit m, default 3m", "RequiredEmailAddress": "Email address required", "InvalidPhoneNumber": "Invalid phone number", - "DuplicatePhoneNumber": "The phone number {0} has been registered!" + "DuplicatePhoneNumber": "The phone number {0} has been registered!", + "DuplicateWeChat": "The wechat has been registered!" } } \ No newline at end of file diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json b/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json index 114e36d31..da45e2944 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/LINGYUN/Abp/Account/Localization/Resources/zh-Hans.json @@ -14,6 +14,7 @@ "Description:PhoneVerifyCodeExpiration": "用户发送短信验证码的有效时长,单位m,默认3m", "RequiredEmailAddress": "邮件地址必须输入", "InvalidPhoneNumber": "手机号无效", - "DuplicatePhoneNumber": "手机号已经注册过!" + "DuplicatePhoneNumber": "手机号已经注册过!", + "DuplicateWeChat": "微信号已经注册过!" } } \ No newline at end of file diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs index 861de3343..31a2237b4 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Domain/Microsoft/AspNetCore/Identity/PhoneNumberUserValidator.cs @@ -35,7 +35,9 @@ namespace Microsoft.AspNetCore.Identity var phoneNumber = await manager.GetPhoneNumberAsync(user); if (phoneNumber.IsNullOrWhiteSpace()) { - throw new UserFriendlyException(_stringLocalizer["InvalidPhoneNumber"].Value, "InvalidPhoneNumber"); + return; + // 如果用户没有手机号,不验证 + //throw new UserFriendlyException(_stringLocalizer["InvalidPhoneNumber"].Value, "InvalidPhoneNumber"); } var phoneNumberHasRegisted = await _identityUserRepository.PhoneNumberHasRegistedAsync(phoneNumber); diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs index af5b83b4a..55d4db76d 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/AccountController.cs @@ -9,7 +9,7 @@ namespace LINGYUN.Abp.Account { [RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] [Area("account")] - [Route("api/account/phone")] + [Route("api/account")] public class AccountController : AbpController, IAccountAppService { protected IAccountAppService AccountAppService { get; } @@ -20,21 +20,28 @@ namespace LINGYUN.Abp.Account } [HttpPost] - [Route("register")] - public virtual async Task RegisterAsync(RegisterVerifyDto input) + [Route("wechat/register")] + public virtual async Task RegisterAsync(WeChatRegisterDto input) { return await AccountAppService.RegisterAsync(input); } [HttpPost] - [Route("verify")] + [Route("phone/register")] + public virtual async Task RegisterAsync(PhoneNumberRegisterDto input) + { + return await AccountAppService.RegisterAsync(input); + } + + [HttpPost] + [Route("phone/verify")] public virtual async Task VerifyPhoneNumberAsync(VerifyDto input) { await AccountAppService.VerifyPhoneNumberAsync(input); } [HttpPut] - [Route("reset-password")] + [Route("phone/reset-password")] public virtual async Task ResetPasswordAsync(PasswordResetDto passwordReset) { await AccountAppService.ResetPasswordAsync(passwordReset); diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN.ApiGateway.Application.Contracts.csproj b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN.ApiGateway.Application.Contracts.csproj index 24a4fe1a7..6cb8dfaf8 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN.ApiGateway.Application.Contracts.csproj +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN.ApiGateway.Application.Contracts.csproj @@ -3,6 +3,13 @@ netstandard2.0 + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs index 1f742719e..037cf17bd 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs @@ -1,11 +1,10 @@ -using DotNetCore.CAP; -using LINGYUN.ApiGateway.EventBus; -using LINGYUN.ApiGateway.Snowflake; +using LINGYUN.ApiGateway.EventBus; using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.EventBus.Distributed; namespace LINGYUN.ApiGateway.Ocelot { @@ -16,14 +15,14 @@ namespace LINGYUN.ApiGateway.Ocelot [Authorize(ApiGatewayPermissions.AggregateRoute.Default)] public class AggregateReRouteAppService : ApiGatewayApplicationServiceBase, IAggregateReRouteAppService { - private readonly ICapPublisher _eventPublisher; + private IDistributedEventBus _eventBus; + protected IDistributedEventBus DistributedEventBus => LazyGetRequiredService(ref _eventBus); + private readonly IAggregateReRouteRepository _aggregateReRouteRepository; public AggregateReRouteAppService( - ICapPublisher eventPublisher, IAggregateReRouteRepository aggregateReRouteRepository) { - _eventPublisher = eventPublisher; _aggregateReRouteRepository = aggregateReRouteRepository; } @@ -75,8 +74,7 @@ namespace LINGYUN.ApiGateway.Ocelot } aggregateRoute = await _aggregateReRouteRepository.InsertAsync(aggregateRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, - new ApigatewayConfigChangeCommand("AggregateRoute", "Create")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(aggregateRoute.AppId, "AggregateRoute", "Create")); return ObjectMapper.Map(aggregateRoute); } @@ -106,8 +104,7 @@ namespace LINGYUN.ApiGateway.Ocelot aggregateRoute = await _aggregateReRouteRepository.UpdateAsync(aggregateRoute, true); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, - new ApigatewayConfigChangeCommand("AggregateRoute", "Update")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(aggregateRoute.AppId, "AggregateRoute", "Update")); return ObjectMapper.Map(aggregateRoute); } @@ -119,8 +116,7 @@ namespace LINGYUN.ApiGateway.Ocelot var aggregateRoute = await _aggregateReRouteRepository.GetByRouteIdAsync(routeId); await _aggregateReRouteRepository.DeleteAsync(aggregateRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, - new ApigatewayConfigChangeCommand("AggregateRoute", "Delete")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(aggregateRoute.AppId, "AggregateRoute", "Delete")); } [Authorize(ApiGatewayPermissions.AggregateRoute.ManageRouteConfig)] @@ -135,8 +131,7 @@ namespace LINGYUN.ApiGateway.Ocelot await _aggregateReRouteRepository.UpdateAsync(aggregateRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, - new ApigatewayConfigChangeCommand("AggregateRoute", "AddRouteConfig")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(aggregateRoute.AppId, "AggregateRoute", "AddRouteConfig")); return ObjectMapper.Map(aggregateRouteConfig); } @@ -150,8 +145,7 @@ namespace LINGYUN.ApiGateway.Ocelot await _aggregateReRouteRepository.UpdateAsync(aggregateRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, - new ApigatewayConfigChangeCommand("AggregateRoute", "DeleteRouteConfig")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(aggregateRoute.AppId, "AggregateRoute", "DeleteRouteConfig")); } } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/GlobalConfigurationAppService.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/GlobalConfigurationAppService.cs index d2dffec1e..483411fff 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/GlobalConfigurationAppService.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/GlobalConfigurationAppService.cs @@ -1,29 +1,28 @@ -using DotNetCore.CAP; -using LINGYUN.ApiGateway.EventBus; +using LINGYUN.ApiGateway.EventBus; using LINGYUN.ApiGateway.Snowflake; using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using System.Threading.Tasks; -using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.EventBus.Distributed; namespace LINGYUN.ApiGateway.Ocelot { [Authorize(ApiGatewayPermissions.Global.Default)] public class GlobalConfigurationAppService : ApiGatewayApplicationServiceBase, IGlobalConfigurationAppService { + private IDistributedEventBus _eventBus; + protected IDistributedEventBus DistributedEventBus => LazyGetRequiredService(ref _eventBus); + private readonly IRouteGroupChecker _routeGroupChecker; private readonly IGlobalConfigRepository _globalConfigRepository; private readonly ISnowflakeIdGenerator _snowflakeIdGenerator; - private readonly ICapPublisher _eventPublisher; public GlobalConfigurationAppService( - ICapPublisher eventPublisher, IRouteGroupChecker routeGroupChecker, ISnowflakeIdGenerator snowflakeIdGenerator, IGlobalConfigRepository globalConfigRepository ) { - _eventPublisher = eventPublisher; _routeGroupChecker = routeGroupChecker; _snowflakeIdGenerator = snowflakeIdGenerator; _globalConfigRepository = globalConfigRepository; @@ -56,7 +55,7 @@ namespace LINGYUN.ApiGateway.Ocelot globalConfiguration = await _globalConfigRepository.InsertAsync(globalConfiguration, true); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, new ApigatewayConfigChangeCommand("Global", "Create")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(globalConfiguration.AppId, "Global", "Create")); return ObjectMapper.Map(globalConfiguration); } @@ -75,7 +74,7 @@ namespace LINGYUN.ApiGateway.Ocelot globalConfiguration = await _globalConfigRepository.UpdateAsync(globalConfiguration, true); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, new ApigatewayConfigChangeCommand("Global", "Modify")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(globalConfiguration.AppId, "Global", "Modify")); return ObjectMapper.Map(globalConfiguration); } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs index 03f81cb6c..441b16a51 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs @@ -1,27 +1,26 @@ -using DotNetCore.CAP; -using LINGYUN.ApiGateway.EventBus; +using LINGYUN.ApiGateway.EventBus; using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using System.Threading.Tasks; -using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.EventBus.Distributed; namespace LINGYUN.ApiGateway.Ocelot { [Authorize(ApiGatewayPermissions.Route.Default)] public class ReRouteAppService : ApiGatewayApplicationServiceBase, IReRouteAppService { + private IDistributedEventBus _eventBus; + protected IDistributedEventBus DistributedEventBus => LazyGetRequiredService(ref _eventBus); + private readonly IRouteGroupChecker _routeGroupChecker; private readonly IReRouteRepository _reRouteRepository; - private readonly ICapPublisher _eventPublisher; public ReRouteAppService( - ICapPublisher eventPublisher, IRouteGroupChecker routeGroupChecker, IReRouteRepository reRouteRepository ) { - _eventPublisher = eventPublisher; _routeGroupChecker = routeGroupChecker; _reRouteRepository = reRouteRepository; } @@ -37,7 +36,7 @@ namespace LINGYUN.ApiGateway.Ocelot var reRouteDto = ObjectMapper.Map(reRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, new ApigatewayConfigChangeCommand("ReRoute", "Create")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(reRoute.AppId, "ReRoute", "Create")); return reRouteDto; } @@ -74,7 +73,7 @@ namespace LINGYUN.ApiGateway.Ocelot var reRouteDto = ObjectMapper.Map(reRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, new ApigatewayConfigChangeCommand("ReRoute", "Modify")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(reRoute.AppId, "ReRoute", "Modify")); return reRouteDto; } @@ -116,9 +115,11 @@ namespace LINGYUN.ApiGateway.Ocelot [Authorize(ApiGatewayPermissions.Route.Delete)] public async Task DeleteAsync(ReRouteGetByIdInputDto routeGetById) { - await _reRouteRepository.DeleteAsync(x => x.ReRouteId.Equals(routeGetById.RouteId)); + var reRoute = await _reRouteRepository.GetByReRouteIdAsync(routeGetById.RouteId); + + await _reRouteRepository.DeleteAsync(reRoute); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, new ApigatewayConfigChangeCommand("ReRoute", "Delete")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(reRoute.AppId, "ReRoute", "Delete")); } [Authorize(ApiGatewayPermissions.Route.Delete)] @@ -128,7 +129,7 @@ namespace LINGYUN.ApiGateway.Ocelot await _reRouteRepository.DeleteAsync(x => x.AppId.Equals(routeGetByAppId.AppId)); - await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, new ApigatewayConfigChangeCommand("ReRoute", "Clean")); + await DistributedEventBus.PublishAsync(new ApigatewayConfigChangeEventData(routeGetByAppId.AppId, "ReRoute", "Clean")); } protected virtual void ApplyReRouteOptions(ReRoute reRoute, ReRouteDtoBase routeDto) diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN.ApiGateway.Domain.Shared.csproj b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN.ApiGateway.Domain.Shared.csproj index 9e3de3ff0..a5f697ea2 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN.ApiGateway.Domain.Shared.csproj +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN.ApiGateway.Domain.Shared.csproj @@ -3,6 +3,13 @@ netstandard2.0 + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeCommand.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeEventData.cs similarity index 56% rename from aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeCommand.cs rename to aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeEventData.cs index 4843f33fb..9c7bf60d3 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeCommand.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain.Shared/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeEventData.cs @@ -2,19 +2,20 @@ namespace LINGYUN.ApiGateway.EventBus { - public class ApigatewayConfigChangeCommand + public class ApigatewayConfigChangeEventData { - public const string EventName = nameof(ApigatewayConfigChangeCommand); public DateTime DateTime { get; set; } + public string AppId { get; set; } public string Method { get; set; } public string Object { get; set; } - protected ApigatewayConfigChangeCommand() + protected ApigatewayConfigChangeEventData() { } - public ApigatewayConfigChangeCommand(string @object, string @method) + public ApigatewayConfigChangeEventData(string appId, string @object, string @method) { + AppId = appId; DateTime = DateTime.Now; Object = @object; Method = @method; diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN.ApiGateway.Domain.csproj b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN.ApiGateway.Domain.csproj index 13ed4360f..36fafec76 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN.ApiGateway.Domain.csproj +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN.ApiGateway.Domain.csproj @@ -6,7 +6,6 @@ - diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/EntityFrameworkCore/ApiGatewayDbContextModelCreatingExtensions.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/EntityFrameworkCore/ApiGatewayDbContextModelCreatingExtensions.cs index 9b790c06a..698ffce84 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/EntityFrameworkCore/ApiGatewayDbContextModelCreatingExtensions.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/EntityFrameworkCore/ApiGatewayDbContextModelCreatingExtensions.cs @@ -304,7 +304,7 @@ namespace LINGYUN.ApiGateway.EntityFrameworkCore e.Property(x => x.DownstreamHostAndPorts).HasMaxLength(1000); e.Property(x => x.DelegatingHandlers).HasMaxLength(1000); - e.HasIndex(i => new { i.DownstreamPathTemplate, i.UpstreamPathTemplate }).IsUnique(); + e.HasIndex(i => new { i.AppId, i.DownstreamPathTemplate, i.UpstreamPathTemplate }).IsUnique(); e.ConfigureConcurrencyStamp(); e.ConfigureExtraProperties(); diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi.Client/LINGYUN.ApiGateway.HttpApi.Client.csproj b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi.Client/LINGYUN.ApiGateway.HttpApi.Client.csproj index 684658912..52ee8fc99 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi.Client/LINGYUN.ApiGateway.HttpApi.Client.csproj +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi.Client/LINGYUN.ApiGateway.HttpApi.Client.csproj @@ -3,6 +3,13 @@ netstandard2.0 + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj new file mode 100644 index 000000000..eb9ec9cbb --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN.Abp.Aliyun.Authorization.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs new file mode 100644 index 000000000..1dc254e80 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunAuthorizationModule.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Aliyun.Authorization +{ + public class AbpAliyunAuthorizationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(configuration.GetSection("Aliyun:Auth")); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs new file mode 100644 index 000000000..7d90f6da9 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Aliyun.Authorization/LINGYUN/Abp/Aliyun/Authorization/AbpAliyunOptions.cs @@ -0,0 +1,14 @@ +namespace LINGYUN.Abp.Aliyun.Authorization +{ + public class AbpAliyunOptions + { + /// + /// 访问标识 + /// + public string AccessKeyId { get; set; } + /// + /// 访问密钥 + /// + public string AccessKeySecret { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN.Abp.BackgroundJobs.Hangfire.csproj b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN.Abp.BackgroundJobs.Hangfire.csproj new file mode 100644 index 000000000..f46c407f6 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN.Abp.BackgroundJobs.Hangfire.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + true + 2.9.0 + LINGYUN + + + + + D:\LocalNuget + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs new file mode 100644 index 000000000..0fc08ae96 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/AbpBackgroundJobsHangfireModule.cs @@ -0,0 +1,34 @@ +using Hangfire; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using Volo.Abp; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.Hangfire; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BackgroundJobs.Hangfire +{ + [DependsOn( + typeof(AbpBackgroundJobsAbstractionsModule), + typeof(AbpHangfireModule) + )] + public class AbpBackgroundJobsHangfireModule : AbpModule + { + public override void OnPreApplicationInitialization(ApplicationInitializationContext context) + { + var options = context.ServiceProvider.GetRequiredService>().Value; + if (!options.IsJobExecutionEnabled) + { + var hangfireOptions = context.ServiceProvider.GetRequiredService>().Value; + hangfireOptions.BackgroundJobServerFactory = CreateOnlyEnqueueJobServer; + } + } + + private BackgroundJobServer CreateOnlyEnqueueJobServer(IServiceProvider serviceProvider) + { + serviceProvider.GetRequiredService(); + return null; + } + } +} \ No newline at end of file diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs new file mode 100644 index 000000000..435f0192f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs @@ -0,0 +1,34 @@ +using Hangfire; +using System; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.BackgroundJobs.Hangfire +{ + [Dependency(ReplaceServices = true)] + public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency + { + public virtual Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, + TimeSpan? delay = null) + { + if (!delay.HasValue) + { + return Task.FromResult( + BackgroundJob.Enqueue>( + adapter => adapter.Execute(args) + ) + ); + } + else + { + return Task.FromResult( + BackgroundJob.Schedule>( + adapter => adapter.Execute(args), + delay.Value + ) + ); + } + } + } +} \ No newline at end of file diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs new file mode 100644 index 000000000..97cb8dc4a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.Threading; + +namespace LINGYUN.Abp.BackgroundJobs.Hangfire +{ + public class HangfireJobExecutionAdapter + { + protected AbpBackgroundJobOptions Options { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } + protected IBackgroundJobExecuter JobExecuter { get; } + + public HangfireJobExecutionAdapter( + IOptions options, + IBackgroundJobExecuter jobExecuter, + IServiceScopeFactory serviceScopeFactory) + { + JobExecuter = jobExecuter; + ServiceScopeFactory = serviceScopeFactory; + Options = options.Value; + } + + public void Execute(TArgs args) + { + if (!Options.IsJobExecutionEnabled) + { + throw new AbpException( + "Background job execution is disabled. " + + "This method should not be called! " + + "If you want to enable the background job execution, " + + $"set {nameof(AbpBackgroundJobOptions)}.{nameof(AbpBackgroundJobOptions.IsJobExecutionEnabled)} to true! " + + "If you've intentionally disabled job execution and this seems a bug, please report it." + ); + } + + using (var scope = ServiceScopeFactory.CreateScope()) + { + var jobType = Options.GetJob(typeof(TArgs)).JobType; + var context = new JobExecutionContext(scope.ServiceProvider, jobType, args); + AsyncHelper.RunSync(() => JobExecuter.ExecuteAsync(context)); + } + } + } +} \ No newline at end of file diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/IBackgroundJobManagerExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/IBackgroundJobManagerExtensions.cs new file mode 100644 index 000000000..aca3a52ea --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/LINGYUN/Abp/BackgroundJobs/Hangfire/IBackgroundJobManagerExtensions.cs @@ -0,0 +1,35 @@ +using Hangfire; +using JetBrains.Annotations; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.BackgroundJobs; + +namespace LINGYUN.Abp.BackgroundJobs.Hangfire +{ + public static class IBackgroundJobManagerExtensions + { + /// + /// 后台作业进入周期性队列 + /// + /// 作业参数类型 + /// 后台作业管理器 + /// Cron表达式 + /// 作业参数 + /// + public static Task EnqueueAsync( + this IBackgroundJobManager backgroundJobManager, + [NotNull] string cron, + TArgs args + ) + { + Check.NotNullOrWhiteSpace(cron, nameof(cron)); + Check.NotNull(args, nameof(args)); + + var jobName = BackgroundJobNameAttribute.GetName(); + + RecurringJob.AddOrUpdate>(jobName, adapter => adapter.Execute(args), cron); + + return Task.CompletedTask; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/Volo/Abp/BackgroundJobs/CronGenerator.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/Volo/Abp/BackgroundJobs/CronGenerator.cs new file mode 100644 index 000000000..fae4a57b1 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs.Hangfire/Volo/Abp/BackgroundJobs/CronGenerator.cs @@ -0,0 +1,78 @@ +using Hangfire; +using System; + +namespace Volo.Abp.BackgroundJobs +{ + public class CronGenerator + { + /// + /// 周期性为分钟的任务 + /// + /// 执行周期的间隔,默认为每分钟一次 + /// + public static string Minute(int interval = 1) + { + return $"1 0/{interval} * * * ? "; + } + + /// + /// 周期性为小时的任务 + /// + /// 第几分钟开始,默认为第一分钟 + /// 执行周期的间隔,默认为每小时一次 + /// + public static string Hour(int minute = 1, int interval = 1) + { + return $"1 {minute} 0/ {interval} * * ? "; + } + + /// + /// 周期性为天的任务 + /// + /// 第几小时开始,默认从1点开始 + /// 第几分钟开始,默认从第1分钟开始 + /// 执行周期的间隔,默认为每天一次 + /// + public static string Day(int hour = 1, int minute = 1, int interval = 1) + { + return $"1 {minute} {hour} 1/ {interval} * ? "; + } + + /// + /// 周期性为周的任务 + /// + /// 星期几开始,默认从星期一点开始 + /// 第几小时开始,默认从1点开始 + /// 第几分钟开始,默认从第1分钟开始 + /// + public static string Week(DayOfWeek dayOfWeek = DayOfWeek.Monday, int hour = 1, int minute = 1) + { + return Cron.Weekly(dayOfWeek, hour, minute); + } + + /// + /// 周期性为月的任务 + /// + /// 几号开始,默认从一号开始 + /// 第几小时开始,默认从1点开始 + /// 第几分钟开始,默认从第1分钟开始 + /// + public static string Month(int day = 1, int hour = 1, int minute = 1) + { + return Cron.Monthly(day, hour, minute); + } + + /// + /// 周期性为年的任务 + /// + /// 几月开始,默认从一月开始 + /// 几号开始,默认从一号开始 + /// 第几小时开始,默认从1点开始 + /// 第几分钟开始,默认从第1分钟开始 + /// + public static string Year(int month = 1, int day = 1, int hour = 1, int minute = 1) + { + return Cron.Yearly(month, day, hour, minute); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN.Abp.BackgroundJobs.csproj b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN.Abp.BackgroundJobs.csproj new file mode 100644 index 000000000..420f871a3 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN.Abp.BackgroundJobs.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN/Abp/BackgroundJobs/RetryAsyncBackgroundJobArgs.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN/Abp/BackgroundJobs/RetryAsyncBackgroundJobArgs.cs new file mode 100644 index 000000000..369ccaf12 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN/Abp/BackgroundJobs/RetryAsyncBackgroundJobArgs.cs @@ -0,0 +1,43 @@ +namespace LINGYUN.Abp.BackgroundJobs +{ + public class RetryAsyncBackgroundJobArgs + { + /// + /// 重试次数 + /// + public int RetryCount { get; set; } = 0; + /// + /// 重试间隔(毫秒) + /// 默认 300000ms = 5min + /// + public double RetryIntervalMillisecond { get; set; } = 300000d; + /// + /// 最大重试次数 + /// 默认 20 + /// + public int MaxRetryCount { get; set; } = 20; + /// + /// 作业参数 + /// + public TArgs JobArgs { get; set; } + + public RetryAsyncBackgroundJobArgs() + { + + } + + public RetryAsyncBackgroundJobArgs(TArgs jobArgs) + { + JobArgs = jobArgs; + } + + public RetryAsyncBackgroundJobArgs(TArgs jobArgs, int retryCount = 0, double interval = 300000d, int maxRetryCount = 20) + { + JobArgs = jobArgs; + + RetryCount = retryCount; + RetryIntervalMillisecond = interval; + MaxRetryCount = maxRetryCount; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN/Abp/BackgroundJobs/RetryAsyncBackgroundJobBase.cs b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN/Abp/BackgroundJobs/RetryAsyncBackgroundJobBase.cs new file mode 100644 index 000000000..e309e8bbd --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BackgroundJobs/LINGYUN/Abp/BackgroundJobs/RetryAsyncBackgroundJobBase.cs @@ -0,0 +1,80 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; + +namespace LINGYUN.Abp.BackgroundJobs +{ + public abstract class RetryAsyncBackgroundJobBase : IAsyncBackgroundJob> + { + public ILogger> Logger { get; set; } + + protected IBackgroundJobManager BackgroundJobManager { get; } + + protected RetryAsyncBackgroundJobBase( + IBackgroundJobManager backgroundJobManager) + { + BackgroundJobManager = backgroundJobManager; + + Logger = NullLogger>.Instance; + } + + public async Task ExecuteAsync(RetryAsyncBackgroundJobArgs args) + { + if (args.RetryCount > args.MaxRetryCount) + { + Logger.LogWarning("Job has failed and the maximum number of retries has been reached. The failure callback is about to enter"); + // 任务执行失败次数已达上限,调用用户定义回调,并不再执行 + await OnJobExecuteFailedAsync(args.JobArgs); + return; + } + try + { + // 执行任务 + await ExecuteAsync(args.JobArgs, args.RetryCount); + // 执行完成后回调 + await OnJobExecuteCompletedAsync(args.JobArgs); + } + catch(Exception ex) + { + Logger.LogWarning("Job execution has failed and a retry is imminent"); + Logger.LogWarning("Job running error:{0}", ex.Message); + + // 每次重试 间隔时间增加1.1倍 + var retryInterval = args.RetryIntervalMillisecond * 1.1; + var retryJobArgs = new RetryAsyncBackgroundJobArgs(args.JobArgs, + args.RetryCount + 1, retryInterval, args.MaxRetryCount); + + Logger.LogDebug("Job task is queued for the next execution"); + + // 计算优先级 + BackgroundJobPriority priority = BackgroundJobPriority.Normal; + + if (args.RetryCount <= (args.MaxRetryCount / 2) && + args.RetryCount > (args.MaxRetryCount / 3)) + { + priority = BackgroundJobPriority.BelowNormal; + } + else if (args.RetryCount > (args.MaxRetryCount / 1.5)) + { + priority = BackgroundJobPriority.Low; + } + // 延迟入队,等待下一次运行 + await BackgroundJobManager.EnqueueAsync(retryJobArgs, priority, delay: TimeSpan.FromMilliseconds(retryInterval)); + } + } + + protected abstract Task ExecuteAsync(TArgs args, int retryCount); + + protected virtual Task OnJobExecuteFailedAsync(TArgs args) + { + return Task.CompletedTask; + } + + protected virtual Task OnJobExecuteCompletedAsync(TArgs args) + { + return Task.CompletedTask; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj new file mode 100644 index 000000000..92d56b011 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN.Abp.BlobStoring.Aliyun.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + + true + 2.9.0 + LINGYUN + 阿里云Oss对象存储Abp集成 + + + + D:\LocalNuget + + + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs new file mode 100644 index 000000000..8930d080d --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunModule.cs @@ -0,0 +1,35 @@ +using LINGYUN.Abp.Aliyun.Authorization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using Volo.Abp.BlobStoring; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + [DependsOn( + typeof(AbpBlobStoringModule), + typeof(AbpAliyunAuthorizationModule))] + public class AbpBlobStoringAliyunModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(options => + { + context.Services.ExecutePreConfiguredActions(options); + options.Containers.ConfigureAll((containerName, containerConfiguration) => + { + containerConfiguration.UseAliyun(aliyun => + { + aliyun.BucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName] ?? ""; + aliyun.CreateBucketIfNotExists = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists).Get(); + aliyun.CreateBucketReferer = configuration.GetSection(AliyunBlobProviderConfigurationNames.CreateBucketReferer).Get>(); + aliyun.Endpoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint]; + }); + }); + }); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs new file mode 100644 index 000000000..6a73a482a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobContainerConfigurationExtensions.cs @@ -0,0 +1,25 @@ +using System; +using Volo.Abp.BlobStoring; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public static class AliyunBlobContainerConfigurationExtensions + { + public static AliyunBlobProviderConfiguration GetAliyunConfiguration( + this BlobContainerConfiguration containerConfiguration) + { + return new AliyunBlobProviderConfiguration(containerConfiguration); + } + + public static BlobContainerConfiguration UseAliyun( + this BlobContainerConfiguration containerConfiguration, + Action aliyunConfigureAction) + { + containerConfiguration.ProviderType = typeof(AliyunBlobProvider); + + aliyunConfigureAction(new AliyunBlobProviderConfiguration(containerConfiguration)); + + return containerConfiguration; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs new file mode 100644 index 000000000..c076c3843 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProvider.cs @@ -0,0 +1,148 @@ +using Aliyun.OSS; +using LINGYUN.Abp.Aliyun.Authorization; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class AliyunBlobProvider : BlobProviderBase, ITransientDependency + { + protected AbpAliyunOptions Options { get; } + protected IAliyunBlobNameCalculator AliyunBlobNameCalculator { get; } + + public AliyunBlobProvider( + IOptions options, + IAliyunBlobNameCalculator aliyunBlobNameCalculator) + { + Options = options.Value; + AliyunBlobNameCalculator = aliyunBlobNameCalculator; + } + + public override async Task DeleteAsync(BlobProviderDeleteArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + + if (await BlobExistsAsync(args, blobName)) + { + var ossClient = GetOssClient(args); + + return ossClient.DeleteObject(GetBucketName(args), blobName).DeleteMarker; + } + + return false; + } + + public override async Task ExistsAsync(BlobProviderExistsArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + + return await BlobExistsAsync(args, blobName); + } + + public override async Task GetOrNullAsync(BlobProviderGetArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + + if (!await BlobExistsAsync(args, blobName)) + { + return null; + } + + var ossClient = GetOssClient(args); + var ossObject = ossClient.GetObject(GetBucketName(args), blobName); + // 返回原始结果才会调用 Stream.ReadAsync(); + return ossObject.Content; + } + + public override async Task SaveAsync(BlobProviderSaveArgs args) + { + var blobName = AliyunBlobNameCalculator.Calculate(args); + var configuration = args.Configuration.GetAliyunConfiguration(); + if (!args.OverrideExisting && await BlobExistsAsync(args, blobName)) + { + throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the bucketName '{GetBucketName(args)}'! Set {nameof(args.OverrideExisting)} if it should be overwritten."); + } + + if (configuration.CreateBucketIfNotExists) + { + await CreateBucketIfNotExists(args, configuration.CreateBucketReferer); + } + + var bucketName = GetBucketName(args); + var ossClient = GetOssClient(args); + + if (args.OverrideExisting && await BlobExistsAsync(args, blobName)) + { + ossClient.DeleteObject(bucketName, blobName); + } + + ossClient.PutObject(bucketName, blobName, args.BlobStream); + } + + protected virtual OssClient GetOssClient(BlobProviderArgs args) + { + var configuration = args.Configuration.GetAliyunConfiguration(); + var ossClient = new OssClient(configuration.Endpoint, Options.AccessKeyId, Options.AccessKeySecret); + return ossClient; + } + + protected virtual async Task CreateBucketIfNotExists(BlobProviderArgs args, IList refererList = null) + { + if (! await BucketExistsAsync(args)) + { + var ossClient = GetOssClient(args); + var bucketName = GetBucketName(args); + + var request = new CreateBucketRequest(bucketName) + { + //设置存储空间访问权限ACL。 + ACL = CannedAccessControlList.PublicReadWrite, + //设置数据容灾类型。 + DataRedundancyType = DataRedundancyType.ZRS + }; + + ossClient.CreateBucket(request); + + if (refererList != null && refererList.Count > 0) + { + var srq = new SetBucketRefererRequest(bucketName, refererList); + ossClient.SetBucketReferer(srq); + } + } + } + + private async Task BlobExistsAsync(BlobProviderArgs args, string blobName) + { + var ossClient = GetOssClient(args); + var bucketExists = await BucketExistsAsync(args); + if (bucketExists) + { + var objectExists = ossClient.DoesObjectExist(GetBucketName(args), blobName); + + return objectExists; + } + return false; + } + + private Task BucketExistsAsync(BlobProviderArgs args) + { + var ossClient = GetOssClient(args); + var bucketExists = ossClient.DoesBucketExist(GetBucketName(args)); + + return Task.FromResult(bucketExists); + } + + private static string GetBucketName(BlobProviderArgs args) + { + var configuration = args.Configuration.GetAliyunConfiguration(); + return configuration.BucketName.IsNullOrWhiteSpace() + ? args.ContainerName + : configuration.BucketName; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs new file mode 100644 index 000000000..b6f2637ab --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using Volo.Abp; +using Volo.Abp.BlobStoring; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class AliyunBlobProviderConfiguration + { + /// + /// 数据中心 + /// + /// + /// 详见 https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.14.417cd47eLc9LHc#concept-zt4-cvy-5db + /// + public string Endpoint + { + get => _containerConfiguration.GetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + /// + /// 命名空间 + /// + public string BucketName + { + get => _containerConfiguration.GetConfiguration(AliyunBlobProviderConfigurationNames.BucketName); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.BucketName, Check.NotNullOrWhiteSpace(value, nameof(value))); + } + /// + /// 命名空间不存在是否创建 + /// + public bool CreateBucketIfNotExists + { + get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, false); + set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketIfNotExists, value); + } + /// + /// 创建命名空间时防盗链列表 + /// + public List CreateBucketReferer + { + get => _containerConfiguration.GetConfiguration>(AliyunBlobProviderConfigurationNames.CreateBucketReferer); + set + { + if (value == null) + { + _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketReferer, new List()); + } + else + { + _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateBucketReferer, value); + } + } + } + + private readonly BlobContainerConfiguration _containerConfiguration; + + public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration) + { + _containerConfiguration = containerConfiguration; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs new file mode 100644 index 000000000..66b0c17ef --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs @@ -0,0 +1,22 @@ +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public static class AliyunBlobProviderConfigurationNames + { + /// + /// 数据中心 + /// + public const string Endpoint = "Aliyun:OSS:Endpoint"; + /// + /// 命名空间 + /// + public const string BucketName = "Aliyun:OSS:BucketName"; + /// + /// 命名空间不存在是否创建 + /// + public const string CreateBucketIfNotExists = "Aliyun:OSS:CreateBucketIfNotExists"; + /// + /// 创建命名空间时防盗链列表 + /// + public const string CreateBucketReferer = "Aliyun:OSS:CreateBucketReferer"; + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs new file mode 100644 index 000000000..220a13c56 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/DefaultAliyunBlobNameCalculator.cs @@ -0,0 +1,24 @@ +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class DefaultAliyunBlobNameCalculator : IAliyunBlobNameCalculator, ITransientDependency + { + protected ICurrentTenant CurrentTenant { get; } + + public DefaultAliyunBlobNameCalculator( + ICurrentTenant currentTenant) + { + CurrentTenant = currentTenant; + } + + public string Calculate(BlobProviderArgs args) + { + return CurrentTenant.Id == null + ? $"host/{args.BlobName}" + : $"tenants/{CurrentTenant.Id.Value:D}/{args.BlobName}"; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs new file mode 100644 index 000000000..b8dbe6a60 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.BlobStoring.Aliyun/LINGYUN/Abp/BlobStoring/Aliyun/IAliyunBlobNameCalculator.cs @@ -0,0 +1,9 @@ +using Volo.Abp.BlobStoring; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public interface IAliyunBlobNameCalculator + { + string Calculate(BlobProviderArgs args); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.EventBus.CAP/LINGYUN.Abp.EventBus.CAP.csproj b/aspnet-core/modules/common/LINGYUN.Abp.EventBus.CAP/LINGYUN.Abp.EventBus.CAP.csproj index 1087610d0..10f6e1ae7 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.EventBus.CAP/LINGYUN.Abp.EventBus.CAP.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.EventBus.CAP/LINGYUN.Abp.EventBus.CAP.csproj @@ -15,7 +15,7 @@ - + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.MySqlStorage/LINGYUN.Abp.Hangfire.Storage.MySql.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.MySqlStorage/LINGYUN.Abp.Hangfire.Storage.MySql.csproj new file mode 100644 index 000000000..2dce503aa --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.MySqlStorage/LINGYUN.Abp.Hangfire.Storage.MySql.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + + false + true + 2.9.0 + LINGYUN + LINGYUN + + + + D:\LocalNuget + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.MySqlStorage/LINGYUN/Abp/Hangfire/Storage/MySql/AbpHangfireMySqlStorageModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.MySqlStorage/LINGYUN/Abp/Hangfire/Storage/MySql/AbpHangfireMySqlStorageModule.cs new file mode 100644 index 000000000..f7a056012 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.MySqlStorage/LINGYUN/Abp/Hangfire/Storage/MySql/AbpHangfireMySqlStorageModule.cs @@ -0,0 +1,38 @@ +using Hangfire; +using Hangfire.MySql.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Hangfire; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Hangfire.Storage.MySql +{ + [DependsOn(typeof(AbpHangfireModule))] + public class AbpHangfireMySqlStorageModule : AbpModule + { + private MySqlStorage _jobStorage; + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + var mysqlStorageOptions = new MySqlStorageOptions(); + configuration.GetSection("Hangfire:MySql").Bind(mysqlStorageOptions); + + var hangfireMySqlConfiguration = configuration.GetSection("Hangfire:MySql:Connection"); + var hangfireMySqlCon = hangfireMySqlConfiguration.Exists() + ? hangfireMySqlConfiguration.Value : configuration.GetConnectionString("Default"); + + _jobStorage = new MySqlStorage(hangfireMySqlCon, mysqlStorageOptions); + context.Services.AddSingleton(fac => + { + return _jobStorage; + }); + + context.Services.AddHangfire(config => + { + config.UseStorage(_jobStorage); + }); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.Storage.SqlServer/LINGYUN.Abp.Hangfire.Storage.SqlServer.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.Storage.SqlServer/LINGYUN.Abp.Hangfire.Storage.SqlServer.csproj new file mode 100644 index 000000000..9258b98dd --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.Storage.SqlServer/LINGYUN.Abp.Hangfire.Storage.SqlServer.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.0 + + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.Storage.SqlServer/LINGYUN/Abp/Hangfire/Storage/SqlServer/AbpHangfireSqlServerStorageModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.Storage.SqlServer/LINGYUN/Abp/Hangfire/Storage/SqlServer/AbpHangfireSqlServerStorageModule.cs new file mode 100644 index 000000000..42e4ff8db --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Hangfire.Storage.SqlServer/LINGYUN/Abp/Hangfire/Storage/SqlServer/AbpHangfireSqlServerStorageModule.cs @@ -0,0 +1,38 @@ +using Hangfire; +using Hangfire.SqlServer; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Hangfire; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Hangfire.Storage.SqlServer +{ + [DependsOn(typeof(AbpHangfireModule))] + public class AbpHangfireSqlServerStorageModule : AbpModule + { + private SqlServerStorage _jobStorage; + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + var sqlserverStorageOptions = new SqlServerStorageOptions(); + configuration.GetSection("Hangfire:SqlServer").Bind(sqlserverStorageOptions); + + var hangfireSqlServerConfiguration = configuration.GetSection("Hangfire:SqlServer:Connection"); + var hangfireSqlServerCon = hangfireSqlServerConfiguration.Exists() + ? hangfireSqlServerConfiguration.Value : configuration.GetConnectionString("Default"); + + _jobStorage = new SqlServerStorage(hangfireSqlServerCon, sqlserverStorageOptions); + context.Services.AddSingleton(fac => + { + return _jobStorage; + }); + + context.Services.AddHangfire(config => + { + config.UseStorage(_jobStorage); + }); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/Class1.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/Class1.cs deleted file mode 100644 index ea63efae8..000000000 --- a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/Class1.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace LINGYUN.Abp.IdentityServer.WeChatValidator -{ - public class Class1 - { - } -} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj index c15204a42..d87bbe6fc 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN.Abp.IdentityServer.WeChatValidator.csproj @@ -5,8 +5,22 @@ + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs new file mode 100644 index 000000000..e821e5f24 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerWeChatValidatorModule.cs @@ -0,0 +1,44 @@ +using LINGYUN.Abp.IdentityServer.WeChatValidator; +using LINGYUN.Abp.WeChat.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.IdentityServer; +using Volo.Abp.IdentityServer.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.IdentityServer +{ + [DependsOn( + typeof(AbpWeChatAuthorizationModule), + typeof(AbpIdentityServerDomainModule))] + public class AbpIdentityServerWeChatValidatorModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(builder => + { + builder.AddExtensionGrantValidator(); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(configuration.GetSection("WeChat:Signature")); + + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator"); + }); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/en.json b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/en.json new file mode 100644 index 000000000..054ab3e9a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/en.json @@ -0,0 +1,9 @@ +{ + "culture": "en", + "texts": { + "InvalidGrant:GrantTypeInvalid": "The type of authorization that is not allowed!", + "InvalidGrant:WeChatTokenInvalid": "WeChat authentication failed!", + "InvalidGrant:WeChatCodeNotFound": "The code obtained when WeChat is logged in is empty or does not exist!", + "InvalidGrant:WeChatNotRegister": "User WeChat account not registed!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/zh-Hans.json b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/zh-Hans.json new file mode 100644 index 000000000..cb5482df5 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator/zh-Hans.json @@ -0,0 +1,9 @@ +{ + "culture": "zh-Hans", + "texts": { + "InvalidGrant:GrantTypeInvalid": "不被允许的授权类型!", + "InvalidGrant:WeChatTokenInvalid": "微信认证失败!", + "InvalidGrant:WeChatCodeNotFound": "微信登录时获取的 code 为空或不存在!", + "InvalidGrant:WeChatNotRegister": "用户微信账号未绑定!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureMiddleware.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureMiddleware.cs new file mode 100644 index 000000000..48c3a040d --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureMiddleware.cs @@ -0,0 +1,78 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using System; +using System.Collections; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.IdentityServer +{ + public class WeChatSignatureMiddleware : IMiddleware, ITransientDependency + { + protected WeChatSignatureOptions Options { get; } + public WeChatSignatureMiddleware(IOptions options) + { + Options = options.Value; + } + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + if (context.Request.Path.HasValue) + { + var requestPath = context.Request.Path.Value; + // 访问地址是否与定义的地址匹配 + if (requestPath.Equals(Options.RequestPath)) + { + var timestamp = context.Request.Query["timestamp"]; + var nonce = context.Request.Query["nonce"]; + var signature = context.Request.Query["signature"]; + var echostr = context.Request.Query["echostr"]; + // 验证消息合法性 + var check = CheckWeChatSignature(Options.Token, timestamp, nonce, signature); + if (check) + { + // 验证通过需要把微信服务器传递的字符原封不动传回 + await context.Response.WriteAsync(echostr); + return; + } + // 微信消息验证不通过 + throw new AbpException("Invalid wechat signature"); + } + } + // 不属于微信的消息进入下一个中间件 + await next(context); + } + + protected bool CheckWeChatSignature(string token, string timestamp, string nonce, string signature) + { + var al = new ArrayList + { + token, + timestamp, + nonce + }; + // step1 排序 + al.Sort(); + string signatureStr = string.Empty; + // step2 拼接 + for (int i = 0; i < al.Count; i++) + { + signatureStr += al[i]; + } + // step3 SHA1加密 + using var sha1 = new SHA1CryptoServiceProvider(); + byte[] bytes_in = Encoding.ASCII.GetBytes(signatureStr); + byte[] bytes_out = sha1.ComputeHash(bytes_in); + string result = BitConverter.ToString(bytes_out).Replace("-", ""); + // step4 比对 + if (result.Equals(signature, StringComparison.CurrentCultureIgnoreCase)) + { + return true; + } + return false; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureOptions.cs new file mode 100644 index 000000000..7e5b82154 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatSignatureOptions.cs @@ -0,0 +1,16 @@ +namespace LINGYUN.Abp.IdentityServer +{ + public class WeChatSignatureOptions + { + /// + /// 微信服务器请求路径 + /// 填写在微信开发者中心配置的地址 + /// + public string RequestPath { get; set; } + /// + /// 微信服务器请求token + /// 填写在微信开发者中心配置的token + /// + public string Token { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs new file mode 100644 index 000000000..3f3485552 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatTokenGrantValidator.cs @@ -0,0 +1,106 @@ +using IdentityModel; +using IdentityServer4.Events; +using IdentityServer4.Models; +using IdentityServer4.Services; +using IdentityServer4.Validation; +using LINGYUN.Abp.WeChat.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Security.Claims; +using System.Threading.Tasks; +using Volo.Abp.Identity; +using Volo.Abp.IdentityServer.Localization; +using Volo.Abp.Security.Claims; +using IdentityUser = Volo.Abp.Identity.IdentityUser; + +namespace LINGYUN.Abp.IdentityServer.WeChatValidator +{ + public class WeChatTokenGrantValidator : IExtensionGrantValidator + { + protected ILogger Logger { get; } + protected AbpWeChatOptions Options { get; } + protected IHttpClientFactory HttpClientFactory{ get; } + protected IEventService EventService { get; } + protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; } + protected IIdentityUserRepository UserRepository { get; } + protected UserManager UserManager { get; } + protected SignInManager SignInManager { get; } + protected IStringLocalizer Localizer { get; } + protected PhoneNumberTokenProvider PhoneNumberTokenProvider { get; } + + + public WeChatTokenGrantValidator( + IEventService eventService, + IWeChatOpenIdFinder weChatOpenIdFinder, + IHttpClientFactory httpClientFactory, + UserManager userManager, + IIdentityUserRepository userRepository, + SignInManager signInManager, + IStringLocalizer stringLocalizer, + PhoneNumberTokenProvider phoneNumberTokenProvider, + IOptions options, + ILogger logger) + { + Logger = logger; + Options = options.Value; + + EventService = eventService; + UserManager = userManager; + SignInManager = signInManager; + Localizer = stringLocalizer; + UserRepository = userRepository; + WeChatOpenIdFinder = weChatOpenIdFinder; + HttpClientFactory = httpClientFactory; + PhoneNumberTokenProvider = phoneNumberTokenProvider; + } + + public string GrantType => WeChatValidatorConsts.WeChatValidatorGrantTypeName; + + public async Task ValidateAsync(ExtensionGrantValidationContext context) + { + var raw = context.Request.Raw; + var credential = raw.Get(OidcConstants.TokenRequest.GrantType); + if (credential == null || !credential.Equals(GrantType)) + { + Logger.LogWarning("Invalid grant type: not allowed"); + context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, + Localizer["InvalidGrant:GrantTypeInvalid"]); + return; + } + var wechatCode = raw.Get(WeChatValidatorConsts.WeChatValidatorTokenName); + if (wechatCode.IsNullOrWhiteSpace() || wechatCode.IsNullOrWhiteSpace()) + { + Logger.LogWarning("Invalid grant type: wechat code not found"); + context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, + Localizer["InvalidGrant:WeChatCodeNotFound"]); + return; + } + var whchatOpenId = await WeChatOpenIdFinder.FindAsync(wechatCode); + var currentUser = await UserManager.FindByLoginAsync("WeChat", whchatOpenId.OpenId); + if(currentUser == null) + { + Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", whchatOpenId.OpenId); + context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, + Localizer["InvalidGrant:WeChatNotRegister"]); + return; + } + var sub = await UserManager.GetUserIdAsync(currentUser); + + var additionalClaims = new List(); + if (currentUser.TenantId.HasValue) + { + additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString())); + } + additionalClaims.Add(new Claim(WeChatValidatorConsts.ClaimTypes.OpenId, whchatOpenId.OpenId)); + + await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, whchatOpenId.OpenId, null)); + context.Result = new GrantValidationResult(sub, + WeChatValidatorConsts.AuthenticationMethods.BasedWeChatAuthentication, additionalClaims.ToArray()); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatValidatorConsts.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatValidatorConsts.cs new file mode 100644 index 000000000..91ab26b6b --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/LINGYUN/Abp/IdentityServer/WeChatValidator/WeChatValidatorConsts.cs @@ -0,0 +1,21 @@ +namespace LINGYUN.Abp.IdentityServer.WeChatValidator +{ + public class WeChatValidatorConsts + { + public const string WeChatValidatorClientName = "WeChatValidator"; + + public const string WeChatValidatorGrantTypeName = "wechat"; + + public const string WeChatValidatorTokenName = "code"; + + public class ClaimTypes + { + public const string OpenId = "wx-openid"; + } + + public class AuthenticationMethods + { + public const string BasedWeChatAuthentication = "wca"; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Builder/IdentityServerApplicationBuilderExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Builder/IdentityServerApplicationBuilderExtensions.cs new file mode 100644 index 000000000..f8b805fbe --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IdentityServer.WeChatValidator/Microsoft/AspNetCore/Builder/IdentityServerApplicationBuilderExtensions.cs @@ -0,0 +1,22 @@ +using LINGYUN.Abp.IdentityServer; + +namespace Microsoft.AspNetCore.Builder +{ + public static class IdentityServerApplicationBuilderExtensions + { + /// + /// 启用中间件可以处理微信服务器消息 + /// 用于验证消息是否来自于微信服务器 + /// + /// + /// + /// 也可以用Controller的形式来实现 + /// + /// + public static IApplicationBuilder UseWeChatSignature(this IApplicationBuilder builder) + { + builder.UseMiddleware(); + return builder; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs index 549f249f8..572ab75c3 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs @@ -10,6 +10,12 @@ namespace LINGYUN.Abp.Notifications.SignalR typeof(AbpAspNetCoreSignalRModule))] public class AbpNotificationsSignalRModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.PublishProviders.Add(); + }); + } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs index 5cd3ab3f1..67f7c60e5 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs @@ -22,9 +22,9 @@ namespace LINGYUN.Abp.Notifications.SignalR.Hubs } [HubMethodName("ChangeState")] - public virtual async Task ChangeStateAsync(long id, NotificationReadState readState = NotificationReadState.Read) + public virtual async Task ChangeStateAsync(string id, NotificationReadState readState = NotificationReadState.Read) { - await NotificationStore.ChangeUserNotificationReadStateAsync(CurrentTenant.Id, CurrentUser.GetId(), id, readState); + await NotificationStore.ChangeUserNotificationReadStateAsync(CurrentTenant.Id, CurrentUser.GetId(), long.Parse(id), readState); } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublisher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs similarity index 60% rename from aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublisher.cs rename to aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs index 8130a659e..04afc41a8 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublisher.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs @@ -2,54 +2,58 @@ using LINGYUN.Abp.RealTime.Client; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; namespace LINGYUN.Abp.Notifications.SignalR { - public class SignalRNotificationPublisher : INotificationPublisher, ISingletonDependency + public class SignalRNotificationPublishProvider : NotificationPublishProvider { - public ILogger Logger { protected get; set; } + public const string ProviderName = "SignalR"; + public override string Name => ProviderName; private readonly IOnlineClientManager _onlineClientManager; private readonly IHubContext _hubContext; - public SignalRNotificationPublisher( + public SignalRNotificationPublishProvider( IOnlineClientManager onlineClientManager, - IHubContext hubContext) + IHubContext hubContext, + IServiceProvider serviceProvider) + : base(serviceProvider) { _hubContext = hubContext; _onlineClientManager = onlineClientManager; - - Logger = NullLogger.Instance; } - public async Task PublishAsync(NotificationInfo notification, IEnumerable userIds) + public override async Task PublishAsync(NotificationInfo notification, IEnumerable identifiers) { - foreach(var userId in userIds) + // 返回标准数据给前端 + notification.Data = NotificationData.ToStandardData(notification.Data); + foreach (var identifier in identifiers) { - var onlineClientContext = new OnlineClientContext(notification.TenantId, userId); + Logger.LogDebug($"Find online client with user {identifier.UserId} - {identifier.UserName}"); + var onlineClientContext = new OnlineClientContext(notification.TenantId, identifier.UserId); var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); foreach (var onlineClient in onlineClients) { try { + Logger.LogDebug($"Find online client {onlineClient.UserId} - {onlineClient.ConnectionId}"); var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); if (signalRClient == null) { Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); continue; } - + Logger.LogDebug($"Found a singalr client, begin senging notifications"); await signalRClient.SendAsync("getNotification", notification); } catch (Exception ex) { - Logger.LogWarning("Could not send notifications to user: {0}", userId); + Logger.LogWarning("Could not send notifications to user: {0}", identifier.UserId); Logger.LogWarning("Send to user notifications error: {0}", ex.Message); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN.Abp.Notifications.WeChat.WeApp.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN.Abp.Notifications.WeChat.WeApp.csproj new file mode 100644 index 000000000..790973e9a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN.Abp.Notifications.WeChat.WeApp.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + + false + true + 2.9.0 + 通知接口的微信小程序发布者实现 + + + + D:\LocalNuget + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpNotificationsWeChatWeAppModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpNotificationsWeChatWeAppModule.cs new file mode 100644 index 000000000..146da9d22 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpNotificationsWeChatWeAppModule.cs @@ -0,0 +1,30 @@ +using LINGYUN.Abp.WeChat.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Polly; +using System; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.WeChat.WeApp +{ + [DependsOn( + typeof(AbpWeChatAuthorizationModule), + typeof(AbpNotificationModule))] + public class AbpNotificationsWeChatWeAppModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(configuration.GetSection("Notifications:WeChat:WeApp")); + + // TODO:是否有必要启用重试机制? + context.Services.AddHttpClient(WeChatWeAppNotificationSender.SendNotificationClientName) + .AddTransientHttpErrorPolicy(builder => + builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)))); + + Configure(options => + { + options.PublishProviders.Add(); + }); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpWeChatWeAppNotificationOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpWeChatWeAppNotificationOptions.cs new file mode 100644 index 000000000..cacc4e47b --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/AbpWeChatWeAppNotificationOptions.cs @@ -0,0 +1,22 @@ +namespace LINGYUN.Abp.Notifications.WeChat.WeApp +{ + public class AbpWeChatWeAppNotificationOptions + { + /// + /// 默认消息头部标记 + /// + public string DefaultMsgPrefix { get; set; } = "[wx]"; + /// + /// 默认小程序模板 + /// + public string DefaultTemplateId { get; set; } + /// + /// 默认跳转小程序类型 + /// + public string DefaultWeAppState { get; set; } = "developer"; + /// + /// 默认小程序语言 + /// + public string DefaultWeAppLanguage { get; set; } = "zh_CN"; + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/IWeChatWeAppNotificationSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/IWeChatWeAppNotificationSender.cs new file mode 100644 index 000000000..de5d8c500 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/IWeChatWeAppNotificationSender.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.WeChat.WeApp +{ + public interface IWeChatWeAppNotificationSender + { + Task SendAsync(WeChatWeAppSendNotificationData notificationData); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationPublishProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationPublishProvider.cs new file mode 100644 index 000000000..6b71643f6 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationPublishProvider.cs @@ -0,0 +1,84 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.WeChat.WeApp +{ + /// + /// 微信小程序消息推送提供者 + /// + public class WeChatWeAppNotificationPublishProvider : NotificationPublishProvider + { + public override string Name => "WeChat.WeApp"; + + protected IWeChatWeAppNotificationSender NotificationSender { get; } + protected AbpWeChatWeAppNotificationOptions Options { get; } + public WeChatWeAppNotificationPublishProvider( + IServiceProvider serviceProvider, + IWeChatWeAppNotificationSender notificationSender, + IOptions options) + : base(serviceProvider) + { + Options = options.Value; + NotificationSender = notificationSender; + } + + public override async Task PublishAsync(NotificationInfo notification, IEnumerable identifiers) + { + // step1 默认微信openid绑定的就是username, + // 如果不是,需要自行处理openid获取逻辑 + + // step2 调用微信消息推送接口 + + foreach (var identifier in identifiers) + { + await SendWeChatTemplateMessagAsync(notification, identifier); + } + } + + protected virtual async Task SendWeChatTemplateMessagAsync(NotificationInfo notification, UserIdentifier identifier) + { + var templateId = GetOrDefaultTemplateId(notification.Data); + Logger.LogDebug($"Get wechat weapp template id: {templateId}"); + + var redirect = GetOrDefault(notification.Data, "RedirectPage", null); + Logger.LogDebug($"Get wechat weapp redirect page: {redirect ?? "null"}"); + + var weAppState = GetOrDefault(notification.Data, "WeAppState", Options.DefaultWeAppState); + Logger.LogDebug($"Get wechat weapp state: {weAppState ?? null}"); + + var weAppLang = GetOrDefault(notification.Data, "WeAppLanguage", Options.DefaultWeAppLanguage); + Logger.LogDebug($"Get wechat weapp language: {weAppLang ?? null}"); + + var weChatWeAppNotificationData = new WeChatWeAppSendNotificationData(identifier.UserName, + templateId, redirect, weAppState, weAppLang); + + + // 写入模板数据 + weChatWeAppNotificationData.WriteStandardData(NotificationData.ToStandardData(Options.DefaultMsgPrefix, notification.Data)); + // weChatWeAppNotificationData.WriteData(Options.DefaultMsgPrefix, notification.Data.Properties); + + Logger.LogDebug($"Sending wechat weapp notification: {notification.Name}"); + // 发送小程序订阅消息 + await NotificationSender.SendAsync(weChatWeAppNotificationData); + } + + protected string GetOrDefaultTemplateId(NotificationData data) + { + return GetOrDefault(data, "TemplateId", Options.DefaultTemplateId); + } + + protected string GetOrDefault(NotificationData data, string key, string defaultValue) + { + if (data.Properties.TryGetValue(key, out object value)) + { + // 取得了数据就删除对应键值 + // data.Properties.Remove(key); + return value.ToString(); + } + return defaultValue; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs new file mode 100644 index 000000000..44ecac7db --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs @@ -0,0 +1,108 @@ +using LINGYUN.Abp.WeChat.Authorization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Newtonsoft.Json; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; + +namespace LINGYUN.Abp.Notifications.WeChat.WeApp +{ + public class WeChatWeAppNotificationSender : IWeChatWeAppNotificationSender, ITransientDependency + { + public const string SendNotificationClientName = "WeChatWeAppSendNotificationClient"; + public ILogger Logger { get; set; } + protected IHttpClientFactory HttpClientFactory { get; } + protected IJsonSerializer JsonSerializer { get; } + protected IWeChatTokenProvider WeChatTokenProvider { get; } + public WeChatWeAppNotificationSender( + IJsonSerializer jsonSerializer, + IHttpClientFactory httpClientFactory, + IWeChatTokenProvider weChatTokenProvider) + { + JsonSerializer = jsonSerializer; + HttpClientFactory = httpClientFactory; + WeChatTokenProvider = weChatTokenProvider; + + Logger = NullLogger.Instance; + } + + public virtual async Task SendAsync(WeChatWeAppSendNotificationData notificationData) + { + var weChatToken = await WeChatTokenProvider.GetTokenAsync(); + var requestParamters = new Dictionary + { + { "access_token", weChatToken.AccessToken } + }; + var weChatSendNotificationUrl = "https://api.weixin.qq.com"; + var weChatSendNotificationPath = "/cgi-bin/message/subscribe/send"; + var requestUrl = BuildRequestUrl(weChatSendNotificationUrl, weChatSendNotificationPath, requestParamters); + var responseContent = await MakeRequestAndGetResultAsync(requestUrl, notificationData); + var weChatSenNotificationResponse = JsonSerializer.Deserialize(responseContent); + + if (!weChatSenNotificationResponse.IsSuccessed) + { + Logger.LogWarning("Send wechat we app subscribe message failed"); + Logger.LogWarning($"Error code: {weChatSenNotificationResponse.ErrorCode}, message: {weChatSenNotificationResponse.ErrorMessage}"); + } + // 失败是否抛出异常 + // weChatSenNotificationResponse.ThrowIfNotSuccess(); + } + protected virtual async Task MakeRequestAndGetResultAsync(string url, WeChatWeAppSendNotificationData notificationData) + { + var client = HttpClientFactory.CreateClient(SendNotificationClientName); + var sendDataContent = JsonSerializer.Serialize(notificationData); + var requestContent = new StringContent(sendDataContent); + var requestMessage = new HttpRequestMessage(HttpMethod.Post, url) + { + Content = requestContent + }; + + var response = await client.SendAsync(requestMessage); + if (!response.IsSuccessStatusCode) + { + throw new AbpException($"WeChat send subscribe message http request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); + } + var resultContent = await response.Content.ReadAsStringAsync(); + + return resultContent; + } + + protected virtual string BuildRequestUrl(string uri, string path, IDictionary paramters) + { + var requestUrlBuilder = new StringBuilder(128); + requestUrlBuilder.Append(uri); + requestUrlBuilder.Append(path).Append("?"); + foreach (var paramter in paramters) + { + requestUrlBuilder.AppendFormat("{0}={1}", paramter.Key, paramter.Value); + requestUrlBuilder.Append("&"); + } + requestUrlBuilder.Remove(requestUrlBuilder.Length - 1, 1); + return requestUrlBuilder.ToString(); + } + } + + public class WeChatSendNotificationResponse + { + [JsonProperty("errcode")] + public int ErrorCode { get; set; } + + [JsonProperty("errmsg")] + public string ErrorMessage { get; set; } + + public bool IsSuccessed => ErrorCode == 0; + + public void ThrowIfNotSuccess() + { + if (ErrorCode != 0) + { + throw new AbpException($"Send wechat weapp notification error:{ErrorMessage}"); + } + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppSendNotificationData.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppSendNotificationData.cs new file mode 100644 index 000000000..5f190f7c4 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppSendNotificationData.cs @@ -0,0 +1,103 @@ +#pragma warning disable IDE1006 // 禁止编译器提示 +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications.WeChat.WeApp +{ + public class WeChatWeAppSendNotificationData + { + /// + /// 接收者(用户)的 openid + /// + public string touser { get; set; } + /// + /// 所需下发的订阅模板id + /// + public string template_id { get; set; } + /// + /// 点击模板卡片后的跳转页面,仅限本小程序内的页面。 + /// 支持带参数,(示例index?foo=bar)。 + /// 该字段不填则模板无跳转 + /// + public string page { get; set; } + /// + /// 跳转小程序类型: + /// developer为开发版;trial为体验版;formal为正式版; + /// 默认为正式版 + /// + public string miniprogram_state { get; set; } + /// + /// 进入小程序查看”的语言类型, + /// 支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文), + /// 默认为zh_CN + /// + public string lang { get; set; } + /// + /// 模板内容, + /// 格式形如 { "key1": { "value": any }, "key2": { "value": any } } + /// + public Dictionary data { get; set; } + + public WeChatWeAppSendNotificationData() { } + public WeChatWeAppSendNotificationData(string openId, string templateId, string redirectPage = "", + string state = "formal", string miniLang = "zh_CN") + { + touser = openId; + template_id = templateId; + page = redirectPage; + miniprogram_state = state; + lang = miniLang; + + data = new Dictionary(); + } + /// + /// 写入标准数据 + /// + /// + /// + public WeChatWeAppSendNotificationData WriteStandardData(NotificationData writeData) + { + foreach (var kv in writeData.Properties) + { + if (!data.ContainsKey(kv.Key)) + { + data.Add(kv.Key, new WeChatNotificationData(kv.Value)); + } + } + return this; + } + + public WeChatWeAppSendNotificationData WriteData(string prefix, string key, object value) + { + // 只截取符合标记的数据 + if (key.StartsWith(prefix)) + { + key = key.Replace(prefix, ""); + if (!data.ContainsKey(key)) + { + data.Add(key, new WeChatNotificationData(value)); + } + } + return this; + } + + public WeChatWeAppSendNotificationData WriteData(string prefix, IDictionary setData) + { + foreach(var kv in setData) + { + WriteData(prefix, kv.Key, kv.Value); + } + return this; + } + } + + public class WeChatNotificationData + { + public object Value { get; } + + public WeChatNotificationData(object value) + { + Value = value; + } + } +} +#pragma warning restore IDE1006 diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj index a6f38bfc2..9af56cb36 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj @@ -13,7 +13,9 @@ + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs index ec8c315e2..30bf9376b 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs @@ -1,14 +1,47 @@ using LINGYUN.Abp.Notifications.Internal; using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Volo.Abp; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.Json; using Volo.Abp.Modularity; namespace LINGYUN.Abp.Notifications { + [DependsOn( + typeof(AbpBackgroundJobsModule), + typeof(AbpJsonModule))] public class AbpNotificationModule : AbpModule { + + public override void PreConfigureServices(ServiceConfigurationContext context) + { + AutoAddDefinitionProviders(context.Services); + } + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddTransient(); } + + private static void AutoAddDefinitionProviders(IServiceCollection services) + { + var definitionProviders = new List(); + + services.OnRegistred(context => + { + if (typeof(INotificationDefinitionProvider).IsAssignableFrom(context.ImplementationType)) + { + definitionProviders.Add(context.ImplementationType); + } + }); + + services.Configure(options => + { + services.ExecutePreConfiguredActions(options); + options.DefinitionProviders.AddIfNotContains(definitionProviders); + }); + } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationOptions.cs new file mode 100644 index 000000000..45289f231 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationOptions.cs @@ -0,0 +1,16 @@ +using Volo.Abp.Collections; + +namespace LINGYUN.Abp.Notifications +{ + public class AbpNotificationOptions + { + public ITypeList DefinitionProviders { get; } + + public ITypeList PublishProviders { get; } + public AbpNotificationOptions() + { + PublishProviders = new TypeList(); + DefinitionProviders = new TypeList(); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionContext.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionContext.cs new file mode 100644 index 000000000..00aaf52e6 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionContext.cs @@ -0,0 +1,9 @@ +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationDefinitionContext + { + NotificationDefinition GetOrNull(string category); + + void Add(params NotificationDefinition[] definitions); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionManager.cs new file mode 100644 index 000000000..ab958ee8f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionManager.cs @@ -0,0 +1,15 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationDefinitionManager + { + [NotNull] + NotificationDefinition Get([NotNull] string category); + + IReadOnlyList GetAll(); + + NotificationDefinition GetOrNull(string category); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionProvider.cs new file mode 100644 index 000000000..7c86ddda0 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDefinitionProvider.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationDefinitionProvider + { + void Define(INotificationDefinitionContext context); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs index 180f82d59..cc450bb9f 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs @@ -1,9 +1,33 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; namespace LINGYUN.Abp.Notifications { + /// + /// 通知发送者接口 + /// public interface INotificationDispatcher { - Task DispatcheAsync(NotificationInfo notification); + /// + /// 发送通知 + /// + /// 通知名称 + /// 数据 + /// 租户 + /// 级别 + /// + Task DispatchAsync(NotificationName notificationName, NotificationData data, Guid? tenantId = null, + NotificationSeverity notificationSeverity = NotificationSeverity.Info); + + /// + /// 发送通知事件 + /// + /// 通知名称 + /// 数据 + /// 租户 + /// 级别 + /// + Task DispatchEventAsync(NotificationName notificationName, NotificationData data, Guid? tenantId = null, + NotificationSeverity notificationSeverity = NotificationSeverity.Info); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProvider.cs new file mode 100644 index 000000000..2819d5a28 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProvider.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationPublishProvider + { + string Name { get; } + + Task PublishAsync(NotificationInfo notification, IEnumerable identifiers); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProviderManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProviderManager.cs new file mode 100644 index 000000000..630b932c9 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishProviderManager.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationPublishProviderManager + { + List Providers { get; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs deleted file mode 100644 index 1e8411eb9..000000000 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.Notifications -{ - public interface INotificationPublisher - { - Task PublishAsync(NotificationInfo notification, IEnumerable userIds); - } -} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs index e7d0074e5..e90af6509 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs @@ -6,22 +6,30 @@ namespace LINGYUN.Abp.Notifications { public interface INotificationStore { - Task InsertUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName); + Task InsertUserSubscriptionAsync(Guid? tenantId, UserIdentifier identifier, string notificationName); - Task InsertUserSubscriptionAsync(Guid? tenantId, IEnumerable userIds, string notificationName); + Task InsertUserSubscriptionAsync(Guid? tenantId, IEnumerable identifiers, string notificationName); Task DeleteUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName); + Task DeleteAllUserSubscriptionAsync(Guid? tenantId, string notificationName); + + Task DeleteUserSubscriptionAsync(Guid? tenantId, IEnumerable identifiers, string notificationName); + Task> GetSubscriptionsAsync(Guid? tenantId, string notificationName); Task> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId); + Task> GetUserSubscriptionsAsync(Guid? tenantId, string userName); + Task IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName); Task InsertNotificationAsync(NotificationInfo notification); Task DeleteNotificationAsync(NotificationInfo notification); + Task DeleteNotificationAsync(int batchCount); + Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId); Task InsertUserNotificationsAsync(NotificationInfo notification, IEnumerable userIds); diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSubscriptionManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSubscriptionManager.cs new file mode 100644 index 000000000..2754a872a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSubscriptionManager.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications +{ + /// + /// 通知订阅管理器 + /// + public interface INotificationSubscriptionManager + { + /// + /// 是否已订阅 + /// + /// 租户 + /// 用户标识 + /// 通知名称 + /// + Task IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName); + /// + /// 订阅通知 + /// + /// 租户 + /// 用户标识 + /// 通知名称 + /// + Task SubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName); + /// + /// 订阅通知 + /// + /// 租户 + /// 用户标识列表 + /// 通知名称 + /// + Task SubscribeAsync(Guid? tenantId, IEnumerable identifiers, string notificationName); + /// + /// 取消所有用户订阅 + /// + /// 租户 + /// 通知名称 + /// + Task UnsubscribeAllAsync(Guid? tenantId, string notificationName); + /// + /// 取消订阅 + /// + /// 租户 + /// 用户标识 + /// 通知名称 + /// + Task UnsubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName); + /// + /// 取消订阅 + /// + /// 租户 + /// 用户标识列表 + /// 通知名称 + /// + Task UnsubscribeAsync(Guid? tenantId, IEnumerable identifiers, string notificationName); + /// + /// 获取通知被订阅用户列表 + /// + /// 租户 + /// 通知名称 + /// + Task> GetSubscriptionsAsync(Guid? tenantId, string notificationName); + /// + /// 获取用户订阅列表 + /// + /// 租户 + /// 用户标识 + /// + Task> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId); + /// + /// 获取用户订阅列表 + /// + /// 租户 + /// 用户名 + /// + Task> GetUserSubscriptionsAsync(Guid? tenantId, string userName); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs index 1e470ee39..b4802b2bd 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs @@ -1,34 +1,210 @@ -using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.EventBus.Distributed; namespace LINGYUN.Abp.Notifications.Internal { + /// + /// Implements . + /// internal class DefaultNotificationDispatcher : INotificationDispatcher { + /// + /// Reference to . + /// + public ILogger Logger { get; set; } + /// + /// Reference to . + /// + public IDistributedEventBus DistributedEventBus { get; set; } + /// + /// Reference to . + /// + private readonly IBackgroundJobManager _backgroundJobManager; + /// + /// Reference to . + /// private readonly INotificationStore _notificationStore; - private readonly INotificationPublisher _notificationPublisher; + /// + /// Reference to . + /// + private readonly INotificationDefinitionManager _notificationDefinitionManager; + /// + /// Reference to . + /// + private readonly INotificationPublishProviderManager _notificationPublishProviderManager; + /// + /// Initializes a new instance of the class. + /// public DefaultNotificationDispatcher( + IBackgroundJobManager backgroundJobManager, + INotificationStore notificationStore, - INotificationPublisher notificationPublisher) + INotificationDefinitionManager notificationDefinitionManager, + INotificationPublishProviderManager notificationPublishProviderManager) { + _backgroundJobManager = backgroundJobManager; + _notificationStore = notificationStore; - _notificationPublisher = notificationPublisher; + _notificationDefinitionManager = notificationDefinitionManager; + _notificationPublishProviderManager = notificationPublishProviderManager; + + DistributedEventBus = NullDistributedEventBus.Instance; + Logger = NullLogger.Instance; } + /// + /// 发送通知 + /// + /// 通知名称 + /// 通知数据 + /// 租户 + /// 级别 + /// + public virtual async Task DispatchAsync(NotificationName notificationName, NotificationData data, Guid? tenantId = null, + NotificationSeverity notificationSeverity = NotificationSeverity.Info) + { + // 获取自定义的通知 + var defineNotification = _notificationDefinitionManager.Get(notificationName.CateGory); + + //// 没有定义的通知,应该也要能发布、订阅, + //// 比如订单之类的,是以订单编号为通知名称,这是动态的,没法自定义 + //if(defineNotification == null) + //{ + // defineNotification = new NotificationDefinition(notificationName.CateGory); + //} + + var notificationInfo = new NotificationInfo + { + CateGory = notificationName.CateGory, + Name = notificationName.Name, + CreationTime = DateTime.Now, + NotificationSeverity = notificationSeverity, + Lifetime = defineNotification.NotificationLifetime, + NotificationType = defineNotification.NotificationType, + TenantId = tenantId, + Data = data + }; - public async Task DispatcheAsync(NotificationInfo notification) + var providers = Enumerable + .Reverse(_notificationPublishProviderManager.Providers); + + if (defineNotification.Providers.Any()) + { + providers = providers.Where(p => defineNotification.Providers.Contains(p.Name)); + } + + await PublishFromProvidersAsync(providers, notificationInfo); + + if (notificationInfo.Lifetime == NotificationLifetime.OnlyOne) + { + // 一次性通知在发送完成后就取消用户订阅 + await _notificationStore.DeleteAllUserSubscriptionAsync(notificationInfo.TenantId, + notificationInfo.Name); + } + } + /// + /// 发送通知事件 + /// + /// + /// + /// + /// + /// + public virtual async Task DispatchEventAsync(NotificationName notificationName, NotificationData data, Guid? tenantId = null, + NotificationSeverity notificationSeverity = NotificationSeverity.Info) { + // 获取自定义的通知 + var defineNotification = _notificationDefinitionManager.Get(notificationName.CateGory); + + var notificationEventData = new NotificationEventData + { + CateGory = notificationName.CateGory, + Name = notificationName.Name, + CreationTime = DateTime.Now, + NotificationSeverity = notificationSeverity, + Lifetime = defineNotification.NotificationLifetime, + NotificationType = defineNotification.NotificationType, + TenantId = tenantId, + Data = data + }; + // 发布分布式通知事件,让消息中心统一处理 + await DistributedEventBus.PublishAsync(notificationEventData); + } + /// + /// 指定提供者发布通知 + /// + /// 提供者列表 + /// 通知信息 + /// + protected async Task PublishFromProvidersAsync(IEnumerable providers, + NotificationInfo notificationInfo) + { + Logger.LogDebug($"Persistent notification {notificationInfo.Name}"); // 持久化通知 - await _notificationStore.InsertNotificationAsync(notification); + await _notificationStore.InsertNotificationAsync(notificationInfo); + Logger.LogDebug($"Gets a list of user subscriptions {notificationInfo.Name}"); // 获取用户订阅列表 - var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notification.TenantId, notification.Name); + var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notificationInfo.TenantId, notificationInfo.Name); + Logger.LogDebug($"Persistent user notifications {notificationInfo.Name}"); // 持久化用户通知 - var subscriptionUserIds = userSubscriptions.Select(us => us.UserId); - await _notificationStore.InsertUserNotificationsAsync(notification, subscriptionUserIds); + var subscriptionUserIdentifiers = userSubscriptions.Select(us => new UserIdentifier(us.UserId, us.UserName)); + + await _notificationStore.InsertUserNotificationsAsync(notificationInfo, + subscriptionUserIdentifiers.Select(u => u.UserId)); + + // 发布通知 + foreach (var provider in providers) + { + await PublishAsync(provider, notificationInfo, subscriptionUserIdentifiers); + } + + // TODO: 需要计算队列大小,根据情况是否需要并行发布消息 + //Parallel.ForEach(providers, async (provider) => + //{ + // await PublishAsync(provider, notificationInfo, subscriptionUserIdentifiers); + //}); + } + /// + /// 发布通知 + /// + /// 通知发布者 + /// 通知信息 + /// 订阅用户列表 + /// + protected async Task PublishAsync(INotificationPublishProvider provider, NotificationInfo notificationInfo, + IEnumerable subscriptionUserIdentifiers) + { + try + { + Logger.LogDebug($"Sending notification with provider {provider.Name}"); + + // 发布 + await provider.PublishAsync(notificationInfo, subscriptionUserIdentifiers); + + Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful"); + } + catch (Exception ex) + { + Logger.LogWarning($"Send notification error with provider {provider.Name}"); + Logger.LogWarning($"Error message:{ex.Message}"); + + Logger.LogTrace(ex, $"Send notification error with provider { provider.Name}"); - // 发布用户通知 - await _notificationPublisher.PublishAsync(notification, subscriptionUserIds); + Logger.LogDebug($"Send notification error, notification {notificationInfo.Name} entry queue"); + // 发送失败的消息进入后台队列 + await _backgroundJobManager.EnqueueAsync( + new NotificationPublishJobArgs(notificationInfo.GetId(), + provider.GetType().AssemblyQualifiedName, + subscriptionUserIdentifiers.ToList(), + notificationInfo.TenantId)); + } } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSubscriptionManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSubscriptionManager.cs new file mode 100644 index 000000000..3754d72d3 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSubscriptionManager.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications.Internal +{ + internal class NotificationSubscriptionManager : INotificationSubscriptionManager, ITransientDependency + { + private readonly INotificationStore _store; + + public NotificationSubscriptionManager( + INotificationStore store) + { + _store = store; + } + + public virtual async Task> GetSubscriptionsAsync(Guid? tenantId, string notificationName) + { + return await _store.GetSubscriptionsAsync(tenantId, notificationName); + } + + public virtual async Task> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId) + { + return await _store.GetUserSubscriptionsAsync(tenantId, userId); + } + + public virtual async Task> GetUserSubscriptionsAsync(Guid? tenantId, string userName) + { + return await _store.GetUserSubscriptionsAsync(tenantId, userName); + } + + public virtual async Task IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName) + { + return await _store.IsSubscribedAsync(tenantId, userId, notificationName); + } + + public virtual async Task SubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName) + { + if (await IsSubscribedAsync(tenantId, identifier.UserId, notificationName)) + { + return; + } + await _store.InsertUserSubscriptionAsync(tenantId, identifier, notificationName); + } + + public virtual async Task SubscribeAsync(Guid? tenantId, IEnumerable identifiers, string notificationName) + { + foreach(var identifier in identifiers) + { + await SubscribeAsync(tenantId, identifier, notificationName); + } + } + + public virtual async Task UnsubscribeAsync(Guid? tenantId, UserIdentifier identifier, string notificationName) + { + await _store.DeleteUserSubscriptionAsync(tenantId, identifier.UserId, notificationName); + } + + public virtual async Task UnsubscribeAllAsync(Guid? tenantId, string notificationName) + { + await _store.DeleteAllUserSubscriptionAsync(tenantId, notificationName); + } + + public virtual async Task UnsubscribeAsync(Guid? tenantId, IEnumerable identifiers, string notificationName) + { + await _store.DeleteUserSubscriptionAsync(tenantId, identifiers, notificationName); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs index 2ed903b2d..ea6e40578 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs @@ -45,5 +45,83 @@ namespace LINGYUN.Abp.Notifications { _properties = new Dictionary(); } + /// + /// 写入标准数据 + /// + /// 标题 + /// 内容 + /// 创建时间 + /// 来源用户 + /// + public NotificationData WriteStandardData(string title, string message, DateTime createTime, string formUser) + { + TrySetData("title", title); + TrySetData("message", message); + TrySetData("formUser", formUser); + TrySetData("createTime", createTime); + return this; + } + /// + /// 写入标准数据 + /// + /// 数据前缀 + /// 标识 + /// 数据内容 + /// + public NotificationData WriteStandardData(string prefix, string key, object value) + { + TrySetData(string.Concat(prefix, key), value); + return this; + } + /// + /// 转换为标准数据 + /// + /// 原始数据 + /// + public static NotificationData ToStandardData(NotificationData sourceData) + { + var data = new NotificationData(); + data.TrySetData("title", sourceData.TryGetData("title")); + data.TrySetData("message", sourceData.TryGetData("message")); + data.TrySetData("formUser", sourceData.TryGetData("formUser")); + data.TrySetData("createTime", sourceData.TryGetData("createTime")); + return data; + } + /// + /// 转换为标准数据 + /// + /// 数据前缀 + /// 原始数据 + /// + public static NotificationData ToStandardData(string prefix, NotificationData sourceData) + { + var data = ToStandardData(sourceData); + + foreach(var property in sourceData.Properties) + { + if (property.Key.StartsWith(prefix)) + { + var key = property.Key.Replace(prefix, ""); + data.TrySetData(key, property.Value); + } + } + return data; + } + + public object TryGetData(string key) + { + if (Properties.TryGetValue(key, out object value)) + { + return value; + } + return null; + } + public void TrySetData(string key, object value) + { + if (value != null && !Properties.ContainsKey(key)) + { + Properties[key] = value; + } + } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs new file mode 100644 index 000000000..f585fbafb --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs @@ -0,0 +1,83 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using Volo.Abp; +using Volo.Abp.Localization; + +/* + * 通知系统的设计不应该定死通知名称 + * 而是规范通知的一些属性,因此不应该是自定义通知名称,而是定义通知的类目,类似于Catalog + * 或者Prefix + * + */ + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationDefinition + { + /// + /// 通知类目 + /// + [NotNull] + public string CateGory { get; set; } + /// + /// 通知显示名称 + /// + [NotNull] + public ILocalizableString DisplayName + { + get => _displayName; + set => _displayName = Check.NotNull(value, nameof(value)); + } + private ILocalizableString _displayName; + /// + /// 通知说明 + /// + [CanBeNull] + public ILocalizableString Description { get; set; } + /// + /// 允许客户端显示订阅 + /// + public bool AllowSubscriptionToClients { get; set; } + /// + /// 存活类型 + /// + public NotificationLifetime NotificationLifetime { get; set; } + /// + /// 通知类型 + /// + public NotificationType NotificationType { get; set; } + /// + /// 通知提供者 + /// + public List Providers { get; } + + public NotificationDefinition( + string category, + ILocalizableString displayName = null, + ILocalizableString description = null, + NotificationType notificationType = NotificationType.Application, + NotificationLifetime lifetime = NotificationLifetime.Persistent, + bool allowSubscriptionToClients = false) + { + CateGory = category; + DisplayName = displayName ?? new FixedLocalizableString(category); + Description = description; + NotificationLifetime = lifetime; + NotificationType = notificationType; + AllowSubscriptionToClients = allowSubscriptionToClients; + + Providers = new List(); + } + + public virtual NotificationDefinition WithProviders(params string[] providers) + { + if (!providers.IsNullOrEmpty()) + { + Providers.AddRange(providers); + } + + return this; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionContext.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionContext.cs new file mode 100644 index 000000000..db8b40bdc --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionContext.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationDefinitionContext : INotificationDefinitionContext + { + protected Dictionary Notifications { get; } + + public NotificationDefinitionContext(Dictionary notifications) + { + Notifications = notifications; + } + + public void Add(params NotificationDefinition[] definitions) + { + if (definitions.IsNullOrEmpty()) + { + return; + } + + foreach (var definition in definitions) + { + Notifications[definition.CateGory] = definition; + } + } + + public NotificationDefinition GetOrNull(string category) + { + return Notifications.GetOrDefault(category); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs new file mode 100644 index 000000000..6c92aa695 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionManager.cs @@ -0,0 +1,75 @@ +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationDefinitionManager : INotificationDefinitionManager, ISingletonDependency + { + protected Lazy> NotificationDefinitions { get; } + + protected AbpNotificationOptions Options { get; } + + protected IServiceProvider ServiceProvider { get; } + + public NotificationDefinitionManager( + IOptions options, + IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + Options = options.Value; + + NotificationDefinitions = new Lazy>(CreateNotificationDefinitions, true); + } + + public virtual NotificationDefinition Get([NotNull] string category) + { + Check.NotNull(category, nameof(category)); + + var notification = GetOrNull(category); + + if (notification == null) + { + throw new AbpException("Undefined notification category: " + category); + } + + return notification; + } + + public virtual IReadOnlyList GetAll() + { + return NotificationDefinitions.Value.Values.ToImmutableList(); + } + + public virtual NotificationDefinition GetOrNull(string category) + { + return NotificationDefinitions.Value.GetOrDefault(category); + } + + protected virtual IDictionary CreateNotificationDefinitions() + { + var notifications = new Dictionary(); + + using (var scope = ServiceProvider.CreateScope()) + { + var providers = Options + .DefinitionProviders + .Select(p => scope.ServiceProvider.GetRequiredService(p) as INotificationDefinitionProvider) + .ToList(); + + foreach (var provider in providers) + { + provider.Define(new NotificationDefinitionContext(notifications)); + } + } + + return notifications; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionProvider.cs new file mode 100644 index 000000000..f921ae5f4 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinitionProvider.cs @@ -0,0 +1,9 @@ +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications +{ + public abstract class NotificationDefinitionProvider : INotificationDefinitionProvider, ITransientDependency + { + public abstract void Define(INotificationDefinitionContext context); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationEventData.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationEventData.cs new file mode 100644 index 000000000..6eebfcd41 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationEventData.cs @@ -0,0 +1,38 @@ +using System; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationEventData + { + public Guid? TenantId { get; set; } + public string CateGory { get; set; } + public string Name { get; set; } + public string Id { get; set; } + public NotificationData Data { get; set; } + public DateTime CreationTime { get; set; } + public NotificationLifetime Lifetime { get; set; } + public NotificationType NotificationType { get; set; } + public NotificationSeverity NotificationSeverity { get; set; } + + public NotificationEventData() + { + + } + + public NotificationInfo ToNotificationInfo() + { + return new NotificationInfo + { + NotificationSeverity = NotificationSeverity, + CreationTime = CreationTime, + Data = Data, + Id = Id, + Name = Name, + CateGory = CateGory, + NotificationType = NotificationType, + Lifetime = Lifetime, + TenantId = TenantId + }; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs index 6b0b5bc98..8b5745359 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; namespace LINGYUN.Abp.Notifications { @@ -7,19 +6,53 @@ namespace LINGYUN.Abp.Notifications { public Guid? TenantId { get; set; } public string Name { get; set; } - [JsonConverter(typeof(HexLongConverter))] - public long Id { get; set; } + public string CateGory { get; set; } + public string Id { get; set; } public NotificationData Data { get; set; } public DateTime CreationTime { get; set; } + public NotificationLifetime Lifetime { get; set; } public NotificationType NotificationType { get; set; } public NotificationSeverity NotificationSeverity { get; set; } public NotificationInfo() { Data = new NotificationData(); + Lifetime = NotificationLifetime.Persistent; NotificationType = NotificationType.Application; NotificationSeverity = NotificationSeverity.Info; CreationTime = DateTime.Now; } + + public long SetId(long id) + { + if (Id.IsNullOrWhiteSpace()) + { + Id = id.ToString(); + return id; + } + + return GetId(); + } + + public long GetId() + { + return long.Parse(Id); + } + + public NotificationEventData ToNotificationEventData() + { + return new NotificationEventData + { + NotificationSeverity = NotificationSeverity, + CreationTime = CreationTime, + Data = Data, + Id = Id, + Name = Name, + CateGory = CateGory, + Lifetime = Lifetime, + NotificationType = NotificationType, + TenantId = TenantId + }; + } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationLifetime.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationLifetime.cs new file mode 100644 index 000000000..6127ca0f1 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationLifetime.cs @@ -0,0 +1,18 @@ +namespace LINGYUN.Abp.Notifications +{ + /// + /// 通知存活时间 + /// 发送之后取消用户订阅,类似于微信小程序 + /// + public enum NotificationLifetime + { + /// + /// 持久化 + /// + Persistent = 0, + /// + /// 一次性 + /// + OnlyOne = 1 + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationName.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationName.cs new file mode 100644 index 000000000..057259ded --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationName.cs @@ -0,0 +1,14 @@ +namespace LINGYUN.Abp.Notifications +{ + public class NotificationName + { + public string CateGory { get; } + public string Name { get; } + + public NotificationName(string cateGory, string name) + { + Name = name; + CateGory = cateGory; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationNameNormalizer.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationNameNormalizer.cs new file mode 100644 index 000000000..1d4ada3d1 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationNameNormalizer.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.Notifications +{ + public static class NotificationNameNormalizer + { + public static NotificationName NormalizerName(string name) + { + return new NotificationName(name, name); + } + public static NotificationName NormalizerName(string category, string name) + { + var notifyName = string.Concat(category, ":", name); + return new NotificationName(category, notifyName); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishJob.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishJob.cs new file mode 100644 index 000000000..2ae41faff --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishJob.cs @@ -0,0 +1,34 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationPublishJob : AsyncBackgroundJob, ITransientDependency + { + protected INotificationStore Store { get; } + protected IServiceProvider ServiceProvider { get; } + + public NotificationPublishJob( + INotificationStore store, + IServiceProvider serviceProvider) + { + Store = store; + ServiceProvider = serviceProvider; + } + + public override async Task ExecuteAsync(NotificationPublishJobArgs args) + { + var providerType = Type.GetType(args.ProviderType); + + if (ServiceProvider.GetRequiredService(providerType) is INotificationPublishProvider publishProvider) + { + var notification = await Store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId); + + await publishProvider.PublishAsync(notification, args.UserIdentifiers); + } + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishJobArgs.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishJobArgs.cs new file mode 100644 index 000000000..128019301 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishJobArgs.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationPublishJobArgs + { + public Guid? TenantId { get; set; } + public long NotificationId { get; set; } + public string ProviderType { get; set; } + public List UserIdentifiers { get; set; } + public NotificationPublishJobArgs(long id, string providerType, List userIdentifiers, Guid? tenantId = null ) + { + NotificationId = id; + ProviderType = providerType; + UserIdentifiers = userIdentifiers; + TenantId = tenantId; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs new file mode 100644 index 000000000..c2f4fda24 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications +{ + public abstract class NotificationPublishProvider : INotificationPublishProvider, ITransientDependency + { + public abstract string Name { get; } + + protected IServiceProvider ServiceProvider { get; } + + protected readonly object ServiceProviderLock = new object(); + + public ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory); + private ILoggerFactory _loggerFactory; + + protected ILogger Logger => _lazyLogger.Value; + private Lazy _lazyLogger => new Lazy(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true); + + + protected TService LazyGetRequiredService(ref TService reference) + { + if (reference == null) + { + lock (ServiceProviderLock) + { + if (reference == null) + { + reference = ServiceProvider.GetRequiredService(); + } + } + } + + return reference; + } + + protected NotificationPublishProvider(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + + public abstract Task PublishAsync(NotificationInfo notification, IEnumerable identifiers); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProviderManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProviderManager.cs new file mode 100644 index 000000000..669f3b678 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProviderManager.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationPublishProviderManager : INotificationPublishProviderManager, ISingletonDependency + { + public List Providers => _lazyProviders.Value; + + protected AbpNotificationOptions Options { get; } + + private readonly Lazy> _lazyProviders; + + public NotificationPublishProviderManager( + IServiceProvider serviceProvider, + IOptions options) + { + Options = options.Value; + + _lazyProviders = new Lazy>( + () => Options + .PublishProviders + .Select(type => serviceProvider.GetRequiredService(type) as INotificationPublishProvider) + .ToList(), + true + ); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSubscriptionInfo.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSubscriptionInfo.cs index 0122731fc..b4bcb5f79 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSubscriptionInfo.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSubscriptionInfo.cs @@ -6,6 +6,7 @@ namespace LINGYUN.Abp.Notifications { public Guid? TenantId { get; set; } public Guid UserId { get; set; } + public string UserName { get; set; } public string NotificationName { get; set; } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/UserIdentifier.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/UserIdentifier.cs new file mode 100644 index 000000000..a6717897f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/UserIdentifier.cs @@ -0,0 +1,16 @@ +using System; + +namespace LINGYUN.Abp.Notifications +{ + public class UserIdentifier + { + public Guid UserId { get; set; } + public string UserName { get; set; } + + public UserIdentifier(Guid userId, string userName) + { + UserId = userId; + UserName = userName; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj index 8c6bc0335..1b84eb70e 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINGYUN.Abp.Sms.Aliyun.csproj @@ -30,4 +30,8 @@ + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs index e36a96c42..cad4c903a 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AbpAliyunSmsModule.cs @@ -1,4 +1,5 @@ -using LINYUN.Abp.Sms.Aliyun.Localization; +using LINGYUN.Abp.Aliyun.Authorization; +using LINYUN.Abp.Sms.Aliyun.Localization; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Json; using Volo.Abp.Localization; @@ -11,7 +12,8 @@ namespace LINYUN.Abp.Sms.Aliyun [DependsOn( typeof(AbpSmsModule), typeof(AbpJsonModule), - typeof(AbpLocalizationModule))] + typeof(AbpLocalizationModule), + typeof(AbpAliyunAuthorizationModule))] public class AbpAliyunSmsModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs index 3384f9982..19f3e04a4 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsOptions.cs @@ -15,14 +15,6 @@ /// public string ActionName { get; set; } = "SendSms"; /// - /// ApiKey - /// - public string AccessKeyId { get; set; } - /// - /// Api密钥 - /// - public string AccessKeySecret { get; set; } - /// /// 默认版本号 /// public string Version { get; set; } = "2017-05-25"; diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs index 36690094b..7f87d2a2f 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs @@ -2,6 +2,7 @@ using Aliyun.Acs.Core.Exceptions; using Aliyun.Acs.Core.Http; using Aliyun.Acs.Core.Profile; +using LINGYUN.Abp.Aliyun.Authorization; using LINYUN.Abp.Sms.Aliyun.Localization; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -21,6 +22,7 @@ namespace LINYUN.Abp.Sms.Aliyun [ExposeServices(typeof(ISmsSender), typeof(AliyunSmsSender))] public class AliyunSmsSender : ISmsSender { + protected AbpAliyunOptions AuthOptions { get; } protected AliyunSmsOptions Options { get; } protected IJsonSerializer JsonSerializer { get; } protected IHostEnvironment Environment { get; } @@ -29,9 +31,12 @@ namespace LINYUN.Abp.Sms.Aliyun IHostEnvironment environment, IJsonSerializer jsonSerializer, IServiceProvider serviceProvider, - IOptions options) + IOptions options, + IOptions authOptions) { Options = options.Value; + AuthOptions = authOptions.Value; + Environment = environment; JsonSerializer = jsonSerializer; ServiceProvider = serviceProvider; @@ -53,7 +58,7 @@ namespace LINYUN.Abp.Sms.Aliyun try { - IClientProfile profile = DefaultProfile.GetProfile(Options.RegionId, Options.AccessKeyId, Options.AccessKeySecret); + IClientProfile profile = DefaultProfile.GetProfile(Options.RegionId, AuthOptions.AccessKeyId, AuthOptions.AccessKeySecret); IAcsClient client = new DefaultAcsClient(profile); CommonResponse response = client.GetCommonResponse(request); var responseContent = Encoding.Default.GetString(response.HttpResponse.Content); diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN.Abp.WeChat.Authorization.csproj b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN.Abp.WeChat.Authorization.csproj new file mode 100644 index 000000000..95b04ed53 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN.Abp.WeChat.Authorization.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs new file mode 100644 index 000000000..cb8ba8810 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatAuthorizationModule.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Polly; +using System; +using Volo.Abp.Caching; +using Volo.Abp.Json; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + [DependsOn(typeof(AbpJsonModule), typeof(AbpCachingModule))] + public class AbpWeChatAuthorizationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(configuration.GetSection("WeChat:Auth")); + + context.Services.AddHttpClient("WeChatRequestClient", options => + { + options.BaseAddress = new Uri("https://api.weixin.qq.com"); + }).AddTransientHttpErrorPolicy(builder => + builder.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)))); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatOptions.cs new file mode 100644 index 000000000..3c4174d9f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/AbpWeChatOptions.cs @@ -0,0 +1,8 @@ +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class AbpWeChatOptions + { + public string AppId { get; set; } + public string AppSecret { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/IWeChatOpenIdFinder.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/IWeChatOpenIdFinder.cs new file mode 100644 index 000000000..3fa47002a --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/IWeChatOpenIdFinder.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + public interface IWeChatOpenIdFinder + { + Task FindAsync(string code); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenId.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenId.cs new file mode 100644 index 000000000..a1e4ae9a9 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenId.cs @@ -0,0 +1,30 @@ +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class WeChatOpenId + { + /// + /// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回 + /// + public string UnionId { get; set; } + /// + /// 用户唯一标识 + /// + public string OpenId { get; set; } + /// + /// 会话密钥 + /// + public string SessionKey { get; set; } + + public WeChatOpenId() + { + + } + + public WeChatOpenId(string openId, string sessionKey, string unionId = null) + { + OpenId = openId; + SessionKey = sessionKey; + UnionId = unionId; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdCacheItem.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdCacheItem.cs new file mode 100644 index 000000000..52950c532 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdCacheItem.cs @@ -0,0 +1,28 @@ +using System; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class WeChatOpenIdCacheItem + { + public string Code { get; set; } + + public WeChatOpenId WeChatOpenId { get; set; } + public WeChatOpenIdCacheItem() + { + + } + + public WeChatOpenIdCacheItem(string code, WeChatOpenId weChatOpenId) + { + Code = code; + WeChatOpenId = weChatOpenId; + } + + public static string CalculateCacheKey(string code, Guid? tenantId = null) + { + string tenant = tenantId != null ? tenantId.Value.ToString("D") : "host"; + + return "t:" + tenant + ",c:" + code; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdFinder.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdFinder.cs new file mode 100644 index 000000000..1adad5390 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdFinder.cs @@ -0,0 +1,97 @@ +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + [Dependency(ServiceLifetime.Singleton, ReplaceServices = true)] + [ExposeServices(typeof(IWeChatOpenIdFinder))] + public class WeChatOpenIdFinder : IWeChatOpenIdFinder + { + public ILogger Logger { get; set; } + protected AbpWeChatOptions Options { get; } + protected ICurrentTenant CurrentTenant { get; } + protected IHttpClientFactory HttpClientFactory { get; } + protected IJsonSerializer JsonSerializer { get; } + protected IDistributedCache Cache { get; } + public WeChatOpenIdFinder( + ICurrentTenant currentTenant, + IJsonSerializer jsonSerializer, + IHttpClientFactory httpClientFactory, + IOptions options, + IDistributedCache cache) + { + CurrentTenant = currentTenant; + JsonSerializer = jsonSerializer; + HttpClientFactory = httpClientFactory; + + Cache = cache; + Options = options.Value; + + Logger = NullLogger.Instance; + } + public virtual async Task FindAsync(string code) + { + return (await GetCacheItemAsync(code, CurrentTenant.Id)).WeChatOpenId; + } + + protected virtual async Task GetCacheItemAsync(string code, Guid? tenantId = null) + { + var cacheKey = WeChatOpenIdCacheItem.CalculateCacheKey(code, tenantId); + + Logger.LogDebug($"WeChatOpenIdFinder.GetCacheItemAsync: {cacheKey}"); + + var cacheItem = await Cache.GetAsync(cacheKey); + + if (cacheItem != null) + { + Logger.LogDebug($"Found in the cache: {cacheKey}"); + return cacheItem; + } + + Logger.LogDebug($"Not found in the cache, getting from the httpClient: {cacheKey}"); + + var client = HttpClientFactory.CreateClient("WeChatRequestClient"); + + var request = new WeChatOpenIdRequest + { + BaseUrl = client.BaseAddress.AbsoluteUri, + AppId = Options.AppId, + Secret = Options.AppSecret, + Code = code + }; + + var response = await client.RequestWeChatOpenIdAsync(request); + var responseContent = await response.Content.ReadAsStringAsync(); + var weChatOpenIdResponse = JsonSerializer.Deserialize(responseContent); + var weChatOpenId = weChatOpenIdResponse.ToWeChatOpenId(); + cacheItem = new WeChatOpenIdCacheItem(code, weChatOpenId); + + Logger.LogDebug($"Setting the cache item: {cacheKey}"); + + var cacheOptions = new DistributedCacheEntryOptions + { + // 微信官方文档表示 session_key的有效期是3天 + // https://developers.weixin.qq.com/community/develop/doc/000c2424654c40bd9c960e71e5b009 + AbsoluteExpiration = DateTimeOffset.Now.AddDays(3) + // SlidingExpiration = TimeSpan.FromDays(3), + }; + + + await Cache.SetAsync(cacheKey, cacheItem, cacheOptions); + + Logger.LogDebug($"Finished setting the cache item: {cacheKey}"); + + return cacheItem; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdRequest.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdRequest.cs new file mode 100644 index 000000000..719d57089 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdRequest.cs @@ -0,0 +1,10 @@ +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class WeChatOpenIdRequest + { + public string BaseUrl { get; set; } + public string AppId { get; set; } + public string Secret { get; set; } + public string Code { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdResponse.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdResponse.cs new file mode 100644 index 000000000..f85b48e42 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/OpenId/WeChatOpenIdResponse.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using System; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + /// + /// 微信OpenId返回对象 + /// + public class WeChatOpenIdResponse + { + /// + /// 错误码 + /// + [JsonProperty("errcode")] + public string ErrorCode { get; set; } + /// + /// 会话密钥 + /// + [JsonProperty("session_key")] + public string SessionKey { get; set; } + /// + /// 用户唯一标识 + /// + [JsonProperty("openid")] + public string OpenId { get; set; } + /// + /// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回 + /// + [JsonProperty("unionid")] + public string UnionId { get; set; } + /// + /// 错误消息 + /// + public string ErrorMessage + { + get + { + switch (ErrorCode) + { + case "-1": return "系统繁忙,此时请开发者稍候再试"; + case "0": return string.Empty; + case "40029": return "code 无效"; + case "45011": return "频率限制,每个用户每分钟100次"; + default: return "未知的异常,请重试"; + }; + } + } + /// + /// 微信认证成功没有errorcode或者errorcode为0 + /// + public bool IsError => !ErrorCode.IsNullOrWhiteSpace() && !"0".Equals(ErrorCode); + + public WeChatOpenId ToWeChatOpenId() + { + if(IsError) + { + throw new AbpException(ErrorMessage); + } + return new WeChatOpenId(OpenId, SessionKey, UnionId); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/IWeChatTokenProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/IWeChatTokenProvider.cs new file mode 100644 index 000000000..dddf69239 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/IWeChatTokenProvider.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + public interface IWeChatTokenProvider + { + Task GetTokenAsync(); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatToken.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatToken.cs new file mode 100644 index 000000000..e09902f0f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatToken.cs @@ -0,0 +1,26 @@ +namespace LINGYUN.Abp.WeChat.Authorization +{ + /// + /// 微信令牌 + /// + public class WeChatToken + { + /// + /// 访问令牌 + /// + public string AccessToken { get; set; } + /// + /// 过期时间,单位(s) + /// + public int ExpiresIn { get; set; } + public WeChatToken() + { + + } + public WeChatToken(string token, int expiresIn) + { + AccessToken = token; + ExpiresIn = expiresIn; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenCacheItem.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenCacheItem.cs new file mode 100644 index 000000000..e0a2d27ee --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenCacheItem.cs @@ -0,0 +1,24 @@ +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class WeChatTokenCacheItem + { + public string AppId { get; set; } + + public WeChatToken WeChatToken { get; set; } + public WeChatTokenCacheItem() + { + + } + + public WeChatTokenCacheItem(string appId, WeChatToken weChatToken) + { + AppId = appId; + WeChatToken = weChatToken; + } + + public static string CalculateCacheKey(string provider, string appId) + { + return "p:" + provider + ",o:" + appId; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenProvider.cs new file mode 100644 index 000000000..3c6b2b7e6 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenProvider.cs @@ -0,0 +1,88 @@ +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class WeChatTokenProvider : IWeChatTokenProvider, ISingletonDependency + { + public ILogger Logger { get; set; } + protected IHttpClientFactory HttpClientFactory { get; } + protected IJsonSerializer JsonSerializer { get; } + protected IDistributedCache Cache { get; } + protected AbpWeChatOptions Options { get; } + public WeChatTokenProvider( + IJsonSerializer jsonSerializer, + IHttpClientFactory httpClientFactory, + IOptions options, + IDistributedCache cache) + { + JsonSerializer = jsonSerializer; + HttpClientFactory = httpClientFactory; + + Cache = cache; + Options = options.Value; + + Logger = NullLogger.Instance; + } + + public virtual async Task GetTokenAsync() + { + return (await GetCacheItemAsync("WeChatToken", Options.AppId)).WeChatToken; + } + + protected virtual async Task GetCacheItemAsync(string provider, string appId) + { + var cacheKey = WeChatTokenCacheItem.CalculateCacheKey(provider, appId); + + Logger.LogDebug($"WeChatTokenProvider.GetCacheItemAsync: {cacheKey}"); + + var cacheItem = await Cache.GetAsync(cacheKey); + + if (cacheItem != null) + { + Logger.LogDebug($"Found in the cache: {cacheKey}"); + return cacheItem; + } + + Logger.LogDebug($"Not found in the cache, getting from the httpClient: {cacheKey}"); + + var client = HttpClientFactory.CreateClient("WeChatRequestClient"); + + var request = new WeChatTokenRequest + { + BaseUrl = client.BaseAddress.AbsoluteUri, + AppSecret = Options.AppSecret, + AppId = Options.AppId, + GrantType = "client_credential" + }; + + var response = await client.RequestWeChatCodeTokenAsync(request); + var responseContent = await response.Content.ReadAsStringAsync(); + var weChatTokenResponse = JsonSerializer.Deserialize(responseContent); + var weChatToken = weChatTokenResponse.ToWeChatToken(); + cacheItem = new WeChatTokenCacheItem(appId, weChatToken); + + Logger.LogDebug($"Setting the cache item: {cacheKey}"); + + var cacheOptions = new DistributedCacheEntryOptions + { + // 设置绝对过期时间为Token有效期剩余的二分钟 + AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(weChatToken.ExpiresIn - 120) + }; + + await Cache.SetAsync(cacheKey, cacheItem, cacheOptions); + + Logger.LogDebug($"Finished setting the cache item: {cacheKey}"); + + return cacheItem; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenRequest.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenRequest.cs new file mode 100644 index 000000000..3259b378d --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenRequest.cs @@ -0,0 +1,10 @@ +namespace LINGYUN.Abp.WeChat.Authorization +{ + public class WeChatTokenRequest + { + public string BaseUrl { get; set; } + public string GrantType { get; set; } + public string AppId { get; set; } + public string AppSecret { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenResponse.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenResponse.cs new file mode 100644 index 000000000..e6be63b80 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/LINGYUN/Abp/WeChat/Authorization/Token/WeChatTokenResponse.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Authorization +{ + /// + /// 微信访问令牌返回对象 + /// + public class WeChatTokenResponse + { + /// + /// 错误码 + /// + [JsonProperty("errcode")] + public int ErrorCode { get; set; } + /// + /// 错误消息 + /// + [JsonProperty("errmsg")] + public string ErrorMessage { get; set; } + /// + /// 访问令牌 + /// + [JsonProperty("access_token")] + public string AccessToken { get; set; } + /// + /// 过期时间,单位(s) + /// + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + public WeChatToken ToWeChatToken() + { + if(ErrorCode != 0) + { + throw new AbpException(ErrorMessage); + } + return new WeChatToken(AccessToken, ExpiresIn); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs new file mode 100644 index 000000000..bdb5c9888 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.WeChat.Authorization/System/Net/Http/HttpClientWeChatTokenRequestExtensions.cs @@ -0,0 +1,45 @@ +using LINGYUN.Abp.WeChat.Authorization; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Http +{ + public static class HttpClientWeChatTokenRequestExtensions + { + public static async Task RequestWeChatCodeTokenAsync(this HttpMessageInvoker client, WeChatTokenRequest request, CancellationToken cancellationToken = default) + { + var getResuestUrlBuilder = new StringBuilder(); + getResuestUrlBuilder.Append(request.BaseUrl); + getResuestUrlBuilder.Append("cgi-bin/token"); + getResuestUrlBuilder.Append("?grant_type=client_credential"); + getResuestUrlBuilder.AppendFormat("&appid={0}", request.AppId); + getResuestUrlBuilder.AppendFormat("&secret={0}", request.AppSecret); + + var getRequest = new HttpRequestMessage(HttpMethod.Get, getResuestUrlBuilder.ToString()); + HttpResponseMessage httpResponse; + + httpResponse = await client.SendAsync(getRequest, cancellationToken).ConfigureAwait(false); + + return httpResponse; + } + + public static async Task RequestWeChatOpenIdAsync(this HttpMessageInvoker client, WeChatOpenIdRequest request, CancellationToken cancellationToken = default) + { + var getResuestUrlBuiilder = new StringBuilder(); + getResuestUrlBuiilder.Append(request.BaseUrl); + getResuestUrlBuiilder.Append("sns/jscode2session"); + getResuestUrlBuiilder.AppendFormat("?appid={0}", request.AppId); + getResuestUrlBuiilder.AppendFormat("&secret={0}", request.Secret); + getResuestUrlBuiilder.AppendFormat("&js_code={0}", request.Code); + getResuestUrlBuiilder.Append("&grant_type=authorization_code"); + + var getRequest = new HttpRequestMessage(HttpMethod.Get, getResuestUrlBuiilder.ToString()); + HttpResponseMessage httpResponse; + + httpResponse = await client.SendAsync(getRequest, cancellationToken).ConfigureAwait(false); + + return httpResponse; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Common.EventBus/LINGYUN/Common/EventBus/Tenants/CreateEventData.cs b/aspnet-core/modules/common/LINGYUN.Common.EventBus/LINGYUN/Common/EventBus/Tenants/CreateEventData.cs index 09b6d2cc8..5585cb3b9 100644 --- a/aspnet-core/modules/common/LINGYUN.Common.EventBus/LINGYUN/Common/EventBus/Tenants/CreateEventData.cs +++ b/aspnet-core/modules/common/LINGYUN.Common.EventBus/LINGYUN/Common/EventBus/Tenants/CreateEventData.cs @@ -10,6 +10,8 @@ namespace LINGYUN.Common.EventBus.Tenants public string Name { get; set; } + public Guid AdminUserId { get; set; } + public string AdminEmailAddress { get; set; } public string AdminPassword { get; set; } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/ApiResources/ApiResourceAppService.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/ApiResources/ApiResourceAppService.cs index 21c238f41..5b402f61f 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/ApiResources/ApiResourceAppService.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/ApiResources/ApiResourceAppService.cs @@ -31,7 +31,8 @@ namespace LINGYUN.Abp.IdentityServer.ApiResources public virtual async Task> GetAsync(ApiResourceGetByPagedInputDto apiResourceGetByPaged) { var apiResources = await ApiResourceRepository.GetListAsync(apiResourceGetByPaged.Sorting, - apiResourceGetByPaged.SkipCount, apiResourceGetByPaged.MaxResultCount); + apiResourceGetByPaged.SkipCount, apiResourceGetByPaged.MaxResultCount, + apiResourceGetByPaged.Filter); var apiResourceCount = await ApiResourceRepository.GetCountAsync(); return new PagedResultDto(apiResourceCount, diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN.Abp.IdentityServer.SmsValidator.csproj b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN.Abp.IdentityServer.SmsValidator.csproj index 9eb0d5c96..04ede37ff 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN.Abp.IdentityServer.SmsValidator.csproj +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN.Abp.IdentityServer.SmsValidator.csproj @@ -6,13 +6,13 @@ - - + + - - + + diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerSmsValidatorModule.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerSmsValidatorModule.cs index 0a3d1975c..9c628fe08 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerSmsValidatorModule.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/AbpIdentityServerSmsValidatorModule.cs @@ -30,7 +30,7 @@ namespace LINGYUN.Abp.IdentityServer { options.Resources .Get() - .AddVirtualJson("/LINGYUN/Abp/IdentityServer/Localization/Resources"); + .AddVirtualJson("/LINGYUN/Abp/IdentityServer/Localization/SmsValidator"); }); } } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/SmsValidator/en.json similarity index 100% rename from aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json rename to aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/SmsValidator/en.json diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/SmsValidator/zh-Hans.json similarity index 100% rename from aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json rename to aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.SmsValidator/LINGYUN/Abp/IdentityServer/Localization/SmsValidator/zh-Hans.json diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj index 71e468153..8d337c0be 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj @@ -3,6 +3,13 @@ netstandard2.0 + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/CleanupNotificationJobArgs.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/CleanupNotificationJobArgs.cs deleted file mode 100644 index 03536e0da..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/CleanupNotificationJobArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace LINGYUN.Abp.MessageService.Notifications -{ - public class CleanupNotificationJobArgs - { - /// - /// 清理大小 - /// - public int Count { get; set; } - /// - /// 清理租户 - /// - public Guid? TenantId { get; set; } - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs index 83de31bff..4e4d39cd6 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs @@ -2,6 +2,8 @@ { public class NotificationConsts { + public const int MaxCateGoryLength = 50; + public const int MaxNameLength = 100; public const int MaxDataLength = 1024 * 1024; diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs index d7a583b55..3a70048aa 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs @@ -3,5 +3,7 @@ public class SubscribeConsts { public const int MaxNotificationNameLength = 100; + + public const int MaxUserNameLength = 128; } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/MultiTenancy/TenantNotificationNames.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/MultiTenancy/TenantNotificationNames.cs new file mode 100644 index 000000000..e7bea5455 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/MultiTenancy/TenantNotificationNames.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.MultiTenancy +{ + public class TenantNotificationNames + { + public const string GroupName = "Volo.Abp.MultiTenancy"; + + public const string NewTenantRegistered = GroupName + ".NewTenantRegistered"; + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/Notifications/UserNotificationNames.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/UserNotificationNames.cs similarity index 82% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/Notifications/UserNotificationNames.cs rename to aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/UserNotificationNames.cs index dc8063377..877517c08 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/Notifications/UserNotificationNames.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/UserNotificationNames.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.Users.Notifications +namespace Volo.Abp.Users { public class UserNotificationNames { diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj index 8ae03890c..576b98e94 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj @@ -3,6 +3,13 @@ netstandard2.0 + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/BackgroundJobs/NotificationExpritionCleanupJob.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/BackgroundJobs/NotificationExpritionCleanupJob.cs deleted file mode 100644 index 7a342922e..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/BackgroundJobs/NotificationExpritionCleanupJob.cs +++ /dev/null @@ -1,37 +0,0 @@ -using LINGYUN.Abp.MessageService.Notifications; -using System.Threading.Tasks; -using Volo.Abp.BackgroundJobs; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; - -namespace LINGYUN.Abp.MessageService.BackgroundJobs -{ - public class NotificationExpritionCleanupJob : AsyncBackgroundJob - { - private readonly ICurrentTenant _currentTenant; - private readonly IUnitOfWorkManager _unitOfWorkManager; - private readonly INotificationRepository _notificationRepository; - public NotificationExpritionCleanupJob( - ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager, - INotificationRepository notificationRepository) - { - _currentTenant = currentTenant; - _unitOfWorkManager = unitOfWorkManager; - _notificationRepository = notificationRepository; - } - - public override async Task ExecuteAsync(CleanupNotificationJobArgs args) - { - using (var unitOfWork = _unitOfWorkManager.Begin()) - { - using (_currentTenant.Change(args.TenantId)) - { - await _notificationRepository.DeleteExpritionAsync(args.Count); - - await unitOfWork.SaveChangesAsync(); - } - } - } - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs index 0b2cb061e..672f1cb08 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs @@ -10,7 +10,6 @@ using Volo.Abp.EventBus; using Volo.Abp.Localization; using Volo.Abp.Settings; using Volo.Abp.Users; -using Volo.Abp.Users.Notifications; namespace LINGYUN.Abp.MessageService.EventBus { @@ -18,24 +17,26 @@ namespace LINGYUN.Abp.MessageService.EventBus { private readonly ISettingProvider _settingProvider; private readonly IStringLocalizer _stringLocalizer; - private readonly INotificationStore _notificationStore; + private readonly INotificationDispatcher _notificationDispatcher; + private readonly INotificationSubscriptionManager _notificationSubscriptionManager; // 需要模拟用户令牌 // 是否有必要 // private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; public UserCreateSendWelcomeEventHandler( ISettingProvider settingProvider, - INotificationStore notificationStore, INotificationDispatcher notificationDispatcher, - IStringLocalizer stringLocalizer + IStringLocalizer stringLocalizer, + INotificationSubscriptionManager notificationSubscriptionManager //ICurrentPrincipalAccessor currentPrincipalAccessor ) { _settingProvider = settingProvider; _stringLocalizer = stringLocalizer; - _notificationStore = notificationStore; + _notificationDispatcher = notificationDispatcher; + _notificationSubscriptionManager = notificationSubscriptionManager; //_currentPrincipalAccessor = currentPrincipalAccessor; } @@ -51,21 +52,27 @@ namespace LINGYUN.Abp.MessageService.EventBus } using (CultureHelper.Use(userDefaultCultureName, userDefaultCultureName)) { + var userIdentifer = new UserIdentifier(eventData.Entity.Id, eventData.Entity.UserName); // 订阅用户欢迎消息 - await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId, - eventData.Entity.Id, UserNotificationNames.WelcomeToApplication); - - var userWelcomeNotifiction = new NotificationInfo - { - CreationTime = DateTime.Now, - Name = UserNotificationNames.WelcomeToApplication, - NotificationSeverity = NotificationSeverity.Info, - NotificationType = NotificationType.System, - TenantId = eventData.Entity.TenantId - }; - userWelcomeNotifiction.Data.Properties["message"] = L("WelcomeToApplicationFormUser", eventData.Entity.UserName); - - await _notificationDispatcher.DispatcheAsync(userWelcomeNotifiction); + await _notificationSubscriptionManager.SubscribeAsync(eventData.Entity.TenantId, + userIdentifer, UserNotificationNames.WelcomeToApplication); + + // Store未检查已订阅 + //await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId, + // userIdentifer, UserNotificationNames.WelcomeToApplication); + + var userWelcomeNotifictionData = new NotificationData(); + + userWelcomeNotifictionData.WriteStandardData( + L("WelcomeToApplicationFormUser", eventData.Entity.Name ?? eventData.Entity.UserName), + L("WelcomeToApplicationFormUser", eventData.Entity.Name ?? eventData.Entity.UserName), + DateTime.Now, eventData.Entity.UserName); + + // 换成用户名称,而不是用户名 + // userWelcomeNotifictionData.Properties["message"] = L("WelcomeToApplicationFormUser", eventData.Entity.Name); + + var noticeNormalizerName = NotificationNameNormalizer.NormalizerName(UserNotificationNames.WelcomeToApplication); + await _notificationDispatcher.DispatchAsync(noticeNormalizerName, userWelcomeNotifictionData, eventData.Entity.TenantId); } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json index c39859059..4571524e1 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json @@ -7,6 +7,8 @@ "Messages:User:1001": "Users do not receive anonymous comments!", "Messages:User:1002": "The user has rejected all messages!", "Messages:User:1003": "The user rejects the message you sent!", + "WelcomeToApplicationNotification": "User Welcome Notice", + "NewTenantRegisterdNotification": "Tenants create notification", "WelcomeToApplicationFormUser": "User :{0} welcome to join us!" } } \ No newline at end of file diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json index 9a326307b..bfc60566f 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json @@ -7,6 +7,8 @@ "Messages:User:1001": "用户不接收匿名发言!", "Messages:User:1002": "用户已拒接所有消息!", "Messages:User:1003": "用户拒绝您发送的消息!", + "WelcomeToApplicationNotification": "用户欢迎通知", + "NewTenantRegisterdNotification": "租户创建通知", "WelcomeToApplicationFormUser": "用户:{0} 欢迎您的加入!" } } \ No newline at end of file diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs index 631b50e39..3c8bfdc0b 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs @@ -16,6 +16,8 @@ namespace LINGYUN.Abp.MessageService.Mapper CreateMap() .ForMember(dto => dto.Id, map => map.MapFrom(src => src.NotificationId)) .ForMember(dto => dto.Name, map => map.MapFrom(src => src.NotificationName)) + .ForMember(dto => dto.CateGory, map => map.MapFrom(src => src.NotificationCateGory)) + .ForMember(dto => dto.Lifetime, map => map.Ignore()) .ForMember(dto => dto.NotificationType, map => map.MapFrom(src => src.Type)) .ForMember(dto => dto.NotificationSeverity, map => map.MapFrom(src => src.Severity)) .ForMember(dto => dto.Data, map => map.MapFrom((src, nfi) => diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/AbpMessageServiceNotificationDefinitionProvider.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/AbpMessageServiceNotificationDefinitionProvider.cs new file mode 100644 index 000000000..493cf83d0 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/AbpMessageServiceNotificationDefinitionProvider.cs @@ -0,0 +1,34 @@ +using LINGYUN.Abp.MessageService.Localization; +using LINGYUN.Abp.Notifications; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class AbpMessageServiceNotificationDefinitionProvider : NotificationDefinitionProvider + { + public override void Define(INotificationDefinitionContext context) + { + context.Add(new NotificationDefinition( + UserNotificationNames.WelcomeToApplication, + L("WelcomeToApplicationNotification"), + L("WelcomeToApplicationNotification"), + notificationType: NotificationType.System, + lifetime: NotificationLifetime.OnlyOne, + allowSubscriptionToClients: true)); + context.Add(new NotificationDefinition( + TenantNotificationNames.NewTenantRegistered, + L("NewTenantRegisterdNotification"), + L("NewTenantRegisterdNotification"), + notificationType: NotificationType.System, + lifetime: NotificationLifetime.OnlyOne, + allowSubscriptionToClients: true)); + } + + protected LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs index 73f7bf28a..f0a98e351 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs @@ -8,6 +8,8 @@ namespace LINGYUN.Abp.MessageService.Notifications { public interface IUserNotificationRepository : IBasicRepository { + Task AnyAsync(Guid userId, long notificationId); + Task InsertUserNotificationsAsync(IEnumerable userNotifications); Task GetByIdAsync(Guid userId, long notificationId); diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs index 329ae9140..75d49b423 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs @@ -12,16 +12,18 @@ namespace LINGYUN.Abp.MessageService.Notifications public virtual NotificationSeverity Severity { get; protected set; } public virtual NotificationType Type { get; set; } public virtual long NotificationId { get; protected set; } + public virtual string NotificationCateGory { get; protected set; } public virtual string NotificationName { get; protected set; } public virtual string NotificationData { get; protected set; } public virtual string NotificationTypeName { get; protected set; } public virtual DateTime? ExpirationTime { get; set; } public virtual DateTime CreationTime { get; set; } protected Notification(){} - public Notification(long id, string name, string dataType, string data, NotificationSeverity severity = NotificationSeverity.Info) + public Notification(long id, string category, string name, string dataType, string data, NotificationSeverity severity = NotificationSeverity.Info) { NotificationId = id; Severity = severity; + NotificationCateGory = category; NotificationName = name; NotificationData = data; NotificationTypeName = dataType; diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs deleted file mode 100644 index a24a3dae8..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs +++ /dev/null @@ -1,40 +0,0 @@ -using LINGYUN.Abp.Notifications; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace LINGYUN.Abp.MessageService.Notifications -{ - public class NotificationDispatcher : INotificationDispatcher, ITransientDependency - { - protected INotificationStore NotificationStore { get; } - protected INotificationPublisher NotificationPublisher { get; } - - public NotificationDispatcher( - INotificationStore notificationStore, - INotificationPublisher notificationPublisher) - { - NotificationStore = notificationStore; - NotificationPublisher = notificationPublisher; - } - - public virtual async Task DispatcheAsync(NotificationInfo notification) - { - var subscribes = await NotificationStore.GetSubscriptionsAsync(notification.TenantId, notification.Name); - foreach (var subscribe in subscribes) - { - await NotificationStore.InsertUserNotificationAsync(notification, subscribe.UserId); - } - - var subscribeUsers = subscribes.Select(s => s.UserId); - await NotifyAsync(notification, subscribeUsers); - } - - protected virtual async Task NotifyAsync(NotificationInfo notification, IEnumerable userIds) - { - await NotificationPublisher.PublishAsync(notification, userIds); - } - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationPublisher.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationPublisher.cs deleted file mode 100644 index 2288cf3b6..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationPublisher.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace LINGYUN.Abp.MessageService.Notifications -{ - class NotificationPublisher - { - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs index d0130281e..ae4002684 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs @@ -3,6 +3,7 @@ using LINGYUN.Abp.MessageService.Utils; using LINGYUN.Abp.Notifications; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Domain.Services; using Volo.Abp.Json; @@ -43,13 +44,11 @@ namespace LINGYUN.Abp.MessageService.Notifications public async Task ChangeUserNotificationReadStateAsync(Guid? tenantId, Guid userId, long notificationId, NotificationReadState readState) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) { - using (CurrentTenant.Change(tenantId)) - { - await UserNotificationRepository.ChangeUserNotificationReadStateAsync(userId, notificationId, readState); + await UserNotificationRepository.ChangeUserNotificationReadStateAsync(userId, notificationId, readState); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); } } @@ -57,14 +56,23 @@ namespace LINGYUN.Abp.MessageService.Notifications public async Task DeleteNotificationAsync(NotificationInfo notification) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(notification.TenantId)) { - using (CurrentTenant.Change(notification.TenantId)) - { - var notify = await NotificationRepository.GetByIdAsync(notification.Id); - await NotificationRepository.DeleteAsync(notify.Id); + var notify = await NotificationRepository.GetByIdAsync(notification.GetId()); + await NotificationRepository.DeleteAsync(notify.Id); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); + } + } + + [UnitOfWork] + public async Task DeleteNotificationAsync(int batchCount) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + await NotificationRepository.DeleteExpritionAsync(batchCount); + + await unitOfWork.SaveChangesAsync(); } } @@ -72,14 +80,24 @@ namespace LINGYUN.Abp.MessageService.Notifications public async Task DeleteUserNotificationAsync(Guid? tenantId, Guid userId, long notificationId) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) { - using (CurrentTenant.Change(tenantId)) - { - var notify = await UserNotificationRepository.GetByIdAsync(userId, notificationId); - await UserNotificationRepository.DeleteAsync(notify.Id); + var notify = await UserNotificationRepository.GetByIdAsync(userId, notificationId); + await UserNotificationRepository.DeleteAsync(notify.Id); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); + } + } + + [UnitOfWork] + public async Task DeleteAllUserSubscriptionAsync(Guid? tenantId, string notificationName) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) + { + await UserSubscribeRepository.DeleteUserSubscriptionAsync(notificationName); + + await unitOfWork.SaveChangesAsync(); } } @@ -87,14 +105,29 @@ namespace LINGYUN.Abp.MessageService.Notifications public async Task DeleteUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) { - using (CurrentTenant.Change(tenantId)) - { - var userSubscribe = await UserSubscribeRepository.GetUserSubscribeAsync(notificationName, userId); - await UserSubscribeRepository.DeleteAsync(userSubscribe.Id); + var userSubscribe = await UserSubscribeRepository.GetUserSubscribeAsync(notificationName, userId); + await UserSubscribeRepository.DeleteAsync(userSubscribe.Id); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); + } + } + + [UnitOfWork] + public async Task DeleteUserSubscriptionAsync(Guid? tenantId, IEnumerable identifiers, string notificationName) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) + { + // TODO:不追踪用户订阅实体? + var userSubscribes = await UserSubscribeRepository.GetSubscribesAsync(notificationName); + + var removeUserSubscribes = userSubscribes.Where(us => identifiers.Any(id => id.UserId.Equals(us.UserId))); + + await UserSubscribeRepository.DeleteUserSubscriptionAsync(removeUserSubscribes); + + await unitOfWork.SaveChangesAsync(); } } @@ -148,33 +181,52 @@ namespace LINGYUN.Abp.MessageService.Notifications } } + public virtual async Task> GetUserSubscriptionsAsync(Guid? tenantId, string userName) + { + using (CurrentTenant.Change(tenantId)) + { + var userSubscriptions = await UserSubscribeRepository.GetUserSubscribesByNameAsync(userName); + + var userSubscriptionInfos = new List(); + + userSubscriptions.ForEach(us => userSubscriptionInfos.Add( + new NotificationSubscriptionInfo + { + UserId = us.UserId, + TenantId = us.TenantId, + NotificationName = us.NotificationName + })); + + return userSubscriptionInfos; + } + } + [UnitOfWork] public async Task InsertNotificationAsync(NotificationInfo notification) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(notification.TenantId)) { - using (CurrentTenant.Change(notification.TenantId)) + // var notifyId = notification.GetId(); + var notifyId = SnowflakeIdGenerator.Create(); + // 保存主键,防止前端js long类型溢出 + // notification.Data["id"] = notifyId.ToString(); + + var notify = new Notification(notifyId, notification.CateGory, notification.Name, + notification.Data.GetType().AssemblyQualifiedName, + JsonSerializer.Serialize(notification.Data), notification.NotificationSeverity) { - var notifyId = SnowflakeIdGenerator.Create(); - // 保存主键,防止前端js long类型溢出 - notification.Data["id"] = notifyId.ToString(); - - var notify = new Notification(notifyId, notification.Name, - notification.Data.GetType().AssemblyQualifiedName, - JsonSerializer.Serialize(notification.Data), notification.NotificationSeverity) - { - CreationTime = Clock.Now, - Type = notification.NotificationType, - ExpirationTime = Clock.Now.AddDays(60) - }; - notify.SetTenantId(notification.TenantId); + CreationTime = Clock.Now, + Type = notification.NotificationType, + ExpirationTime = Clock.Now.AddDays(60) + }; + notify.SetTenantId(notification.TenantId); - await NotificationRepository.InsertAsync(notify); + await NotificationRepository.InsertAsync(notify); - notification.Id = notify.NotificationId; + notification.Id = notify.NotificationId.ToString(); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); } } @@ -182,55 +234,49 @@ namespace LINGYUN.Abp.MessageService.Notifications public async Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(notification.TenantId)) { - using (CurrentTenant.Change(notification.TenantId)) - { - var userNotification = new UserNotification(notification.Id, userId); - await UserNotificationRepository.InsertAsync(userNotification); + var userNotification = new UserNotification(notification.GetId(), userId, notification.TenantId); + await UserNotificationRepository.InsertAsync(userNotification); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); } } [UnitOfWork] - public async Task InsertUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName) + public async Task InsertUserSubscriptionAsync(Guid? tenantId, UserIdentifier identifier, string notificationName) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) { - using (CurrentTenant.Change(tenantId)) - { - var userSubscription = new UserSubscribe(notificationName, userId) - { - CreationTime = Clock.Now - }; + var userSubscription = new UserSubscribe(notificationName, identifier.UserId, identifier.UserName, tenantId) + { + CreationTime = Clock.Now + }; - await UserSubscribeRepository.InsertAsync(userSubscription); + await UserSubscribeRepository.InsertAsync(userSubscription); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); } } [UnitOfWork] - public async Task InsertUserSubscriptionAsync(Guid? tenantId, IEnumerable userIds, string notificationName) + public async Task InsertUserSubscriptionAsync(Guid? tenantId, IEnumerable identifiers, string notificationName) { using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(tenantId)) { - using (CurrentTenant.Change(tenantId)) - { - var userSubscribes = new List(); + var userSubscribes = new List(); - foreach(var userId in userIds) - { - userSubscribes.Add(new UserSubscribe(notificationName, userId)); - } + foreach (var identifier in identifiers) + { + userSubscribes.Add(new UserSubscribe(notificationName, identifier.UserId, identifier.UserName, tenantId)); + } - await UserSubscribeRepository.InsertUserSubscriptionAsync(userSubscribes); + await UserSubscribeRepository.InsertUserSubscriptionAsync(userSubscribes); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); } } @@ -240,15 +286,28 @@ namespace LINGYUN.Abp.MessageService.Notifications return await UserSubscribeRepository.UserSubscribeExistsAysnc(notificationName, userId); } + [UnitOfWork] public async Task InsertUserNotificationsAsync(NotificationInfo notification, IEnumerable userIds) { - var userNofitications = new List(); - foreach(var userId in userIds) + // 添加工作单元 + using (var unitOfWork = _unitOfWorkManager.Begin()) + using (CurrentTenant.Change(notification.TenantId)) { - var userNofitication = new UserNotification(notification.Id, userId); - userNofitications.Add(userNofitication); + var userNofitications = new List(); + foreach (var userId in userIds) + { + // 重复检查 + // TODO:如果存在很多个订阅用户,这是个隐患 + if (!await UserNotificationRepository.AnyAsync(userId, notification.GetId())) + { + var userNofitication = new UserNotification(notification.GetId(), userId, notification.TenantId); + userNofitications.Add(userNofitication); + } + } + await UserNotificationRepository.InsertUserNotificationsAsync(userNofitications); + + await unitOfWork.SaveChangesAsync(); } - await UserNotificationRepository.InsertUserNotificationsAsync(userNofitications); } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs index 2099b4d06..871866eff 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs @@ -12,11 +12,12 @@ namespace LINGYUN.Abp.MessageService.Notifications public virtual long NotificationId { get; protected set; } public virtual NotificationReadState ReadStatus { get; protected set; } protected UserNotification() { } - public UserNotification(long notificationId, Guid userId) + public UserNotification(long notificationId, Guid userId, Guid? tenantId = null) { UserId = userId; NotificationId = notificationId; ReadStatus = NotificationReadState.UnRead; + TenantId = tenantId; } public void ChangeReadState(NotificationReadState readStatus) diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs index 0615db628..3b3915751 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs @@ -15,8 +15,14 @@ namespace LINGYUN.Abp.MessageService.Subscriptions Task> GetUserSubscribesAsync(Guid userId); + Task> GetUserSubscribesByNameAsync(string userName); + Task> GetUserSubscribesAsync(string notificationName); Task InsertUserSubscriptionAsync(IEnumerable userSubscribes); + + Task DeleteUserSubscriptionAsync(IEnumerable userSubscribes); + + Task DeleteUserSubscriptionAsync(string notificationName); } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs index 4fb6dbc1e..e3fd97d74 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs @@ -13,9 +13,10 @@ namespace LINGYUN.Abp.MessageService.Subscriptions protected Subscribe() { } - protected Subscribe(string notificationName) + protected Subscribe(string notificationName, Guid? tenantId = null) { NotificationName = notificationName; + TenantId = tenantId; } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs index 5c5f03c4c..b6726644e 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs @@ -6,10 +6,13 @@ namespace LINGYUN.Abp.MessageService.Subscriptions public class UserSubscribe : Subscribe, IHasCreationTime { public virtual Guid UserId { get; set; } + public virtual string UserName { get; set; } protected UserSubscribe() { } - public UserSubscribe(string notificationName, Guid userId) : base(notificationName) + public UserSubscribe(string notificationName, Guid userId, string userName, Guid? tenantId = null) + : base(notificationName, tenantId) { UserId = userId; + UserName = userName; } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj index f2ad8207b..57518a766 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj @@ -3,6 +3,14 @@ netstandard2.0 + false + true + 2.9.0 + LINGYUN + + + + D:\LocalNuget diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs index 71e42ab07..c18867104 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs @@ -25,13 +25,14 @@ namespace LINGYUN.Abp.MessageService.EntityFrameworkCore b.ToTable(options.TablePrefix + "Notifications", options.Schema); b.Property(p => p.NotificationName).HasMaxLength(NotificationConsts.MaxNameLength).IsRequired(); + b.Property(p => p.NotificationCateGory).HasMaxLength(NotificationConsts.MaxCateGoryLength).IsRequired(); b.Property(p => p.NotificationTypeName).HasMaxLength(NotificationConsts.MaxTypeNameLength).IsRequired(); b.Property(p => p.NotificationData).HasMaxLength(NotificationConsts.MaxDataLength).IsRequired(); b.ConfigureMultiTenant(); b.ConfigureCreationTime(); - b.HasIndex(p => p.NotificationName); + b.HasIndex(p => new { p.TenantId, p.NotificationName }); }); builder.Entity(b => @@ -49,6 +50,10 @@ namespace LINGYUN.Abp.MessageService.EntityFrameworkCore b.ToTable(options.TablePrefix + "UserSubscribes", options.Schema); b.Property(p => p.NotificationName).HasMaxLength(SubscribeConsts.MaxNotificationNameLength).IsRequired(); + b.Property(p => p.UserName) + .HasMaxLength(SubscribeConsts.MaxUserNameLength) + .HasDefaultValue("/")// 不是必须的 + .IsRequired(); b.ConfigureCreationTime(); b.ConfigureMultiTenant(); diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs index 1b1b1e653..e5a674b4c 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs @@ -29,7 +29,9 @@ namespace LINGYUN.Abp.MessageService.Messages var groupAdmins = await (from gp in DbContext.Set() join gpa in DbContext.Set() on gp.GroupId equals gpa.GroupId - select gpa).ToListAsync(); + select gpa) + .Distinct() + .ToListAsync(); return groupAdmins; } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs index 6508e1a83..f0e1b29d7 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs @@ -35,6 +35,7 @@ namespace LINGYUN.Abp.MessageService.Messages skipCount -= 1; } var groupMessages = await DbContext.Set() + .Distinct() .Where(x => x.GroupId.Equals(groupId) && x.Type.Equals(type)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Content.Contains(filter) || x.SendUserName.Contains(filter)) .OrderByDescending(x => x.MessageId) @@ -52,6 +53,7 @@ namespace LINGYUN.Abp.MessageService.Messages skipCount -= 1; } var groupMessages = await DbContext.Set() + .Distinct() .Where(x => x.GroupId.Equals(groupId) && x.CreatorId.Equals(sendUserId) && x.Type.Equals(type)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Content.Contains(filter) || x.SendUserName.Contains(filter)) .OrderByDescending(x => x.MessageId) @@ -77,6 +79,7 @@ namespace LINGYUN.Abp.MessageService.Messages skipCount -= 1; } var userMessages = await DbContext.Set() + .Distinct() .Where(x => x.CreatorId.Equals(sendUserId) && x.ReceiveUserId.Equals(receiveUserId) && x.Type.Equals(type)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Content.Contains(filter) || x.SendUserName.Contains(filter)) .OrderByDescending(x => x.MessageId) diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs index 95cfec605..de852f05c 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs @@ -38,6 +38,7 @@ namespace LINGYUN.Abp.MessageService.Messages TenantId = ug.TenantId, UserId = ug.UserId }) + .Distinct() .AsNoTracking() .ToListAsync(); return groupUsers; @@ -73,7 +74,9 @@ namespace LINGYUN.Abp.MessageService.Messages GroupUserCount = ug.Count(), MaxUserLength = ug.Key.MaxUserCount, Name = ug.Key.Name - }).ToListAsync(); + }) + .Distinct() + .ToListAsync(); return userGroups; } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs index 96d4f55e7..86636675d 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs @@ -20,6 +20,12 @@ namespace LINGYUN.Abp.MessageService.Notifications { } + public async Task AnyAsync(Guid userId, long notificationId) + { + return await DbSet + .AnyAsync(x => x.NotificationId.Equals(notificationId) && x.UserId.Equals(userId)); + } + public async Task InsertUserNotificationsAsync(IEnumerable userNotifications) { await DbSet.AddRangeAsync(userNotifications); @@ -49,9 +55,11 @@ namespace LINGYUN.Abp.MessageService.Notifications join n in DbContext.Set() on un.NotificationId equals n.NotificationId where un.UserId.Equals(userId) && un.ReadStatus.Equals(readState) - select n) - .Take(maxResultCount) - .ToListAsync(); + orderby n.NotificationId descending + select n) + .Distinct() + .Take(maxResultCount) + .ToListAsync(); return userNofitications; } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs index 898701772..7d2178527 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs @@ -21,7 +21,11 @@ namespace LINGYUN.Abp.MessageService.Subscriptions public async Task> GetSubscribesAsync(string notificationName) { - var userSubscribes = await DbSet.Where(x => x.NotificationName.Equals(notificationName)).ToListAsync(); + var userSubscribes = await DbSet + .Distinct() + .Where(x => x.NotificationName.Equals(notificationName)) + .AsNoTracking() + .ToListAsync(); return userSubscribes; } @@ -30,6 +34,7 @@ namespace LINGYUN.Abp.MessageService.Subscriptions { var userSubscribe = await DbSet .Where(x => x.UserId.Equals(userId) && x.NotificationName.Equals(notificationName)) + .AsNoTracking() .FirstOrDefaultAsync(); return userSubscribe; @@ -38,6 +43,7 @@ namespace LINGYUN.Abp.MessageService.Subscriptions public async Task> GetUserSubscribesAsync(Guid userId) { var userSubscribeNames = await DbSet + .Distinct() .Where(x => x.UserId.Equals(userId)) .Select(x => x.NotificationName) .ToListAsync(); @@ -45,9 +51,21 @@ namespace LINGYUN.Abp.MessageService.Subscriptions return userSubscribeNames; } + public async Task> GetUserSubscribesByNameAsync(string userName) + { + var userSubscribeNames = await DbSet + .Distinct() + .Where(x => x.UserName.Equals(userName)) + .AsNoTracking() + .ToListAsync(); + + return userSubscribeNames; + } + public async Task> GetUserSubscribesAsync(string notificationName) { var subscribeUsers = await DbSet + .Distinct() .Where(x => x.NotificationName.Equals(notificationName)) .Select(x => x.UserId) .ToListAsync(); @@ -60,6 +78,18 @@ namespace LINGYUN.Abp.MessageService.Subscriptions await DbSet.AddRangeAsync(userSubscribes); } + public async Task DeleteUserSubscriptionAsync(string notificationName) + { + var userSubscribes = await DbSet.Where(x => x.NotificationName.Equals(notificationName)).ToListAsync(); + DbSet.RemoveRange(userSubscribes); + } + + public Task DeleteUserSubscriptionAsync(IEnumerable userSubscribes) + { + DbSet.RemoveRange(userSubscribes); + return Task.CompletedTask; + } + public async Task UserSubscribeExistsAysnc(string notificationName, Guid userId) { return await DbSet.AnyAsync(x => x.UserId.Equals(userId) && x.NotificationName.Equals(notificationName)); diff --git a/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs b/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs index 4e4c38adf..f45750382 100644 --- a/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs +++ b/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs @@ -63,6 +63,7 @@ namespace LINGYUN.Abp.TenantManagement { Id = tenant.Id, Name = tenant.Name, + AdminUserId = GuidGenerator.Create(), AdminEmailAddress = input.AdminEmailAddress, AdminPassword = input.AdminPassword }; @@ -99,12 +100,7 @@ namespace LINGYUN.Abp.TenantManagement { return; } - var deleteEventData = new DeleteEventData - { - Id = id - }; await TenantRepository.DeleteAsync(tenant); - await EventBus.PublishAsync(deleteEventData); } [Authorize(TenantManagementPermissions.Tenants.ManageConnectionStrings)] diff --git a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs index 2e9890ec2..d8b85a023 100644 --- a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs +++ b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs @@ -18,6 +18,7 @@ using Volo.Abp; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.Auditing; using Volo.Abp.Autofac; +using Volo.Abp.Caching; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.MySQL; @@ -40,6 +41,7 @@ namespace AuthServer.Host typeof(AbpCAPEventBusModule), typeof(AbpIdentityAspNetCoreModule), typeof(AbpIdentityServerSmsValidatorModule), + typeof(AbpIdentityServerWeChatValidatorModule), typeof(AbpEntityFrameworkCoreMySQLModule), typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpIdentityServerEntityFrameworkCoreModule), @@ -63,7 +65,8 @@ namespace AuthServer.Host .UseRabbitMQ(rabbitMQOptions => { configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); - }); + }) + .UseDashboard(); }); } @@ -77,6 +80,15 @@ namespace AuthServer.Host options.UseMySQL(); }); + Configure(options => + { + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpiration = DateTimeOffset.Now.AddDays(60); + options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); + }); + Configure(options => { options.Languages.Add(new LanguageInfo("en", "en", "English")); @@ -105,13 +117,14 @@ namespace AuthServer.Host context.Services.AddStackExchangeRedisCache(options => { - options.InstanceName = configuration["Redis:InstanceName"]; - options.Configuration = configuration["Redis:Configuration"]; + options.Configuration = configuration["RedisCache:ConnectString"]; + var instanceName = configuration["RedisCache:RedisPrefix"]; + options.InstanceName = instanceName.IsNullOrEmpty() ? "MessageService_Cache" : instanceName; }); if (!hostingEnvironment.IsDevelopment()) { - var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); context.Services .AddDataProtection() .PersistKeysToStackExchangeRedis(redis, "AuthServer-Protection-Keys"); @@ -149,6 +162,10 @@ namespace AuthServer.Host app.UseMultiTenancy(); app.UseIdentityServer(); app.UseAuditing(); + + // 处理微信消息 + // app.UseWeChatSignature(); + SeedData(context); } diff --git a/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj b/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj index 2443966f8..45c5bef4f 100644 --- a/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj +++ b/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj @@ -6,17 +6,18 @@ - - + + + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -34,6 +35,7 @@ + diff --git a/aspnet-core/services/account/AuthServer.Host/EventBus/Handlers/TenantCreateEventHandler.cs b/aspnet-core/services/account/AuthServer.Host/EventBus/Handlers/TenantCreateEventHandler.cs index 7181c07ee..dcc69e2e9 100644 --- a/aspnet-core/services/account/AuthServer.Host/EventBus/Handlers/TenantCreateEventHandler.cs +++ b/aspnet-core/services/account/AuthServer.Host/EventBus/Handlers/TenantCreateEventHandler.cs @@ -1,10 +1,16 @@ using LINGYUN.Common.EventBus.Tenants; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Logging; +using System; using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Guids; using Volo.Abp.Identity; -using Volo.Abp.DependencyInjection; -using Microsoft.Extensions.Logging; using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; +using IdentityRole = Volo.Abp.Identity.IdentityRole; +using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace AuthServer.Host.EventBus.Handlers { @@ -12,32 +18,70 @@ namespace AuthServer.Host.EventBus.Handlers { protected ILogger Logger { get; } protected ICurrentTenant CurrentTenant { get; } - protected IIdentityDataSeeder IdentityDataSeeder { get; } + protected IGuidGenerator GuidGenerator { get; } + protected IdentityUserManager IdentityUserManager { get; } + protected IdentityRoleManager IdentityRoleManager { get; } public TenantCreateEventHandler( ICurrentTenant currentTenant, - IIdentityDataSeeder identityDataSeeder, + IGuidGenerator guidGenerator, + IdentityUserManager identityUserManager, + IdentityRoleManager identityRoleManager, ILogger logger) { Logger = logger; CurrentTenant = currentTenant; - IdentityDataSeeder = identityDataSeeder; + GuidGenerator = guidGenerator; + IdentityUserManager = identityUserManager; + IdentityRoleManager = identityRoleManager; } + [UnitOfWork] public async Task HandleEventAsync(CreateEventData eventData) { using (CurrentTenant.Change(eventData.Id, eventData.Name)) { - var identitySeedResult = await IdentityDataSeeder - .SeedAsync(eventData.AdminEmailAddress, eventData.AdminPassword, eventData.Id); - if (!identitySeedResult.CreatedAdminUser) + const string tenantAdminRoleName = "admin"; + var tenantAdminRoleId = Guid.Empty; ; + + if (!await IdentityRoleManager.RoleExistsAsync(tenantAdminRoleName)) { - Logger.LogWarning("Tenant {0} admin user {1} not created!", eventData.Name, eventData.AdminEmailAddress); + tenantAdminRoleId = GuidGenerator.Create(); + var tenantAdminRole = new IdentityRole(tenantAdminRoleId, tenantAdminRoleName, eventData.Id) + { + IsStatic = true, + IsPublic = true + }; + (await IdentityRoleManager.CreateAsync(tenantAdminRole)).CheckErrors(); } - if (!identitySeedResult.CreatedAdminRole) + else { - Logger.LogWarning("Tenant {0} admin role not created!", eventData.Name); + var tenantAdminRole = await IdentityRoleManager.FindByNameAsync(tenantAdminRoleName); + tenantAdminRoleId = tenantAdminRole.Id; + } + + var tenantAdminUser = await IdentityUserManager.FindByNameAsync(eventData.AdminEmailAddress); + if (tenantAdminUser == null) + { + tenantAdminUser = new IdentityUser(eventData.AdminUserId, eventData.AdminEmailAddress, + eventData.AdminEmailAddress, eventData.Id); + + tenantAdminUser.AddRole(tenantAdminRoleId); + + // 创建租户管理用户 + (await IdentityUserManager.CreateAsync(tenantAdminUser)).CheckErrors(); + (await IdentityUserManager.AddPasswordAsync(tenantAdminUser, eventData.AdminPassword)).CheckErrors(); } + //var identitySeedResult = await IdentityDataSeeder + // .SeedAsync(eventData.AdminEmailAddress, eventData.AdminPassword, eventData.Id); + //if (!identitySeedResult.CreatedAdminUser) + //{ + // Logger.LogWarning("Tenant {0} admin user {1} not created!", eventData.Name, eventData.AdminEmailAddress); + //} + //if (!identitySeedResult.CreatedAdminRole) + //{ + // Logger.LogWarning("Tenant {0} admin role not created!", eventData.Name); + //} } } } diff --git a/aspnet-core/services/account/AuthServer.Host/IdentityServer/IdentityServerDataSeedContributor.cs b/aspnet-core/services/account/AuthServer.Host/IdentityServer/IdentityServerDataSeedContributor.cs index f05e4d42a..5356e5842 100644 --- a/aspnet-core/services/account/AuthServer.Host/IdentityServer/IdentityServerDataSeedContributor.cs +++ b/aspnet-core/services/account/AuthServer.Host/IdentityServer/IdentityServerDataSeedContributor.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Configuration; +using LINGYUN.Abp.IdentityServer.WeChatValidator; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; @@ -8,6 +9,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; +using Volo.Abp.Identity; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; using Volo.Abp.IdentityServer.IdentityResources; @@ -21,6 +23,7 @@ namespace Multicolin.Aftermarket.IdentityServer private readonly IApiResourceRepository _apiResourceRepository; private readonly IClientRepository _clientRepository; private readonly IIdentityResourceDataSeeder _identityResourceDataSeeder; + private readonly IIdentityClaimTypeRepository _identityClaimTypeRepository; private readonly IPermissionDataSeeder _permissionDataSeeder; private readonly IGuidGenerator _guidGenerator; private readonly IConfiguration _configuration; @@ -30,11 +33,13 @@ namespace Multicolin.Aftermarket.IdentityServer IPermissionDataSeeder permissionDataSeeder, IApiResourceRepository apiResourceRepository, IIdentityResourceDataSeeder identityResourceDataSeeder, + IIdentityClaimTypeRepository identityClaimTypeRepository, IGuidGenerator guidGenerator) { _clientRepository = clientRepository; _permissionDataSeeder = permissionDataSeeder; _apiResourceRepository = apiResourceRepository; + _identityClaimTypeRepository = identityClaimTypeRepository; _identityResourceDataSeeder = identityResourceDataSeeder; _guidGenerator = guidGenerator; var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"; @@ -52,6 +57,18 @@ namespace Multicolin.Aftermarket.IdentityServer await _identityResourceDataSeeder.CreateStandardResourcesAsync(); await CreateApiResourcesAsync(); await CreateClientsAsync(); + await CreateWeChatClaimTypeAsync(); + } + + private async Task CreateWeChatClaimTypeAsync() + { + if (!await _identityClaimTypeRepository.AnyAsync(WeChatValidatorConsts.ClaimTypes.OpenId)) + { + var wechatClaimType = new IdentityClaimType(_guidGenerator.Create(), WeChatValidatorConsts.ClaimTypes.OpenId, + isStatic: true, description: "适用于微信认证的用户标识"); + + await _identityClaimTypeRepository.InsertAsync(wechatClaimType); + } } private async Task CreateApiResourcesAsync() diff --git a/aspnet-core/services/account/AuthServer.Host/Properties/launchSettings.json b/aspnet-core/services/account/AuthServer.Host/Properties/launchSettings.json index 581e8d94f..3e2911416 100644 --- a/aspnet-core/services/account/AuthServer.Host/Properties/launchSettings.json +++ b/aspnet-core/services/account/AuthServer.Host/Properties/launchSettings.json @@ -11,7 +11,7 @@ "AuthServer.Host": { "commandName": "Project", "launchBrowser": false, - "applicationUrl": "http://localhost:44385", + "applicationUrl": "https://localhost:44386;http://localhost:44385", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj index 69f88f285..e02f5665d 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN.ApiGateway.Host.csproj @@ -25,6 +25,7 @@ + diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs index 8eb8eae72..6284a67b1 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs @@ -1,7 +1,8 @@ -using Microsoft.AspNetCore.Builder; +using DotNetCore.CAP; +using LINGYUN.Abp.EventBus.CAP; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Ocelot.Configuration.Repository; using Ocelot.DependencyInjection; using Ocelot.Extenssions; @@ -11,9 +12,7 @@ using Volo.Abp; using Volo.Abp.AspNetCore; using Volo.Abp.Autofac; using Volo.Abp.AutoMapper; -using Volo.Abp.Http.Client; using Volo.Abp.Http.Client.IdentityModel; -using Volo.Abp.IdentityModel; using Volo.Abp.Modularity; namespace LINGYUN.ApiGateway @@ -23,10 +22,33 @@ namespace LINGYUN.ApiGateway typeof(AbpHttpClientIdentityModelModule), typeof(AbpAutoMapperModule), typeof(ApiGatewayHttpApiClientModule), + typeof(AbpCAPEventBusModule), typeof(AbpAspNetCoreModule) )] public class ApiGatewayHostModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + // 不启用则使用本地配置文件的方式启动Ocelot + if (configuration.GetValue("EnabledDynamicOcelot")) + { + context.Services.AddSingleton(); + } + + PreConfigure(options => + { + options + .UseInMemoryStorage() + .UseDashboard() + .UseRabbitMQ(rabbitMQOptions => + { + configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); + }); + }); + } + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); @@ -39,13 +61,6 @@ namespace LINGYUN.ApiGateway Configure(configuration.GetSection("ApiGateway")); - // 不启用则使用本地配置文件的方式启动Ocelot - if (configuration.GetValue("EnabledDynamicOcelot")) - { - context.Services.AddSingleton(); - ConfigureCAP(context.Services, configuration); - } - context.Services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { @@ -64,34 +79,11 @@ namespace LINGYUN.ApiGateway public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); - var env = context.GetEnvironment(); app.UseAuditing(); // 启用ws协议 app.UseWebSockets(); app.UseOcelot().Wait(); } - - private void ConfigureCAP(IServiceCollection services, IConfiguration configuration) - { - services.AddCap(x => - { - x.UseInMemoryStorage(); - - x.UseDashboard(); - - x.UseRabbitMQ(cfg => - { - cfg.HostName = configuration.GetValue("CAP:RabbitMQ:Connect:Host"); - cfg.VirtualHost = configuration.GetValue("CAP:RabbitMQ:Connect:VirtualHost"); - cfg.Port = configuration.GetValue("CAP:RabbitMQ:Connect:Port"); - cfg.UserName = configuration.GetValue("CAP:RabbitMQ:Connect:UserName"); - cfg.Password = configuration.GetValue("CAP:RabbitMQ:Connect:Password"); - cfg.ExchangeName = configuration.GetValue("CAP:RabbitMQ:Connect:ExchangeName"); - }); - - x.FailedRetryCount = 5; - }); - } } } diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeEventHandler.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeEventHandler.cs new file mode 100644 index 000000000..63b3513b6 --- /dev/null +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/ApigatewayConfigChangeEventHandler.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.Repository; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; + +namespace LINGYUN.ApiGateway.EventBus +{ + public class ApigatewayConfigChangeEventHandler : IDistributedEventHandler, ITransientDependency + { + protected ApiGatewayOptions Options { get; } + private readonly ILogger _logger; + + private readonly IFileConfigurationRepository _fileConfigRepo; + private readonly IInternalConfigurationRepository _internalConfigRepo; + private readonly IInternalConfigurationCreator _internalConfigCreator; + public ApigatewayConfigChangeEventHandler( + IOptions options, + IFileConfigurationRepository fileConfigRepo, + IInternalConfigurationRepository internalConfigRepo, + IInternalConfigurationCreator internalConfigCreator, + ILogger logger) + { + _fileConfigRepo = fileConfigRepo; + _internalConfigRepo = internalConfigRepo; + _internalConfigCreator = internalConfigCreator; + _logger = logger; + + Options = options.Value; + } + + public async Task HandleEventAsync(ApigatewayConfigChangeEventData eventData) + { + if (Options.AppId.Equals(eventData.AppId)) + { + var fileConfig = await _fileConfigRepo.Get(); + + if (fileConfig.IsError) + { + _logger.LogWarning($"error geting file config, errors are {string.Join(",", fileConfig.Errors.Select(x => x.Message))}"); + return; + } + else + { + var config = await _internalConfigCreator.Create(fileConfig.Data); + if (!config.IsError) + { + _internalConfigRepo.AddOrReplace(config.Data); + } + } + _logger.LogInformation("ocelot configuration changed on {0}", eventData.DateTime); + } + } + } +} diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/IOcelotConfigurationChangedEvent.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/IOcelotConfigurationChangedEvent.cs deleted file mode 100644 index eb2ba6d60..000000000 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/IOcelotConfigurationChangedEvent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace LINGYUN.ApiGateway.EventBus -{ - public interface IOcelotConfigurationChangedEvent - { - Task OnOcelotConfigurationChanged(ApigatewayConfigChangeCommand changeCommand); - } -} diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/OcelotConfigurationChangedEvent.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/OcelotConfigurationChangedEvent.cs deleted file mode 100644 index d91cefe17..000000000 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/EventBus/OcelotConfigurationChangedEvent.cs +++ /dev/null @@ -1,52 +0,0 @@ -using DotNetCore.CAP; -using LINGYUN.ApiGateway.Ocelot; -using Microsoft.Extensions.Logging; -using Ocelot.Configuration.Creator; -using Ocelot.Configuration.Repository; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace LINGYUN.ApiGateway.EventBus -{ - public class OcelotConfigurationChangedEvent : IOcelotConfigurationChangedEvent, ITransientDependency, ICapSubscribe - { - private readonly ILogger _logger; - - private readonly IFileConfigurationRepository _fileConfigRepo; - private readonly IInternalConfigurationRepository _internalConfigRepo; - private readonly IInternalConfigurationCreator _internalConfigCreator; - public OcelotConfigurationChangedEvent( - IFileConfigurationRepository fileConfigRepo, - IInternalConfigurationRepository internalConfigRepo, - IInternalConfigurationCreator internalConfigCreator, - ILogger logger) - { - _fileConfigRepo = fileConfigRepo; - _internalConfigRepo = internalConfigRepo; - _internalConfigCreator = internalConfigCreator; - _logger = logger; - } - - [CapSubscribe(ApigatewayConfigChangeCommand.EventName)] - public async Task OnOcelotConfigurationChanged(ApigatewayConfigChangeCommand changeCommand) - { - var fileConfig = await _fileConfigRepo.Get(); - - if (fileConfig.IsError) - { - _logger.LogWarning($"error geting file config, errors are {string.Join(",", fileConfig.Errors.Select(x => x.Message))}"); - return; - } - else - { - var config = await _internalConfigCreator.Create(fileConfig.Data); - if (!config.IsError) - { - _internalConfigRepo.AddOrReplace(config.Data); - } - } - _logger.LogInformation("ocelot configuration changed on {0}", changeCommand.DateTime); - } - } -} diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs index 4e37195c4..08d857f2a 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs @@ -1,5 +1,7 @@ -using DotNetCore.CAP.Messages; +using DotNetCore.CAP; +using DotNetCore.CAP.Messages; using IdentityModel; +using LINGYUN.Abp.EventBus.CAP; using LINGYUN.ApiGateway.EntityFrameworkCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; @@ -35,10 +37,26 @@ namespace LINGYUN.ApiGateway typeof(AbpTenantManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), + typeof(AbpCAPEventBusModule), typeof(AbpAutofacModule) )] public class ApiGatewayHttpApiHostModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + PreConfigure(options => + { + options + .UseMySql(configuration.GetConnectionString("Default")) + .UseRabbitMQ(rabbitMQOptions => + { + configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); + }); + }); + } + public override void ConfigureServices(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); @@ -96,34 +114,6 @@ namespace LINGYUN.ApiGateway options.InstanceName = instanceName.IsNullOrEmpty() ? "ApiGateway_Cache" : instanceName; }); - context.Services.AddCap(x => - { - x.UseEntityFramework(); - - x.UseDashboard(); - - x.UseRabbitMQ(cfg => - { - cfg.HostName = configuration["CAP:RabbitMQ:Connect:Host"]; - cfg.VirtualHost = configuration["CAP:RabbitMQ:Connect:VirtualHost"]; - cfg.UserName = configuration["CAP:RabbitMQ:Connect:UserName"]; - cfg.Password = configuration["CAP:RabbitMQ:Connect:Password"]; - cfg.ExchangeName = configuration["CAP:RabbitMQ:Connect:ExchangeName"]; - cfg.Port = configuration.GetValue("CAP:RabbitMQ:Connect:Port"); - }); - - x.FailedRetryCount = 5; - - x.FailedThresholdCallback = (type, message) => - { - // 是订阅者的错误 - if (type == MessageType.Subscribe) - { - Console.WriteLine(message); - } - }; - }); - if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj index 572a7f95e..e9f0df4ff 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj @@ -39,6 +39,7 @@ + diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/20200618090102_Modify-ReRoute-Index-Unique.Designer.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/20200618090102_Modify-ReRoute-Index-Unique.Designer.cs new file mode 100644 index 000000000..e92a50cc1 --- /dev/null +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/20200618090102_Modify-ReRoute-Index-Unique.Designer.cs @@ -0,0 +1,881 @@ +// +using System; +using LINGYUN.ApiGateway.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.ApiGateway.HttpApi.Host.Migrations +{ + [DbContext(typeof(HttpApiHostMigrationsDbContext))] + [Migration("20200618090102_Modify-ReRoute-Index-Unique")] + partial class ModifyReRouteIndexUnique + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.AggregateReRoute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Aggregator") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("AppId") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Name") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("ReRouteIsCaseSensitive") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("ReRouteKeys") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("UpstreamHost") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("UpstreamHttpMethod") + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("UpstreamPathTemplate") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.HasKey("Id"); + + b.ToTable("AppApiGatewayAggregate"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.AggregateReRouteConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AggregateReRouteId") + .HasColumnType("int"); + + b.Property("JsonPath") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Parameter") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("ReRouteKey") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("AggregateReRouteId"); + + b.ToTable("AppApiGatewayAggregateConfig"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.AuthenticationOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AllowedScopes") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("AuthenticationProviderKey") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewayAuthOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.CacheOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("Region") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("TtlSeconds") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewayCacheOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.DynamicReRoute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("DownstreamHttpVersion") + .HasColumnType("varchar(30) CHARACTER SET utf8mb4") + .HasMaxLength(30); + + b.Property("DynamicReRouteId") + .HasColumnType("bigint"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("ServiceName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.HasKey("Id"); + + b.ToTable("AppApiGatewayDynamicReRoute"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("BaseUrl") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("DownstreamHttpVersion") + .HasColumnType("varchar(30) CHARACTER SET utf8mb4") + .HasMaxLength(30); + + b.Property("DownstreamScheme") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("ItemId") + .HasColumnType("bigint"); + + b.Property("RequestIdKey") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.HasKey("Id"); + + b.ToTable("AppApiGatewayGlobalConfiguration"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.Headers", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("Value") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.ToTable("AppApiGatewayHeaders"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.HostAndPort", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Host") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("Port") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("AppApiGatewayHostAndPort"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.HttpHandlerOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AllowAutoRedirect") + .HasColumnType("tinyint(1)"); + + b.Property("ItemId") + .HasColumnType("bigint"); + + b.Property("MaxConnectionsPerServer") + .HasColumnType("int"); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("UseCookieContainer") + .HasColumnType("tinyint(1)"); + + b.Property("UseProxy") + .HasColumnType("tinyint(1)"); + + b.Property("UseTracing") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("ItemId") + .IsUnique(); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewayHttpOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.LoadBalancerOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Expiry") + .HasColumnType("int"); + + b.Property("ItemId") + .HasColumnType("bigint"); + + b.Property("Key") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("Type") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.HasKey("Id"); + + b.HasIndex("ItemId") + .IsUnique(); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewayBalancerOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.QoSOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("DurationOfBreak") + .HasColumnType("int"); + + b.Property("ExceptionsAllowedBeforeBreaking") + .HasColumnType("int"); + + b.Property("ItemId") + .HasColumnType("bigint"); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("TimeoutValue") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ItemId") + .IsUnique(); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewayQoSOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.RateLimitOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientIdHeader") + .ValueGeneratedOnAdd() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50) + .HasDefaultValue("ClientId"); + + b.Property("DisableRateLimitHeaders") + .HasColumnType("tinyint(1)"); + + b.Property("HttpStatusCode") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(429); + + b.Property("ItemId") + .HasColumnType("bigint"); + + b.Property("QuotaExceededMessage") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("RateLimitCounterPrefix") + .ValueGeneratedOnAdd() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50) + .HasDefaultValue("ocelot"); + + b.HasKey("Id"); + + b.HasIndex("ItemId") + .IsUnique(); + + b.ToTable("AppApiGatewayRateLimitOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.RateLimitRule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClientWhitelist") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DynamicReRouteId") + .HasColumnType("bigint"); + + b.Property("EnableRateLimiting") + .HasColumnType("tinyint(1)"); + + b.Property("Limit") + .HasColumnType("bigint"); + + b.Property("Period") + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("PeriodTimespan") + .HasColumnType("double"); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("DynamicReRouteId") + .IsUnique(); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewayRateLimitRule"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.ReRoute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AddClaimsToRequest") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("AddHeadersToRequest") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("AddQueriesToRequest") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("AppId") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("ChangeDownstreamPathTemplate") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("DangerousAcceptAnyServerCertificateValidator") + .HasColumnType("tinyint(1)"); + + b.Property("DelegatingHandlers") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DownstreamHeaderTransform") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DownstreamHostAndPorts") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DownstreamHttpMethod") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("DownstreamHttpVersion") + .HasColumnType("varchar(30) CHARACTER SET utf8mb4") + .HasMaxLength(30); + + b.Property("DownstreamPathTemplate") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("DownstreamScheme") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Key") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("Priority") + .HasColumnType("int"); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.Property("ReRouteIsCaseSensitive") + .HasColumnType("tinyint(1)"); + + b.Property("ReRouteName") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("RequestIdKey") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("RouteClaimsRequirement") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("ServiceName") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("ServiceNamespace") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("Timeout") + .HasColumnType("int"); + + b.Property("UpstreamHeaderTransform") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("UpstreamHost") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("UpstreamHttpMethod") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("UpstreamPathTemplate") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.HasKey("Id"); + + b.HasIndex("AppId", "DownstreamPathTemplate", "UpstreamPathTemplate") + .IsUnique(); + + b.ToTable("AppApiGatewayReRoute"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.RouteGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AppId") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("AppIpAddress") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("AppName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsActive") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.HasKey("Id"); + + b.HasIndex("AppId", "AppName", "AppIpAddress"); + + b.ToTable("AppApiGatewayRouteGroup"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.SecurityOptions", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("IPAllowedList") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("IPBlockedList") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("ReRouteId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ReRouteId") + .IsUnique(); + + b.ToTable("AppApiGatewaySecurityOptions"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.ServiceDiscoveryProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ConfigurationKey") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Host") + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("ItemId") + .HasColumnType("bigint"); + + b.Property("Namespace") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("PollingInterval") + .HasColumnType("int"); + + b.Property("Port") + .HasColumnType("int"); + + b.Property("Scheme") + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("Token") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Type") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.HasKey("Id"); + + b.HasIndex("ItemId") + .IsUnique(); + + b.ToTable("AppApiGatewayDiscovery"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.AggregateReRouteConfig", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.AggregateReRoute", null) + .WithMany("ReRouteKeysConfig") + .HasForeignKey("AggregateReRouteId"); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.AuthenticationOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("AuthenticationOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.AuthenticationOptions", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.CacheOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("CacheOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.CacheOptions", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.HttpHandlerOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "GlobalConfiguration") + .WithOne("HttpHandlerOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.HttpHandlerOptions", "ItemId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "ItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("HttpHandlerOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.HttpHandlerOptions", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.LoadBalancerOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "GlobalConfiguration") + .WithOne("LoadBalancerOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.LoadBalancerOptions", "ItemId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "ItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("LoadBalancerOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.LoadBalancerOptions", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.QoSOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "GlobalConfiguration") + .WithOne("QoSOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.QoSOptions", "ItemId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "ItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("QoSOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.QoSOptions", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.RateLimitOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "GlobalConfiguration") + .WithOne("RateLimitOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.RateLimitOptions", "ItemId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.RateLimitRule", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.DynamicReRoute", "DynamicReRoute") + .WithOne("RateLimitRule") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.RateLimitRule", "DynamicReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.DynamicReRoute", "DynamicReRouteId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("RateLimitOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.RateLimitRule", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.SecurityOptions", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRoute") + .WithOne("SecurityOptions") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.SecurityOptions", "ReRouteId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.ReRoute", "ReRouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.ServiceDiscoveryProvider", b => + { + b.HasOne("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "GlobalConfiguration") + .WithOne("ServiceDiscoveryProvider") + .HasForeignKey("LINGYUN.ApiGateway.Ocelot.ServiceDiscoveryProvider", "ItemId") + .HasPrincipalKey("LINGYUN.ApiGateway.Ocelot.GlobalConfiguration", "ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/20200618090102_Modify-ReRoute-Index-Unique.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/20200618090102_Modify-ReRoute-Index-Unique.cs new file mode 100644 index 000000000..eef1c3614 --- /dev/null +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/20200618090102_Modify-ReRoute-Index-Unique.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.ApiGateway.HttpApi.Host.Migrations +{ + public partial class ModifyReRouteIndexUnique : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_AppApiGatewayReRoute_DownstreamPathTemplate_UpstreamPathTemp~", + table: "AppApiGatewayReRoute"); + + migrationBuilder.CreateIndex( + name: "IX_AppApiGatewayReRoute_AppId_DownstreamPathTemplate_UpstreamPa~", + table: "AppApiGatewayReRoute", + columns: new[] { "AppId", "DownstreamPathTemplate", "UpstreamPathTemplate" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_AppApiGatewayReRoute_AppId_DownstreamPathTemplate_UpstreamPa~", + table: "AppApiGatewayReRoute"); + + migrationBuilder.CreateIndex( + name: "IX_AppApiGatewayReRoute_DownstreamPathTemplate_UpstreamPathTemp~", + table: "AppApiGatewayReRoute", + columns: new[] { "DownstreamPathTemplate", "UpstreamPathTemplate" }, + unique: true); + } + } +} diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/HttpApiHostMigrationsDbContextModelSnapshot.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/HttpApiHostMigrationsDbContextModelSnapshot.cs index 8485ba7cc..b0dc27b8e 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/HttpApiHostMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/Migrations/HttpApiHostMigrationsDbContextModelSnapshot.cs @@ -4,6 +4,7 @@ using LINGYUN.ApiGateway.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; namespace LINGYUN.ApiGateway.HttpApi.Host.Migrations { @@ -14,7 +15,8 @@ namespace LINGYUN.ApiGateway.HttpApi.Host.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.3") + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("LINGYUN.ApiGateway.Ocelot.AggregateReRoute", b => @@ -603,7 +605,7 @@ namespace LINGYUN.ApiGateway.HttpApi.Host.Migrations b.HasKey("Id"); - b.HasIndex("DownstreamPathTemplate", "UpstreamPathTemplate") + b.HasIndex("AppId", "DownstreamPathTemplate", "UpstreamPathTemplate") .IsUnique(); b.ToTable("AppApiGatewayReRoute"); diff --git a/aspnet-core/services/cleanup-logs.bat b/aspnet-core/services/cleanup-logs.bat index 6375621d7..4afd1f6ef 100644 --- a/aspnet-core/services/cleanup-logs.bat +++ b/aspnet-core/services/cleanup-logs.bat @@ -4,8 +4,9 @@ chcp 65001 echo. 清理所有服务日志 -del .\platform\LINGYUN.Platform.HttpApi.Host\Logs /y -del .\apigateway\LINGYUN.ApiGateway.Host\Logs /y -del .\apigateway\LINGYUN.ApiGateway.HttpApi.Host\Logs /y -del .\account\AuthServer.Host\Logs /y +del .\platform\LINGYUN.Platform.HttpApi.Host\Logs /Q +del .\apigateway\LINGYUN.ApiGateway.Host\Logs /Q +del .\apigateway\LINGYUN.ApiGateway.HttpApi.Host\Logs /Q +del .\account\AuthServer.Host\Logs /Q +del .\messages\LINGYUN.Abp.MessageService.HttpApi.Host\Logs /Q diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/BackgroundJobs/NotificationCleanupExpritionJob.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/BackgroundJobs/NotificationCleanupExpritionJob.cs new file mode 100644 index 000000000..591ced1b8 --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/BackgroundJobs/NotificationCleanupExpritionJob.cs @@ -0,0 +1,38 @@ +using LINGYUN.Abp.Notifications; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.MessageService.BackgroundJobs +{ + internal class NotificationCleanupExpritionJob : AsyncBackgroundJob, ITransientDependency + { + protected INotificationStore Store { get; } + protected IServiceProvider ServiceProvider { get; } + + public NotificationCleanupExpritionJob( + INotificationStore store, + IServiceProvider serviceProvider) + { + Store = store; + ServiceProvider = serviceProvider; + } + + public override async Task ExecuteAsync(NotificationCleanupExpritionJobArgs args) + { + try + { + Logger.LogDebug("Before cleanup exprition jobs..."); + await Store.DeleteNotificationAsync(args.Count); + Logger.LogDebug("Exprition jobs cleanup job was successful..."); + } + catch (Exception ex) + { + Logger.LogWarning("Exprition jobs cleanup job was failed..."); + Logger.LogWarning("Error:{0}", ex.Message); + } + } + } +} diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/BackgroundJobs/NotificationCleanupExpritionJobArgs.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/BackgroundJobs/NotificationCleanupExpritionJobArgs.cs new file mode 100644 index 000000000..73b57110a --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/BackgroundJobs/NotificationCleanupExpritionJobArgs.cs @@ -0,0 +1,23 @@ +using Volo.Abp.BackgroundJobs; + +namespace LINGYUN.Abp.MessageService.BackgroundJobs +{ + [BackgroundJobName("定时清理过期通知消息任务")] + internal class NotificationCleanupExpritionJobArgs + { + /// + /// 清理大小 + /// + public int Count { get; set; } + + public NotificationCleanupExpritionJobArgs() + { + + } + + public NotificationCleanupExpritionJobArgs(int count = 200) + { + Count = count; + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs similarity index 50% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs index fc87e40a4..ba1909d8e 100644 --- a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs @@ -17,26 +17,37 @@ namespace LINGYUN.Abp.MessageService.Controllers _notificationDispatcher = notificationDispatcher; } - [HttpPost] - [Route("Send")] - public async Task SendNofitication([FromForm] SendNotification notification) + [HttpGet] + [Route("Test")] + public async Task> Test() { - var notificationInfo = new NotificationInfo + await Task.CompletedTask; + + return new Dictionary() { - TenantId = null, - NotificationSeverity = notification.Severity, - NotificationType = NotificationType.Application, - Id = new Random().Next(int.MinValue, int.MaxValue), - Name = "TestApplicationNotofication", - CreationTime = Clock.Now + {"thing2", "测试标题" }, + {"name3", "测试人员" }, }; - notificationInfo.Data.Properties["id"] = notificationInfo.Id.ToString(); - notificationInfo.Data.Properties["title"] = notification.Title; - notificationInfo.Data.Properties["message"] = notification.Message; - notificationInfo.Data.Properties["datetime"] = Clock.Now; - notificationInfo.Data.Properties["severity"] = notification.Severity; + } + + [HttpPost] + [Route("Send")] + public async Task SendNofitication([FromBody] SendNotification notification) + { + var notificationData = new NotificationData(); + notificationData.Properties["title"] = notification.Title; + notificationData.Properties["message"] = notification.Message; + notificationData.Properties["datetime"] = Clock.Now; + notificationData.Properties["severity"] = notification.Severity; + + notificationData.Properties.AddIfNotContains(notification.Data); - await _notificationDispatcher.DispatcheAsync(notificationInfo); + var notificationName = NotificationNameNormalizer.NormalizerName("TestApplicationNotofication"); + + await _notificationDispatcher.DispatchAsync(notificationName, notificationData, + notificationSeverity: notification.Severity); + + // await _notificationDispatcher.DispatcheAsync(notificationInfo); } } @@ -45,7 +56,9 @@ namespace LINGYUN.Abp.MessageService.Controllers public Guid UserId { get; set; } public string Title { get; set; } public string Message { get; set; } + public Dictionary Data { get; set; } = new Dictionary(); public NotificationSeverity Severity { get; set; } = NotificationSeverity.Success; + } public class TestApplicationNotificationData : NotificationData diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs new file mode 100644 index 000000000..a8623dea1 --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs @@ -0,0 +1,143 @@ +using LINGYUN.Abp.Notifications; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.MessageService.EventBus.Distributed +{ + /// + /// 订阅通知发布事件,统一发布消息 + /// + /// + /// 作用在于SignalR客户端只会与一台服务器建立连接, + /// 只有启用了SignlR服务端的才能真正将消息发布到客户端 + /// + public class NotificationEventHandler : IDistributedEventHandler, ITransientDependency + { + /// + /// Reference to . + /// + public ILogger Logger { get; set; } + /// + /// Reference to . + /// + protected IBackgroundJobManager BackgroundJobManager; + /// + /// Reference to . + /// + protected INotificationStore NotificationStore { get; } + /// + /// Reference to . + /// + protected INotificationPublishProviderManager NotificationPublishProviderManager { get; } + + /// + /// Initializes a new instance of the class. + /// + public NotificationEventHandler( + IBackgroundJobManager backgroundJobManager, + + INotificationStore notificationStore, + INotificationPublishProviderManager notificationPublishProviderManager) + { + BackgroundJobManager = backgroundJobManager; + + NotificationStore = notificationStore; + NotificationPublishProviderManager = notificationPublishProviderManager; + + Logger = NullLogger.Instance; + } + + [UnitOfWork] + public virtual async Task HandleEventAsync(NotificationEventData eventData) + { + var notificationInfo = eventData.ToNotificationInfo(); + + var providers = Enumerable + .Reverse(NotificationPublishProviderManager.Providers); + + await PublishFromProvidersAsync(providers, notificationInfo); + } + + /// + /// 指定提供者发布通知 + /// + /// 提供者列表 + /// 通知信息 + /// + protected async Task PublishFromProvidersAsync(IEnumerable providers, + NotificationInfo notificationInfo) + { + Logger.LogDebug($"Persistent notification {notificationInfo.Name}"); + + // 持久化通知 + await NotificationStore.InsertNotificationAsync(notificationInfo); + + Logger.LogDebug($"Gets a list of user subscriptions {notificationInfo.Name}"); + // 获取用户订阅列表 + var userSubscriptions = await NotificationStore.GetSubscriptionsAsync(notificationInfo.TenantId, notificationInfo.Name); + + Logger.LogDebug($"Persistent user notifications {notificationInfo.Name}"); + // 持久化用户通知 + var subscriptionUserIdentifiers = userSubscriptions.Select(us => new UserIdentifier(us.UserId, us.UserName)); + + await NotificationStore.InsertUserNotificationsAsync(notificationInfo, + subscriptionUserIdentifiers.Select(u => u.UserId)); + + // 发布通知 + foreach (var provider in providers) + { + await PublishAsync(provider, notificationInfo, subscriptionUserIdentifiers); + } + + if (notificationInfo.Lifetime == NotificationLifetime.OnlyOne) + { + // 一次性通知在发送完成后就取消用户订阅 + await NotificationStore.DeleteAllUserSubscriptionAsync(notificationInfo.TenantId, + notificationInfo.Name); + } + } + /// + /// 发布通知 + /// + /// 通知发布者 + /// 通知信息 + /// 订阅用户列表 + /// + protected async Task PublishAsync(INotificationPublishProvider provider, NotificationInfo notificationInfo, + IEnumerable subscriptionUserIdentifiers) + { + try + { + Logger.LogDebug($"Sending notification with provider {provider.Name}"); + + // 发布 + await provider.PublishAsync(notificationInfo, subscriptionUserIdentifiers); + + Logger.LogDebug($"Send notification {notificationInfo.Name} with provider {provider.Name} was successful"); + } + catch (Exception ex) + { + Logger.LogWarning($"Send notification error with provider {provider.Name}"); + Logger.LogWarning($"Error message:{ex.Message}"); + + Logger.LogTrace(ex, $"Send notification error with provider { provider.Name}"); + + Logger.LogDebug($"Send notification error, notification {notificationInfo.Name} entry queue"); + // 发送失败的消息进入后台队列 + await BackgroundJobManager.EnqueueAsync( + new NotificationPublishJobArgs(notificationInfo.GetId(), + provider.GetType().AssemblyQualifiedName, + subscriptionUserIdentifiers.ToList(), + notificationInfo.TenantId)); + } + } + } +} diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs new file mode 100644 index 000000000..48e62bcc3 --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs @@ -0,0 +1,75 @@ +using LINGYUN.Common.EventBus.Tenants; +using System.Threading.Tasks; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.DependencyInjection; +using Microsoft.Extensions.Logging; +using Volo.Abp.MultiTenancy; +using LINGYUN.Abp.Notifications; +using Microsoft.Extensions.Localization; +using LINGYUN.Abp.MessageService.Localization; +using System; +using Volo.Abp.Settings; +using Volo.Abp.Localization; +using System.Globalization; + +namespace LINGYUN.Abp.MessageService.EventBus.Distributed +{ + public class TenantCreateEventHandler : IDistributedEventHandler, ITransientDependency + { + protected ILogger Logger { get; } + protected ICurrentTenant CurrentTenant { get; } + protected ISettingProvider SettingProvider { get; } + protected IStringLocalizer StringLocalizer { get; } + protected INotificationDispatcher NotificationDispatcher { get; } + protected INotificationSubscriptionManager NotificationSubscriptionManager { get; } + + public TenantCreateEventHandler( + ICurrentTenant currentTenant, + ISettingProvider settingProvider, + INotificationDispatcher notificationDispatcher, + INotificationSubscriptionManager notificationSubscriptionManager, + IStringLocalizer stringLocalizer, + ILogger logger) + { + Logger = logger; + CurrentTenant = currentTenant; + SettingProvider = settingProvider; + StringLocalizer = stringLocalizer; + NotificationDispatcher = notificationDispatcher; + NotificationSubscriptionManager = notificationSubscriptionManager; + } + + public async Task HandleEventAsync(CreateEventData eventData) + { + var userDefaultCultureName = await SettingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage); + if (userDefaultCultureName.IsNullOrWhiteSpace()) + { + userDefaultCultureName = CultureInfo.CurrentUICulture.Name; + } + // 使用系统区域语言发布通知 + using (CultureHelper.Use(userDefaultCultureName, userDefaultCultureName)) + { + var noticeNormalizerName = NotificationNameNormalizer.NormalizerName(TenantNotificationNames.NewTenantRegistered); + var tenantAdminUserIdentifier = new UserIdentifier(eventData.AdminUserId, eventData.AdminEmailAddress); + + // 管理用户订阅租户创建通知 + await NotificationSubscriptionManager.SubscribeAsync(eventData.Id, tenantAdminUserIdentifier, noticeNormalizerName.Name); + + var notificationData = new NotificationData(); + notificationData.WriteStandardData( + L("NewTenantRegisteredNotificationTitle"), + L("NewTenantRegisteredNotificationMessage", eventData.Name), + DateTime.Now, eventData.AdminEmailAddress); + + // 发布租户创建通知 + await NotificationDispatcher.DispatchAsync(noticeNormalizerName, notificationData, + eventData.Id, NotificationSeverity.Success); + } + } + + protected string L(string name, params object[] args) + { + return StringLocalizer[name, args]?.Value; + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj similarity index 52% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj index 240b2809a..08d38c8de 100644 --- a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj @@ -6,14 +6,25 @@ - - - + + + + + + + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + @@ -32,11 +43,15 @@ - - - - - + + + + + + + + + diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs similarity index 79% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs index d7f763c9f..a1390d1ce 100644 --- a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs @@ -1,10 +1,16 @@ using DotNetCore.CAP; +using Hangfire; using IdentityModel; +using LINGYUN.Abp.BackgroundJobs.Hangfire; using LINGYUN.Abp.EventBus.CAP; +using LINGYUN.Abp.Hangfire.Storage.MySql; using LINGYUN.Abp.IM.SignalR; +using LINGYUN.Abp.MessageService.BackgroundJobs; using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using LINGYUN.Abp.MessageService.Localization; using LINGYUN.Abp.MessageService.MultiTenancy; using LINGYUN.Abp.Notifications.SignalR; +using LINGYUN.Abp.Notifications.WeChat.WeApp; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; @@ -18,6 +24,8 @@ using Volo.Abp; using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.Autofac; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.Caching; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Localization; using Volo.Abp.Modularity; @@ -26,6 +34,7 @@ using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.Security.Claims; using Volo.Abp.SettingManagement.EntityFrameworkCore; using Volo.Abp.TenantManagement.EntityFrameworkCore; +using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem; namespace LINGYUN.Abp.MessageService @@ -40,7 +49,10 @@ namespace LINGYUN.Abp.MessageService typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpIMSignalRModule), typeof(AbpNotificationsSignalRModule), + typeof(AbpNotificationsWeChatWeAppModule), typeof(AbpCAPEventBusModule), + typeof(AbpBackgroundJobsHangfireModule), + typeof(AbpHangfireMySqlStorageModule), typeof(AbpAutofacModule) )] public class AbpMessageServiceHttpApiHostModule : AbpModule @@ -56,7 +68,8 @@ namespace LINGYUN.Abp.MessageService .UseRabbitMQ(rabbitMQOptions => { configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); - }); + }) + .UseDashboard(); }); } @@ -70,6 +83,14 @@ namespace LINGYUN.Abp.MessageService options.UseMySQL(); }); + Configure(options => + { + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); + }); + Configure(options => { options.FileSets.AddEmbedded("LINGYUN.Abp.MessageService"); @@ -100,6 +121,10 @@ namespace LINGYUN.Abp.MessageService { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + + options.Resources + .Get() + .AddVirtualJson("/LINGYUN/Abp/MessageService/Localization/HttpApiHost"); }); context.Services.AddAuthentication("Bearer") @@ -130,6 +155,14 @@ namespace LINGYUN.Abp.MessageService } } + public override void OnPostApplicationInitialization(ApplicationInitializationContext context) + { + var backgroundJobManager = context.ServiceProvider.GetRequiredService(); + // 五分钟执行一次的定时任务 + AsyncHelper.RunSync(async () => await + backgroundJobManager.EnqueueAsync(CronGenerator.Minute(5), new NotificationCleanupExpritionJobArgs(200))); + } + public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); @@ -160,6 +193,8 @@ namespace LINGYUN.Abp.MessageService }); // 审计日志 app.UseAuditing(); + app.UseHangfireServer(); + app.UseHangfireDashboard(); // 路由 app.UseConfiguredEndpoints(); } diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Localization/HttpApiHost/en.json b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Localization/HttpApiHost/en.json new file mode 100644 index 000000000..2716c4a9b --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Localization/HttpApiHost/en.json @@ -0,0 +1,7 @@ +{ + "culture": "en", + "texts": { + "NewTenantRegisteredNotificationTitle": "Tenants create notification", + "NewTenantRegisteredNotificationMessage": "New tenants to create success, the tenant name: {0}!" + } +} \ No newline at end of file diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Localization/HttpApiHost/zh-Hans.json b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Localization/HttpApiHost/zh-Hans.json new file mode 100644 index 000000000..175a73b94 --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Localization/HttpApiHost/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hans", + "texts": { + "NewTenantRegisteredNotificationTitle": "租户创建通知", + "NewTenantRegisteredNotificationMessage": "新租户创建成功,租户名称:{0}!" + } +} \ No newline at end of file diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Notifications/MessageServiceDefinitionProvider.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Notifications/MessageServiceDefinitionProvider.cs new file mode 100644 index 000000000..144ee3b3a --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Notifications/MessageServiceDefinitionProvider.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.MessageService.Localization; +using LINGYUN.Abp.Notifications; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class MessageServiceDefinitionProvider : NotificationDefinitionProvider + { + public override void Define(INotificationDefinitionContext context) + { + context.Add(new NotificationDefinition( + "TestApplicationNotofication", + L("TestApplicationNotofication"), + L("TestApplicationNotofication"), + notificationType: NotificationType.Application, + lifetime: NotificationLifetime.OnlyOne, + allowSubscriptionToClients: true)); + } + + protected LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200609151853_Create-User-Subscription-Column-UserName.Designer.cs similarity index 95% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200609151853_Create-User-Subscription-Column-UserName.Designer.cs index 8704b41fc..1c75e4d1d 100644 --- a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200609151853_Create-User-Subscription-Column-UserName.Designer.cs @@ -3,18 +3,22 @@ using System; using LINGYUN.Abp.MessageService.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; namespace LINGYUN.Abp.MessageService.Migrations { [DbContext(typeof(MessageServiceHostMigrationsDbContext))] - partial class MessageServiceHostMigrationsDbContextModelSnapshot : ModelSnapshot + [Migration("20200609151853_Create-User-Subscription-Column-UserName")] + partial class CreateUserSubscriptionColumnUserName { - protected override void BuildModel(ModelBuilder modelBuilder) + protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.3") + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroup", b => @@ -478,6 +482,13 @@ namespace LINGYUN.Abp.MessageService.Migrations b.Property("UserId") .HasColumnType("char(36)"); + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128) + .HasDefaultValue("/"); + b.HasKey("Id"); b.HasIndex("TenantId", "UserId", "NotificationName") diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200609151853_Create-User-Subscription-Column-UserName.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200609151853_Create-User-Subscription-Column-UserName.cs new file mode 100644 index 000000000..5c109d763 --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200609151853_Create-User-Subscription-Column-UserName.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + public partial class CreateUserSubscriptionColumnUserName : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UserName", + table: "AppUserSubscribes", + maxLength: 128, + nullable: false, + defaultValue: "/"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UserName", + table: "AppUserSubscribes"); + } + } +} diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200617010925_Add-Notification-Column-CateGory.Designer.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200617010925_Add-Notification-Column-CateGory.Designer.cs new file mode 100644 index 000000000..352a9f8ae --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200617010925_Add-Notification-Column-CateGory.Designer.cs @@ -0,0 +1,508 @@ +// +using System; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + [DbContext(typeof(MessageServiceHostMigrationsDbContext))] + [Migration("20200617010925_Add-Notification-Column-CateGory")] + partial class AddNotificationColumnCateGory + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Address") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(20) CHARACTER SET utf8mb4") + .HasMaxLength(20); + + b.Property("Notice") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Tag") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroupAdmin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowDissolveGroup") + .HasColumnType("tinyint(1)"); + + b.Property("AllowKickPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendNotice") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSilence") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("IsSuperAdmin") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppChatGroupAdmins"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddFriend") + .HasColumnType("tinyint(1)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowReceiveMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("RequireAddFriendValition") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("char(36)"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserSpecialFocus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("FocusUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserSpecialFocuss"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExpirationTime") + .HasColumnType("datetime(6)"); + + b.Property("NotificationCateGory") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("NotificationData") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("NotificationTypeName") + .IsRequired() + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("Severity") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName"); + + b.ToTable("AppNotifications"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.UserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("ReadStatus") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationId") + .HasName("IX_Tenant_User_Notification_Id"); + + b.ToTable("AppUserNotifications"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Subscriptions.UserSubscribe", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("NotificationName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128) + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationName") + .IsUnique() + .HasName("IX_Tenant_User_Notification_Name"); + + b.ToTable("AppUserSubscribes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200617010925_Add-Notification-Column-CateGory.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200617010925_Add-Notification-Column-CateGory.cs new file mode 100644 index 000000000..928173a6d --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200617010925_Add-Notification-Column-CateGory.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + public partial class AddNotificationColumnCateGory : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_AppNotifications_NotificationName", + table: "AppNotifications"); + + migrationBuilder.AddColumn( + name: "NotificationCateGory", + table: "AppNotifications", + maxLength: 50, + nullable: false, + defaultValue: ""); + + migrationBuilder.CreateIndex( + name: "IX_AppNotifications_TenantId_NotificationName", + table: "AppNotifications", + columns: new[] { "TenantId", "NotificationName" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_AppNotifications_TenantId_NotificationName", + table: "AppNotifications"); + + migrationBuilder.DropColumn( + name: "NotificationCateGory", + table: "AppNotifications"); + + migrationBuilder.CreateIndex( + name: "IX_AppNotifications_NotificationName", + table: "AppNotifications", + column: "NotificationName"); + } + } +} diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs new file mode 100644 index 000000000..824c5c9e7 --- /dev/null +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs @@ -0,0 +1,506 @@ +// +using System; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + [DbContext(typeof(MessageServiceHostMigrationsDbContext))] + partial class MessageServiceHostMigrationsDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Address") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(20) CHARACTER SET utf8mb4") + .HasMaxLength(20); + + b.Property("Notice") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Tag") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroupAdmin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowDissolveGroup") + .HasColumnType("tinyint(1)"); + + b.Property("AllowKickPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendNotice") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSilence") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("IsSuperAdmin") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppChatGroupAdmins"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddFriend") + .HasColumnType("tinyint(1)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowReceiveMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("RequireAddFriendValition") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("char(36)"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserSpecialFocus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("FocusUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserSpecialFocuss"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExpirationTime") + .HasColumnType("datetime(6)"); + + b.Property("NotificationCateGory") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.Property("NotificationData") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("NotificationTypeName") + .IsRequired() + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("Severity") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "NotificationName"); + + b.ToTable("AppNotifications"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.UserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("ReadStatus") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationId") + .HasName("IX_Tenant_User_Notification_Id"); + + b.ToTable("AppUserNotifications"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Subscriptions.UserSubscribe", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("NotificationName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("UserName") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128) + .HasDefaultValue("/"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationName") + .IsUnique() + .HasName("IX_Tenant_User_Notification_Name"); + + b.ToTable("AppUserSubscribes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/MultiTenancy/AuthorizationTenantResolveContributor.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/MultiTenancy/AuthorizationTenantResolveContributor.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/MultiTenancy/AuthorizationTenantResolveContributor.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/MultiTenancy/AuthorizationTenantResolveContributor.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs similarity index 100% rename from aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs rename to aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContext.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContext.cs index 8c7382a55..58d969d74 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContext.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContext.cs @@ -20,16 +20,16 @@ namespace LINGYUN.Platform.EntityFrameworkCore { base.OnModelCreating(modelBuilder); + modelBuilder.UseMySQL(); modelBuilder.ConfigureIdentity(); modelBuilder.ConfigureIdentityServer(options => { options.TablePrefix = "IdentityServer"; options.Schema = null; - options.DatabaseProvider = EfCoreDatabaseProvider.MySql; }); - modelBuilder.ConfigureTenantManagement(); - modelBuilder.ConfigureSettingManagement(); - modelBuilder.ConfigurePermissionManagement(); + //modelBuilder.ConfigureTenantManagement(); + //modelBuilder.ConfigureSettingManagement(); + //modelBuilder.ConfigurePermissionManagement(); } } } diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContextFactory.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContextFactory.cs index 9dd641cfd..678225c61 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContextFactory.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EntityFrameworkCore/PlatformHttpApiHostMigrationsDbContextFactory.cs @@ -12,7 +12,7 @@ namespace LINGYUN.Platform.EntityFrameworkCore var configuration = BuildConfiguration(); var builder = new DbContextOptionsBuilder() - .UseMySql(configuration.GetConnectionString("Default")); + .UseMySql(configuration.GetConnectionString("AbpIdentityServer")); return new PlatformHttpApiHostMigrationsDbContext(builder.Options); } diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantCreateEventHandler.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantCreateEventHandler.cs index 2eb2c586d..622776b8a 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantCreateEventHandler.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantCreateEventHandler.cs @@ -1,7 +1,6 @@ using LINGYUN.Common.EventBus.Tenants; using Microsoft.EntityFrameworkCore; using System; -using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -45,7 +44,9 @@ namespace LINGYUN.Platform.EventBus.Handlers using (CurrentTenant.Change(eventData.Id, eventData.Name)) { var definitionPermissions = PermissionDefinitionManager.GetPermissions(); - var grantPermissions = definitionPermissions.Select(p => p.Name).ToArray(); + var grantPermissions = definitionPermissions + .Where(p => p.MultiTenancySide.HasFlag(MultiTenancySides.Tenant)) + .Select(p => p.Name).ToArray(); //var grantPermissions = new List(); //foreach (var permission in definitionPermissions) //{ diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantDeleteEventHandler.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantDeleteEventHandler.cs index d642b1eea..92f2b29cf 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantDeleteEventHandler.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/EventBus/Handlers/TenantDeleteEventHandler.cs @@ -1,19 +1,20 @@ -using LINGYUN.Common.EventBus.Tenants; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using System; using System.Text; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.Domain.Repositories; using Volo.Abp.EventBus.Distributed; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.PermissionManagement; +using Volo.Abp.TenantManagement; using Volo.Abp.Uow; namespace LINGYUN.Platform.EventBus.Handlers { - public class TenantDeleteEventHandler : IDistributedEventHandler, ITransientDependency + public class TenantDeleteEventHandler : IDistributedEventHandler>, ITransientDependency { protected ICurrentTenant CurrentTenant { get; } protected IGuidGenerator GuidGenerator { get; } @@ -31,12 +32,13 @@ namespace LINGYUN.Platform.EventBus.Handlers PermissionGrantRepository = permissionGrantRepository; } - public async Task HandleEventAsync(DeleteEventData eventData) + public async Task HandleEventAsync(EntityDeletedEto eventData) { using var unitOfWork = UnitOfWorkManager.Begin(); // 订阅租户删除事件,删除管理员角色所有权限 // TODO: 租户貌似不存在了,删除应该会失败 - using (CurrentTenant.Change(eventData.Id)) + // 有缓存存在的话,可以获取到租户连接字符串 + using (CurrentTenant.Change(eventData.Entity.Id)) { // var grantPermissions = await PermissionGrantRepository.GetListAsync("R", "admin"); @@ -47,11 +49,11 @@ namespace LINGYUN.Platform.EventBus.Handlers var batchRmovePermissionSql = string.Empty; if (PermissionGrantRepository.GetDbContext().Database.IsMySql()) { - batchRmovePermissionSql = BuildMySqlBatchDeleteScript(permissionTableName, eventData.Id); + batchRmovePermissionSql = BuildMySqlBatchDeleteScript(permissionTableName, eventData.Entity.Id); } else { - batchRmovePermissionSql = BuildSqlServerBatchDeleteScript(permissionTableName, eventData.Id); + batchRmovePermissionSql = BuildSqlServerBatchDeleteScript(permissionTableName, eventData.Entity.Id); } await PermissionGrantRepository.GetDbContext().Database diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj index 4bc6d412b..258bf3ddc 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj @@ -5,6 +5,13 @@ LINGYUN.Platform + + + + + + + @@ -16,14 +23,15 @@ - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/zh-Hans.json b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/zh-Hans.json index 83575a629..10c8c6196 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/zh-Hans.json +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/zh-Hans.json @@ -2,6 +2,8 @@ "culture": "zh-Hans", "texts": { "DisplayName:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "启用电话号码确认", - "Description:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "用户是否可以确认电话号码." + "Description:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "用户是否可以确认电话号码.", + "Identity.OrganizationUnit.MaxUserMembershipCount": "最大组织机构数", + "Description:Abp.Identity.OrganizationUnit.MaxUserMembershipCount": "单个用户允许加入的最大组织机构数." } } \ No newline at end of file diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200513010936_Migration-IdentityServer-MySql.Designer.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200513010936_Migration-IdentityServer-MySql.Designer.cs new file mode 100644 index 000000000..7493706b8 --- /dev/null +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200513010936_Migration-IdentityServer-MySql.Designer.cs @@ -0,0 +1,1259 @@ +// +using LINGYUN.Platform.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using System; + +namespace LINGYUN.Platform.Migrations +{ + [DbContext(typeof(PlatformHttpApiHostMigrationsDbContext))] + [Migration("20200513010936_Migration-IdentityServer-MySql")] + partial class MigrationIdentityServerMySql + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Description") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Regex") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDefault") + .HasColumnName("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("IsPublic") + .HasColumnName("IsPublic") + .HasColumnType("tinyint(1)"); + + b.Property("IsStatic") + .HasColumnName("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") + .HasMaxLength(1024); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnName("Email") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnName("Name") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .IsRequired() + .HasColumnName("NormalizedEmail") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasColumnType("varchar(16) CHARACTER SET utf8mb4") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") + .HasMaxLength(1024); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasColumnType("varchar(196) CHARACTER SET utf8mb4") + .HasMaxLength(196); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Name") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Value") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Properties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerApiResources"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ApiResourceId", "Type"); + + b.ToTable("IdentityServerApiClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("ApiResourceId", "Name"); + + b.ToTable("IdentityServerApiScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ApiResourceId", "Name", "Type"); + + b.ToTable("IdentityServerApiScopeClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("ApiResourceId", "Type", "Value"); + + b.ToTable("IdentityServerApiSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenType") + .HasColumnType("int"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("tinyint(1)"); + + b.Property("AllowOfflineAccess") + .HasColumnType("tinyint(1)"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("tinyint(1)"); + + b.Property("AllowRememberConsent") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("tinyint(1)"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("int"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("BackChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("ConsentLifetime") + .HasColumnType("int"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DeviceCodeLifetime") + .HasColumnType("int"); + + b.Property("EnableLocalLogin") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime") + .HasColumnType("int"); + + b.Property("IncludeJwtId") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("LogoUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("PairWiseSubjectSalt") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration") + .HasColumnType("int"); + + b.Property("RefreshTokenUsage") + .HasColumnType("int"); + + b.Property("RequireClientSecret") + .HasColumnType("tinyint(1)"); + + b.Property("RequireConsent") + .HasColumnType("tinyint(1)"); + + b.Property("RequirePkce") + .HasColumnType("tinyint(1)"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("tinyint(1)"); + + b.Property("UserCodeType") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("UserSsoLifetime") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("IdentityServerClients"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Origin") + .HasColumnType("varchar(150) CHARACTER SET utf8mb4") + .HasMaxLength(150); + + b.HasKey("ClientId", "Origin"); + + b.ToTable("IdentityServerClientCorsOrigins"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("GrantType") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("ClientId", "GrantType"); + + b.ToTable("IdentityServerClientGrantTypes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Provider") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ClientId", "Provider"); + + b.ToTable("IdentityServerClientIdPRestrictions"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("PostLogoutRedirectUri") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.HasKey("ClientId", "PostLogoutRedirectUri"); + + b.ToTable("IdentityServerClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Key") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("ClientId", "Key"); + + b.ToTable("IdentityServerClientProperties"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("RedirectUri") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.HasKey("ClientId", "RedirectUri"); + + b.ToTable("IdentityServerClientRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Scope") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ClientId", "Scope"); + + b.ToTable("IdentityServerClientScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Devices.DeviceFlowCodes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("UserCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.HasIndex("UserCode") + .IsUnique(); + + b.ToTable("IdentityServerDeviceFlowCodes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Grants.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("IdentityServerPersistedGrants"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.Property("IdentityResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("IdentityResourceId", "Type"); + + b.ToTable("IdentityServerIdentityClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Properties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerIdentityResources"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiScope", null) + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId", "Name") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", null) + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200513010936_Migration-IdentityServer-MySql.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200513010936_Migration-IdentityServer-MySql.cs new file mode 100644 index 000000000..cfd47f8c5 --- /dev/null +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200513010936_Migration-IdentityServer-MySql.cs @@ -0,0 +1,773 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.Platform.Migrations +{ + public partial class MigrationIdentityServerMySql : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AbpClaimTypes", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 256, nullable: false), + Name = table.Column(maxLength: 256, nullable: false), + Required = table.Column(nullable: false), + IsStatic = table.Column(nullable: false), + Regex = table.Column(maxLength: 512, nullable: true), + RegexDescription = table.Column(maxLength: 128, nullable: true), + Description = table.Column(maxLength: 256, nullable: true), + ValueType = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpClaimTypes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpRoles", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(maxLength: 256, nullable: false), + TenantId = table.Column(nullable: true), + Name = table.Column(maxLength: 256, nullable: false), + NormalizedName = table.Column(maxLength: 256, nullable: false), + IsDefault = table.Column(nullable: false), + IsStatic = table.Column(nullable: false), + IsPublic = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpUsers", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + IsDeleted = table.Column(nullable: false, defaultValue: false), + DeleterId = table.Column(nullable: true), + DeletionTime = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + UserName = table.Column(maxLength: 256, nullable: false), + NormalizedUserName = table.Column(maxLength: 256, nullable: false), + Name = table.Column(maxLength: 64, nullable: true), + Surname = table.Column(maxLength: 64, nullable: true), + Email = table.Column(maxLength: 256, nullable: false), + NormalizedEmail = table.Column(maxLength: 256, nullable: false), + EmailConfirmed = table.Column(nullable: false, defaultValue: false), + PasswordHash = table.Column(maxLength: 256, nullable: true), + SecurityStamp = table.Column(maxLength: 256, nullable: false), + PhoneNumber = table.Column(maxLength: 16, nullable: true), + PhoneNumberConfirmed = table.Column(nullable: false, defaultValue: false), + TwoFactorEnabled = table.Column(nullable: false, defaultValue: false), + LockoutEnd = table.Column(nullable: true), + LockoutEnabled = table.Column(nullable: false, defaultValue: false), + AccessFailedCount = table.Column(nullable: false, defaultValue: 0) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiResources", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + IsDeleted = table.Column(nullable: false, defaultValue: false), + DeleterId = table.Column(nullable: true), + DeletionTime = table.Column(nullable: true), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Enabled = table.Column(nullable: false), + Properties = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiResources", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClients", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + IsDeleted = table.Column(nullable: false, defaultValue: false), + DeleterId = table.Column(nullable: true), + DeletionTime = table.Column(nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + ClientName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + ClientUri = table.Column(maxLength: 2000, nullable: true), + LogoUri = table.Column(maxLength: 2000, nullable: true), + Enabled = table.Column(nullable: false), + ProtocolType = table.Column(maxLength: 200, nullable: false), + RequireClientSecret = table.Column(nullable: false), + RequireConsent = table.Column(nullable: false), + AllowRememberConsent = table.Column(nullable: false), + AlwaysIncludeUserClaimsInIdToken = table.Column(nullable: false), + RequirePkce = table.Column(nullable: false), + AllowPlainTextPkce = table.Column(nullable: false), + AllowAccessTokensViaBrowser = table.Column(nullable: false), + FrontChannelLogoutUri = table.Column(maxLength: 2000, nullable: true), + FrontChannelLogoutSessionRequired = table.Column(nullable: false), + BackChannelLogoutUri = table.Column(maxLength: 2000, nullable: true), + BackChannelLogoutSessionRequired = table.Column(nullable: false), + AllowOfflineAccess = table.Column(nullable: false), + IdentityTokenLifetime = table.Column(nullable: false), + AccessTokenLifetime = table.Column(nullable: false), + AuthorizationCodeLifetime = table.Column(nullable: false), + ConsentLifetime = table.Column(nullable: true), + AbsoluteRefreshTokenLifetime = table.Column(nullable: false), + SlidingRefreshTokenLifetime = table.Column(nullable: false), + RefreshTokenUsage = table.Column(nullable: false), + UpdateAccessTokenClaimsOnRefresh = table.Column(nullable: false), + RefreshTokenExpiration = table.Column(nullable: false), + AccessTokenType = table.Column(nullable: false), + EnableLocalLogin = table.Column(nullable: false), + IncludeJwtId = table.Column(nullable: false), + AlwaysSendClientClaims = table.Column(nullable: false), + ClientClaimsPrefix = table.Column(maxLength: 200, nullable: true), + PairWiseSubjectSalt = table.Column(maxLength: 200, nullable: true), + UserSsoLifetime = table.Column(nullable: true), + UserCodeType = table.Column(maxLength: 100, nullable: true), + DeviceCodeLifetime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClients", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerDeviceFlowCodes", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + DeviceCode = table.Column(maxLength: 200, nullable: false), + UserCode = table.Column(maxLength: 200, nullable: false), + SubjectId = table.Column(maxLength: 200, nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + Expiration = table.Column(nullable: false), + Data = table.Column(maxLength: 50000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerDeviceFlowCodes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerIdentityResources", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + IsDeleted = table.Column(nullable: false, defaultValue: false), + DeleterId = table.Column(nullable: true), + DeletionTime = table.Column(nullable: true), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Enabled = table.Column(nullable: false), + Required = table.Column(nullable: false), + Emphasize = table.Column(nullable: false), + ShowInDiscoveryDocument = table.Column(nullable: false), + Properties = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerIdentityResources", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerPersistedGrants", + columns: table => new + { + Key = table.Column(maxLength: 200, nullable: false), + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + Type = table.Column(maxLength: 50, nullable: false), + SubjectId = table.Column(maxLength: 200, nullable: true), + ClientId = table.Column(maxLength: 200, nullable: false), + CreationTime = table.Column(nullable: false), + Expiration = table.Column(nullable: true), + Data = table.Column(maxLength: 10000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerPersistedGrants", x => x.Key); + }); + + migrationBuilder.CreateTable( + name: "AbpRoleClaims", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + ClaimType = table.Column(maxLength: 256, nullable: false), + ClaimValue = table.Column(maxLength: 1024, nullable: true), + RoleId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpRoleClaims_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserClaims", + columns: table => new + { + Id = table.Column(nullable: false), + TenantId = table.Column(nullable: true), + ClaimType = table.Column(maxLength: 256, nullable: false), + ClaimValue = table.Column(maxLength: 1024, nullable: true), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AbpUserClaims_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserLogins", + columns: table => new + { + UserId = table.Column(nullable: false), + LoginProvider = table.Column(maxLength: 64, nullable: false), + TenantId = table.Column(nullable: true), + ProviderKey = table.Column(maxLength: 196, nullable: false), + ProviderDisplayName = table.Column(maxLength: 128, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserLogins", x => new { x.UserId, x.LoginProvider }); + table.ForeignKey( + name: "FK_AbpUserLogins_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserRoles", + columns: table => new + { + UserId = table.Column(nullable: false), + RoleId = table.Column(nullable: false), + TenantId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserRoles_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserTokens", + columns: table => new + { + UserId = table.Column(nullable: false), + LoginProvider = table.Column(maxLength: 64, nullable: false), + Name = table.Column(maxLength: 128, nullable: false), + TenantId = table.Column(nullable: true), + Value = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AbpUserTokens_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiClaims", + columns: table => new + { + Type = table.Column(maxLength: 200, nullable: false), + ApiResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiClaims", x => new { x.ApiResourceId, x.Type }); + table.ForeignKey( + name: "FK_IdentityServerApiClaims_IdentityServerApiResources_ApiResour~", + column: x => x.ApiResourceId, + principalTable: "IdentityServerApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiScopes", + columns: table => new + { + ApiResourceId = table.Column(nullable: false), + Name = table.Column(maxLength: 200, nullable: false), + DisplayName = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 1000, nullable: true), + Required = table.Column(nullable: false), + Emphasize = table.Column(nullable: false), + ShowInDiscoveryDocument = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiScopes", x => new { x.ApiResourceId, x.Name }); + table.ForeignKey( + name: "FK_IdentityServerApiScopes_IdentityServerApiResources_ApiResour~", + column: x => x.ApiResourceId, + principalTable: "IdentityServerApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiSecrets", + columns: table => new + { + Type = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 300, nullable: false), + ApiResourceId = table.Column(nullable: false), + Description = table.Column(maxLength: 2000, nullable: true), + Expiration = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiSecrets", x => new { x.ApiResourceId, x.Type, x.Value }); + table.ForeignKey( + name: "FK_IdentityServerApiSecrets_IdentityServerApiResources_ApiResou~", + column: x => x.ApiResourceId, + principalTable: "IdentityServerApiResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientClaims", + columns: table => new + { + ClientId = table.Column(nullable: false), + Type = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 250, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientClaims", x => new { x.ClientId, x.Type, x.Value }); + table.ForeignKey( + name: "FK_IdentityServerClientClaims_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientCorsOrigins", + columns: table => new + { + ClientId = table.Column(nullable: false), + Origin = table.Column(maxLength: 150, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientCorsOrigins", x => new { x.ClientId, x.Origin }); + table.ForeignKey( + name: "FK_IdentityServerClientCorsOrigins_IdentityServerClients_Client~", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientGrantTypes", + columns: table => new + { + ClientId = table.Column(nullable: false), + GrantType = table.Column(maxLength: 250, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientGrantTypes", x => new { x.ClientId, x.GrantType }); + table.ForeignKey( + name: "FK_IdentityServerClientGrantTypes_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientIdPRestrictions", + columns: table => new + { + ClientId = table.Column(nullable: false), + Provider = table.Column(maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientIdPRestrictions", x => new { x.ClientId, x.Provider }); + table.ForeignKey( + name: "FK_IdentityServerClientIdPRestrictions_IdentityServerClients_Cl~", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientPostLogoutRedirectUris", + columns: table => new + { + ClientId = table.Column(nullable: false), + PostLogoutRedirectUri = table.Column(maxLength: 300, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientPostLogoutRedirectUris", x => new { x.ClientId, x.PostLogoutRedirectUri }); + table.ForeignKey( + name: "FK_IdentityServerClientPostLogoutRedirectUris_IdentityServerCli~", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientProperties", + columns: table => new + { + ClientId = table.Column(nullable: false), + Key = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 2000, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientProperties", x => new { x.ClientId, x.Key }); + table.ForeignKey( + name: "FK_IdentityServerClientProperties_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientRedirectUris", + columns: table => new + { + ClientId = table.Column(nullable: false), + RedirectUri = table.Column(maxLength: 300, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientRedirectUris", x => new { x.ClientId, x.RedirectUri }); + table.ForeignKey( + name: "FK_IdentityServerClientRedirectUris_IdentityServerClients_Clien~", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientScopes", + columns: table => new + { + ClientId = table.Column(nullable: false), + Scope = table.Column(maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientScopes", x => new { x.ClientId, x.Scope }); + table.ForeignKey( + name: "FK_IdentityServerClientScopes_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerClientSecrets", + columns: table => new + { + Type = table.Column(maxLength: 250, nullable: false), + Value = table.Column(maxLength: 300, nullable: false), + ClientId = table.Column(nullable: false), + Description = table.Column(maxLength: 2000, nullable: true), + Expiration = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerClientSecrets", x => new { x.ClientId, x.Type, x.Value }); + table.ForeignKey( + name: "FK_IdentityServerClientSecrets_IdentityServerClients_ClientId", + column: x => x.ClientId, + principalTable: "IdentityServerClients", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerIdentityClaims", + columns: table => new + { + Type = table.Column(maxLength: 200, nullable: false), + IdentityResourceId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerIdentityClaims", x => new { x.IdentityResourceId, x.Type }); + table.ForeignKey( + name: "FK_IdentityServerIdentityClaims_IdentityServerIdentityResources~", + column: x => x.IdentityResourceId, + principalTable: "IdentityServerIdentityResources", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "IdentityServerApiScopeClaims", + columns: table => new + { + Type = table.Column(maxLength: 200, nullable: false), + ApiResourceId = table.Column(nullable: false), + Name = table.Column(maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_IdentityServerApiScopeClaims", x => new { x.ApiResourceId, x.Name, x.Type }); + table.ForeignKey( + name: "FK_IdentityServerApiScopeClaims_IdentityServerApiScopes_ApiReso~", + columns: x => new { x.ApiResourceId, x.Name }, + principalTable: "IdentityServerApiScopes", + principalColumns: new[] { "ApiResourceId", "Name" }, + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoleClaims_RoleId", + table: "AbpRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpRoles_NormalizedName", + table: "AbpRoles", + column: "NormalizedName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserClaims_UserId", + table: "AbpUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserLogins_LoginProvider_ProviderKey", + table: "AbpUserLogins", + columns: new[] { "LoginProvider", "ProviderKey" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserRoles_RoleId_UserId", + table: "AbpUserRoles", + columns: new[] { "RoleId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_Email", + table: "AbpUsers", + column: "Email"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedEmail", + table: "AbpUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_NormalizedUserName", + table: "AbpUsers", + column: "NormalizedUserName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUsers_UserName", + table: "AbpUsers", + column: "UserName"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerClients_ClientId", + table: "IdentityServerClients", + column: "ClientId"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerDeviceFlowCodes_DeviceCode", + table: "IdentityServerDeviceFlowCodes", + column: "DeviceCode", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerDeviceFlowCodes_Expiration", + table: "IdentityServerDeviceFlowCodes", + column: "Expiration"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerDeviceFlowCodes_UserCode", + table: "IdentityServerDeviceFlowCodes", + column: "UserCode", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerPersistedGrants_Expiration", + table: "IdentityServerPersistedGrants", + column: "Expiration"); + + migrationBuilder.CreateIndex( + name: "IX_IdentityServerPersistedGrants_SubjectId_ClientId_Type", + table: "IdentityServerPersistedGrants", + columns: new[] { "SubjectId", "ClientId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpClaimTypes"); + + migrationBuilder.DropTable( + name: "AbpRoleClaims"); + + migrationBuilder.DropTable( + name: "AbpUserClaims"); + + migrationBuilder.DropTable( + name: "AbpUserLogins"); + + migrationBuilder.DropTable( + name: "AbpUserRoles"); + + migrationBuilder.DropTable( + name: "AbpUserTokens"); + + migrationBuilder.DropTable( + name: "IdentityServerApiClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerApiScopeClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerApiSecrets"); + + migrationBuilder.DropTable( + name: "IdentityServerClientClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerClientCorsOrigins"); + + migrationBuilder.DropTable( + name: "IdentityServerClientGrantTypes"); + + migrationBuilder.DropTable( + name: "IdentityServerClientIdPRestrictions"); + + migrationBuilder.DropTable( + name: "IdentityServerClientPostLogoutRedirectUris"); + + migrationBuilder.DropTable( + name: "IdentityServerClientProperties"); + + migrationBuilder.DropTable( + name: "IdentityServerClientRedirectUris"); + + migrationBuilder.DropTable( + name: "IdentityServerClientScopes"); + + migrationBuilder.DropTable( + name: "IdentityServerClientSecrets"); + + migrationBuilder.DropTable( + name: "IdentityServerDeviceFlowCodes"); + + migrationBuilder.DropTable( + name: "IdentityServerIdentityClaims"); + + migrationBuilder.DropTable( + name: "IdentityServerPersistedGrants"); + + migrationBuilder.DropTable( + name: "AbpRoles"); + + migrationBuilder.DropTable( + name: "AbpUsers"); + + migrationBuilder.DropTable( + name: "IdentityServerApiScopes"); + + migrationBuilder.DropTable( + name: "IdentityServerClients"); + + migrationBuilder.DropTable( + name: "IdentityServerIdentityResources"); + + migrationBuilder.DropTable( + name: "IdentityServerApiResources"); + } + } +} diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200606012143_Upgrade-Abp-2.9.0.Designer.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200606012143_Upgrade-Abp-2.9.0.Designer.cs new file mode 100644 index 000000000..b41063fac --- /dev/null +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200606012143_Upgrade-Abp-2.9.0.Designer.cs @@ -0,0 +1,1426 @@ +// +using System; +using LINGYUN.Platform.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Platform.Migrations +{ + [DbContext(typeof(PlatformHttpApiHostMigrationsDbContext))] + [Migration("20200606012143_Upgrade-Abp-2.9.0")] + partial class UpgradeAbp290 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Description") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Regex") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDefault") + .HasColumnName("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("IsPublic") + .HasColumnName("IsPublic") + .HasColumnType("tinyint(1)"); + + b.Property("IsStatic") + .HasColumnName("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") + .HasMaxLength(1024); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnName("Email") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnName("Name") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .IsRequired() + .HasColumnName("NormalizedEmail") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasColumnType("varchar(16) CHARACTER SET utf8mb4") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") + .HasMaxLength(1024); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasColumnType("varchar(196) CHARACTER SET utf8mb4") + .HasMaxLength(196); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Name") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Value") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Code") + .IsRequired() + .HasColumnName("Code") + .HasColumnType("varchar(95) CHARACTER SET utf8mb4") + .HasMaxLength(95); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnName("DisplayName") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Properties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerApiResources"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ApiResourceId", "Type"); + + b.ToTable("IdentityServerApiClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("ApiResourceId", "Name"); + + b.ToTable("IdentityServerApiScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ApiResourceId", "Name", "Type"); + + b.ToTable("IdentityServerApiScopeClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("ApiResourceId", "Type", "Value"); + + b.ToTable("IdentityServerApiSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenType") + .HasColumnType("int"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("tinyint(1)"); + + b.Property("AllowOfflineAccess") + .HasColumnType("tinyint(1)"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("tinyint(1)"); + + b.Property("AllowRememberConsent") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("tinyint(1)"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("int"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("BackChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("ConsentLifetime") + .HasColumnType("int"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DeviceCodeLifetime") + .HasColumnType("int"); + + b.Property("EnableLocalLogin") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime") + .HasColumnType("int"); + + b.Property("IncludeJwtId") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("LogoUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("PairWiseSubjectSalt") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration") + .HasColumnType("int"); + + b.Property("RefreshTokenUsage") + .HasColumnType("int"); + + b.Property("RequireClientSecret") + .HasColumnType("tinyint(1)"); + + b.Property("RequireConsent") + .HasColumnType("tinyint(1)"); + + b.Property("RequirePkce") + .HasColumnType("tinyint(1)"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("tinyint(1)"); + + b.Property("UserCodeType") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("UserSsoLifetime") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("IdentityServerClients"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Origin") + .HasColumnType("varchar(150) CHARACTER SET utf8mb4") + .HasMaxLength(150); + + b.HasKey("ClientId", "Origin"); + + b.ToTable("IdentityServerClientCorsOrigins"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("GrantType") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("ClientId", "GrantType"); + + b.ToTable("IdentityServerClientGrantTypes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Provider") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ClientId", "Provider"); + + b.ToTable("IdentityServerClientIdPRestrictions"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("PostLogoutRedirectUri") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.HasKey("ClientId", "PostLogoutRedirectUri"); + + b.ToTable("IdentityServerClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Key") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("ClientId", "Key"); + + b.ToTable("IdentityServerClientProperties"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("RedirectUri") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.HasKey("ClientId", "RedirectUri"); + + b.ToTable("IdentityServerClientRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Scope") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ClientId", "Scope"); + + b.ToTable("IdentityServerClientScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Devices.DeviceFlowCodes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("UserCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.HasIndex("UserCode") + .IsUnique(); + + b.ToTable("IdentityServerDeviceFlowCodes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Grants.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("IdentityServerPersistedGrants"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.Property("IdentityResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("IdentityResourceId", "Type"); + + b.ToTable("IdentityServerIdentityClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Properties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerIdentityResources"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiScope", null) + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId", "Name") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", null) + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200606012143_Upgrade-Abp-2.9.0.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200606012143_Upgrade-Abp-2.9.0.cs new file mode 100644 index 000000000..6bc7368c7 --- /dev/null +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/20200606012143_Upgrade-Abp-2.9.0.cs @@ -0,0 +1,199 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.Platform.Migrations +{ + public partial class UpgradeAbp290 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Value", + table: "IdentityServerClientSecrets", + maxLength: 300, + nullable: false, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 4000); + + migrationBuilder.AlterColumn( + name: "RedirectUri", + table: "IdentityServerClientRedirectUris", + maxLength: 300, + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(2000) CHARACTER SET utf8mb4", + oldMaxLength: 2000); + + migrationBuilder.AlterColumn( + name: "PostLogoutRedirectUri", + table: "IdentityServerClientPostLogoutRedirectUris", + maxLength: 300, + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(2000) CHARACTER SET utf8mb4", + oldMaxLength: 2000); + + migrationBuilder.AlterColumn( + name: "Value", + table: "IdentityServerApiSecrets", + maxLength: 300, + nullable: false, + oldClrType: typeof(string), + oldType: "longtext CHARACTER SET utf8mb4", + oldMaxLength: 4000); + + migrationBuilder.CreateTable( + name: "AbpOrganizationUnits", + columns: table => new + { + Id = table.Column(nullable: false), + ExtraProperties = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + IsDeleted = table.Column(nullable: false, defaultValue: false), + DeleterId = table.Column(nullable: true), + DeletionTime = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + ParentId = table.Column(nullable: true), + Code = table.Column(maxLength: 95, nullable: false), + DisplayName = table.Column(maxLength: 128, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpOrganizationUnits", x => x.Id); + table.ForeignKey( + name: "FK_AbpOrganizationUnits_AbpOrganizationUnits_ParentId", + column: x => x.ParentId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "AbpOrganizationUnitRoles", + columns: table => new + { + RoleId = table.Column(nullable: false), + OrganizationUnitId = table.Column(nullable: false), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpOrganizationUnitRoles", x => new { x.OrganizationUnitId, x.RoleId }); + table.ForeignKey( + name: "FK_AbpOrganizationUnitRoles_AbpOrganizationUnits_OrganizationUn~", + column: x => x.OrganizationUnitId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpOrganizationUnitRoles_AbpRoles_RoleId", + column: x => x.RoleId, + principalTable: "AbpRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AbpUserOrganizationUnits", + columns: table => new + { + UserId = table.Column(nullable: false), + OrganizationUnitId = table.Column(nullable: false), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpUserOrganizationUnits", x => new { x.OrganizationUnitId, x.UserId }); + table.ForeignKey( + name: "FK_AbpUserOrganizationUnits_AbpOrganizationUnits_OrganizationUn~", + column: x => x.OrganizationUnitId, + principalTable: "AbpOrganizationUnits", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AbpUserOrganizationUnits_AbpUsers_UserId", + column: x => x.UserId, + principalTable: "AbpUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnitRoles_RoleId_OrganizationUnitId", + table: "AbpOrganizationUnitRoles", + columns: new[] { "RoleId", "OrganizationUnitId" }); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnits_Code", + table: "AbpOrganizationUnits", + column: "Code"); + + migrationBuilder.CreateIndex( + name: "IX_AbpOrganizationUnits_ParentId", + table: "AbpOrganizationUnits", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_AbpUserOrganizationUnits_UserId_OrganizationUnitId", + table: "AbpUserOrganizationUnits", + columns: new[] { "UserId", "OrganizationUnitId" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AbpOrganizationUnitRoles"); + + migrationBuilder.DropTable( + name: "AbpUserOrganizationUnits"); + + migrationBuilder.DropTable( + name: "AbpOrganizationUnits"); + + migrationBuilder.AlterColumn( + name: "Value", + table: "IdentityServerClientSecrets", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 4000, + nullable: false, + oldClrType: typeof(string), + oldMaxLength: 300); + + migrationBuilder.AlterColumn( + name: "RedirectUri", + table: "IdentityServerClientRedirectUris", + type: "varchar(2000) CHARACTER SET utf8mb4", + maxLength: 2000, + nullable: false, + oldClrType: typeof(string), + oldMaxLength: 300); + + migrationBuilder.AlterColumn( + name: "PostLogoutRedirectUri", + table: "IdentityServerClientPostLogoutRedirectUris", + type: "varchar(2000) CHARACTER SET utf8mb4", + maxLength: 2000, + nullable: false, + oldClrType: typeof(string), + oldMaxLength: 300); + + migrationBuilder.AlterColumn( + name: "Value", + table: "IdentityServerApiSecrets", + type: "longtext CHARACTER SET utf8mb4", + maxLength: 4000, + nullable: false, + oldClrType: typeof(string), + oldMaxLength: 300); + } + } +} diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/IdentityServerMigrationsDbContextModelSnapshot.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/IdentityServerMigrationsDbContextModelSnapshot.cs new file mode 100644 index 000000000..a05a6827e --- /dev/null +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/Migrations/IdentityServerMigrationsDbContextModelSnapshot.cs @@ -0,0 +1,1424 @@ +// +using System; +using LINGYUN.Platform.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Platform.Migrations +{ + [DbContext(typeof(PlatformHttpApiHostMigrationsDbContext))] + partial class IdentityServerMigrationsDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) + .HasAnnotation("ProductVersion", "3.1.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Description") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Regex") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .IsRequired() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDefault") + .HasColumnName("IsDefault") + .HasColumnType("tinyint(1)"); + + b.Property("IsPublic") + .HasColumnName("IsPublic") + .HasColumnType("tinyint(1)"); + + b.Property("IsStatic") + .HasColumnName("IsStatic") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") + .HasMaxLength(1024); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .IsRequired() + .HasColumnName("Email") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnName("Name") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .IsRequired() + .HasColumnName("NormalizedEmail") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasColumnType("varchar(16) CHARACTER SET utf8mb4") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("varchar(1024) CHARACTER SET utf8mb4") + .HasMaxLength(1024); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasColumnType("varchar(196) CHARACTER SET utf8mb4") + .HasMaxLength(196); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("char(36)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Name") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Value") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("Code") + .IsRequired() + .HasColumnName("Code") + .HasColumnType("varchar(95) CHARACTER SET utf8mb4") + .HasMaxLength(95); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnName("DisplayName") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("char(36)"); + + b.Property("RoleId") + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Properties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerApiResources"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ApiResourceId", "Type"); + + b.ToTable("IdentityServerApiClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("ApiResourceId", "Name"); + + b.ToTable("IdentityServerApiScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Name") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ApiResourceId", "Name", "Type"); + + b.ToTable("IdentityServerApiScopeClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.Property("ApiResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("ApiResourceId", "Type", "Value"); + + b.ToTable("IdentityServerApiSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.Client", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("AbsoluteRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenLifetime") + .HasColumnType("int"); + + b.Property("AccessTokenType") + .HasColumnType("int"); + + b.Property("AllowAccessTokensViaBrowser") + .HasColumnType("tinyint(1)"); + + b.Property("AllowOfflineAccess") + .HasColumnType("tinyint(1)"); + + b.Property("AllowPlainTextPkce") + .HasColumnType("tinyint(1)"); + + b.Property("AllowRememberConsent") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysIncludeUserClaimsInIdToken") + .HasColumnType("tinyint(1)"); + + b.Property("AlwaysSendClientClaims") + .HasColumnType("tinyint(1)"); + + b.Property("AuthorizationCodeLifetime") + .HasColumnType("int"); + + b.Property("BackChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("BackChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ClientClaimsPrefix") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("ConsentLifetime") + .HasColumnType("int"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DeviceCodeLifetime") + .HasColumnType("int"); + + b.Property("EnableLocalLogin") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("FrontChannelLogoutSessionRequired") + .HasColumnType("tinyint(1)"); + + b.Property("FrontChannelLogoutUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("IdentityTokenLifetime") + .HasColumnType("int"); + + b.Property("IncludeJwtId") + .HasColumnType("tinyint(1)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("LogoUri") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("PairWiseSubjectSalt") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ProtocolType") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("RefreshTokenExpiration") + .HasColumnType("int"); + + b.Property("RefreshTokenUsage") + .HasColumnType("int"); + + b.Property("RequireClientSecret") + .HasColumnType("tinyint(1)"); + + b.Property("RequireConsent") + .HasColumnType("tinyint(1)"); + + b.Property("RequirePkce") + .HasColumnType("tinyint(1)"); + + b.Property("SlidingRefreshTokenLifetime") + .HasColumnType("int"); + + b.Property("UpdateAccessTokenClaimsOnRefresh") + .HasColumnType("tinyint(1)"); + + b.Property("UserCodeType") + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("UserSsoLifetime") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("IdentityServerClients"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Origin") + .HasColumnType("varchar(150) CHARACTER SET utf8mb4") + .HasMaxLength(150); + + b.HasKey("ClientId", "Origin"); + + b.ToTable("IdentityServerClientCorsOrigins"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("GrantType") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.HasKey("ClientId", "GrantType"); + + b.ToTable("IdentityServerClientGrantTypes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Provider") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ClientId", "Provider"); + + b.ToTable("IdentityServerClientIdPRestrictions"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("PostLogoutRedirectUri") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.HasKey("ClientId", "PostLogoutRedirectUri"); + + b.ToTable("IdentityServerClientPostLogoutRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Key") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .IsRequired() + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.HasKey("ClientId", "Key"); + + b.ToTable("IdentityServerClientProperties"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("RedirectUri") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.HasKey("ClientId", "RedirectUri"); + + b.ToTable("IdentityServerClientRedirectUris"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Scope") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("ClientId", "Scope"); + + b.ToTable("IdentityServerClientScopes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.Property("ClientId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(250) CHARACTER SET utf8mb4") + .HasMaxLength(250); + + b.Property("Value") + .HasColumnType("varchar(300) CHARACTER SET utf8mb4") + .HasMaxLength(300); + + b.Property("Description") + .HasColumnType("varchar(2000) CHARACTER SET utf8mb4") + .HasMaxLength(2000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("ClientId", "Type", "Value"); + + b.ToTable("IdentityServerClientSecrets"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Devices.DeviceFlowCodes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("UserCode") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.HasIndex("UserCode") + .IsUnique(); + + b.ToTable("IdentityServerDeviceFlowCodes"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Grants.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(10000); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("SubjectId") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("varchar(50) CHARACTER SET utf8mb4") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("IdentityServerPersistedGrants"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.Property("IdentityResourceId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.HasKey("IdentityResourceId", "Type"); + + b.ToTable("IdentityServerIdentityClaims"); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("char(36)"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("varchar(1000) CHARACTER SET utf8mb4") + .HasMaxLength(1000); + + b.Property("DisplayName") + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Emphasize") + .HasColumnType("tinyint(1)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("tinyint(1)") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(200) CHARACTER SET utf8mb4") + .HasMaxLength(200); + + b.Property("Properties") + .HasColumnType("longtext CHARACTER SET utf8mb4"); + + b.Property("Required") + .HasColumnType("tinyint(1)"); + + b.Property("ShowInDiscoveryDocument") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("IdentityServerIdentityResources"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiResourceClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("Scopes") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiScopeClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiScope", null) + .WithMany("UserClaims") + .HasForeignKey("ApiResourceId", "Name") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.ApiResources.ApiSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.ApiResources.ApiResource", null) + .WithMany("Secrets") + .HasForeignKey("ApiResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("Claims") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientCorsOrigin", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedCorsOrigins") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientGrantType", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedGrantTypes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientIdPRestriction", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("IdentityProviderRestrictions") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientPostLogoutRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("PostLogoutRedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientProperty", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("Properties") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientRedirectUri", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("RedirectUris") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientScope", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("AllowedScopes") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.Clients.ClientSecret", b => + { + b.HasOne("Volo.Abp.IdentityServer.Clients.Client", null) + .WithMany("ClientSecrets") + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.IdentityServer.IdentityResources.IdentityClaim", b => + { + b.HasOne("Volo.Abp.IdentityServer.IdentityResources.IdentityResource", null) + .WithMany("UserClaims") + .HasForeignKey("IdentityResourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs index ce7ce9139..2dc4d3ea9 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs @@ -26,6 +26,7 @@ using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.Autofac; +using Volo.Abp.Caching; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.MySQL; using Volo.Abp.Identity; @@ -94,7 +95,8 @@ namespace LINGYUN.Platform .UseRabbitMQ(rabbitMQOptions => { configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); - }); + }) + .UseDashboard(); }); PreConfigure(builder => @@ -113,6 +115,14 @@ namespace LINGYUN.Platform options.UseMySQL(); }); + Configure(options => + { + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); + }); + Configure(options => { options.FileSets.AddEmbedded("LINGYUN.Platform"); diff --git a/aspnet-core/services/start-all-service.bat b/aspnet-core/services/start-all-service.bat index c7641f6ff..a311b5962 100644 --- a/aspnet-core/services/start-all-service.bat +++ b/aspnet-core/services/start-all-service.bat @@ -4,5 +4,6 @@ cls start .\start-identity-server.bat --run start .\start-apigateway-admin.bat --run start .\start-platform.bat --run +start .\start-messages.bat --run ping -n 10 127.1 >nul start .\start-apigateway-host.bat --run \ No newline at end of file diff --git a/aspnet-core/services/start-messages.bat b/aspnet-core/services/start-messages.bat new file mode 100644 index 000000000..42b2fae8d --- /dev/null +++ b/aspnet-core/services/start-messages.bat @@ -0,0 +1,29 @@ +@echo off +cls +chcp 65001 + +echo. 启动消息服务 + +cd .\messages\LINGYUN.Abp.MessageService.HttpApi.Host + +if '%1' equ '--publish' goto publish +if '%1' equ '--run' goto run +if '%1' equ '--restore' goto restore +if '%1' equ '' goto run +exit + +:publish +dotnet publish -c Release -o ..\..\Publish\messages --no-cache --no-restore +copy Dockerfile ..\..\Publish\messages\Dockerfile +pause +exit + +:run +dotnet run +pause +exit + +:restore +dotnet restore +pause +exit \ No newline at end of file diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj new file mode 100644 index 000000000..acf12d3c1 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs new file mode 100644 index 000000000..2a75696bd --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestBase.cs @@ -0,0 +1,9 @@ +using LINGYUN.Abp.Tests; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class AbpBlobStoringAliyunTestBase : AbpTestsBase + { + + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs new file mode 100644 index 000000000..4333b987f --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs @@ -0,0 +1,56 @@ +using Aliyun.OSS; +using LINGYUN.Abp.Tests; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using Volo.Abp; +using Volo.Abp.Autofac; +using Volo.Abp.BlobStoring; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + [DependsOn( + typeof(AbpBlobStoringModule), + typeof(AbpBlobStoringAliyunModule), + typeof(AbpTestsBaseModule), + typeof(AbpAutofacModule) + )] + public class AbpBlobStoringAliyunTestModule : AbpModule + { + private string _bucketName; + private string _accessKeyId; + private string _accessKeySecret; + private string _endPoint; + + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configurationOptions = new AbpConfigurationBuilderOptions + { + BasePath = @"D:\Projects\Development\Abp\BlobStoring\Aliyun", + EnvironmentName = "Development" + }; + + context.Services.ReplaceConfiguration(ConfigurationHelper.BuildConfiguration(configurationOptions)); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + _endPoint = configuration[AliyunBlobProviderConfigurationNames.Endpoint]; + _bucketName = configuration[AliyunBlobProviderConfigurationNames.BucketName]; + _accessKeyId = configuration["Aliyun:Auth:AccessKeyId"]; + _accessKeySecret = configuration["Aliyun:Auth:AccessKeySecret"]; + } + + public override void OnApplicationShutdown(ApplicationShutdownContext context) + { + var ossClient = new OssClient(_endPoint, _accessKeyId, _accessKeySecret); + if (ossClient.DoesBucketExist(_bucketName)) + { + ossClient.DeleteBucket(_bucketName); + } + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs new file mode 100644 index 000000000..b28628fc2 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/Aliyun/BlobContainer_Tests.cs @@ -0,0 +1,99 @@ +using LINGYUN.Abp.BlobStoring.TestObjects; +using Shouldly; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.BlobStoring; +using Xunit; + +namespace LINGYUN.Abp.BlobStoring.Aliyun +{ + public class BlobContainer_Tests : AbpBlobStoringAliyunTestBase + { + protected IBlobContainer Container { get; } + public BlobContainer_Tests() + { + Container = GetRequiredService>(); + } + + [Theory] + [InlineData("test-blob-1")] + [InlineData("test-blob-1.txt")] + [InlineData("test-folder/test-blob-1")] + public async Task Should_Save_And_Get_Blobs(string blobName) + { + var testContent = "test content".GetBytes(); + await Container.SaveAsync(blobName, testContent); + try + { + var resultBytes = await Container.GetAllBytesAsync(blobName); + resultBytes.SequenceEqual(testContent).ShouldBeTrue(); + } + finally + { + await Container.DeleteAsync(blobName); + } + } + + [Fact] + public async Task Should_Overwrite_Pre_Saved_Blob_If_Requested() + { + var blobName = "test-blob-1"; + + var testContent = "test content".GetBytes(); + await Container.SaveAsync(blobName, testContent); + + var testContentOverwritten = "test content overwritten".GetBytes(); + await Container.SaveAsync(blobName, testContentOverwritten, true); + + var result = await Container.GetAllBytesAsync(blobName); + result.SequenceEqual(testContentOverwritten).ShouldBeTrue(); + + await Container.DeleteAsync(blobName); + } + + + [Fact] + public async Task Should_Not_Allow_To_Overwrite_Pre_Saved_Blob_By_Default() + { + var blobName = "test-blob-1"; + + var testContent = "test content".GetBytes(); + await Container.SaveAsync(blobName, testContent); + + var testContentOverwritten = "test content overwritten".GetBytes(); + await Assert.ThrowsAsync(() => + Container.SaveAsync(blobName, testContentOverwritten) + ); + + await Container.DeleteAsync(blobName); + } + + [Theory] + [InlineData("test-blob-1")] + [InlineData("test-blob-1.txt")] + [InlineData("test-folder/test-blob-1")] + public async Task Should_Delete_Saved_Blobs(string blobName) + { + await Container.SaveAsync(blobName, "test content".GetBytes()); + (await Container.GetAllBytesAsync(blobName)).ShouldNotBeNull(); + + await Container.DeleteAsync(blobName); + (await Container.GetAllBytesOrNullAsync(blobName)).ShouldBeNull(); + } + + [Theory] + [InlineData("test-blob-1")] + [InlineData("test-blob-1.txt")] + [InlineData("test-folder/test-blob-1")] + public virtual async Task Saved_Blobs_Should_Exists(string blobName) + { + await Container.SaveAsync(blobName, "test content".GetBytes()); + (await Container.ExistsAsync(blobName)).ShouldBeTrue(); + + await Container.DeleteAsync(blobName); + (await Container.ExistsAsync(blobName)).ShouldBeFalse(); + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs new file mode 100644 index 000000000..47562c6a3 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.BlobStoring.Aliyun.Tests/LINGYUN/Abp/BlobStoring/TestObjects/TestContainer1.cs @@ -0,0 +1,6 @@ +namespace LINGYUN.Abp.BlobStoring.TestObjects +{ + public class TestContainer1 + { + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj new file mode 100644 index 000000000..d1b8b5acc --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN.Abp.TestsBase.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs new file mode 100644 index 000000000..fb8afac33 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBase.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.Tests +{ + public abstract class AbpTestsBase : AbpIntegratedTest + where TStartupModule : IAbpModule + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected virtual Task WithUnitOfWorkAsync(Func func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func action) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + await action(); + + await uow.CompleteAsync(); + } + } + } + + protected virtual Task WithUnitOfWorkAsync(Func> func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func> func) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + var result = await func(); + await uow.CompleteAsync(); + return result; + } + } + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs new file mode 100644 index 000000000..f7b0d6cff --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.TestBase/LINGYUN/Abp/Tests/AbpTestsBaseModule.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Tests +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpTestBaseModule), + typeof(AbpAuthorizationModule) + )] + public class AbpTestsBaseModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAlwaysAllowAuthorization(); + } + } +} diff --git a/vueJs/src/api/clients.ts b/vueJs/src/api/clients.ts index 2b6f44852..bd29d5e40 100644 --- a/vueJs/src/api/clients.ts +++ b/vueJs/src/api/clients.ts @@ -14,7 +14,8 @@ export default class ClientService { public static getClients(payload: ClientGetByPaged) { let _url = '/api/IdentityServer/Clients' - _url += '?sorting=' + payload.sorting + _url += '?filter=' + payload.filter + _url += '&sorting=' + payload.sorting _url += '&skipCount=' + pagerFormat(payload.skipCount) _url += '&maxResultCount=' + payload.maxResultCount return ApiService.Get>(_url, serviceUrl) @@ -81,7 +82,7 @@ export default class ClientService { } export class ClientGetByPaged extends PagedAndSortedResultRequestDto { - filter?: string + filter = '' } export enum HashType { diff --git a/vueJs/src/components/Notification/components/UserMessages.vue b/vueJs/src/components/Notification/components/UserMessages.vue new file mode 100644 index 000000000..e69de29bb diff --git a/vueJs/src/components/Notification/components/UserNofitications.vue b/vueJs/src/components/Notification/components/UserNofitications.vue new file mode 100644 index 000000000..c0b14ba73 --- /dev/null +++ b/vueJs/src/components/Notification/components/UserNofitications.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/vueJs/src/components/Notification/index.vue b/vueJs/src/components/Notification/index.vue index 0f4e776ac..827ea7ea1 100644 --- a/vueJs/src/components/Notification/index.vue +++ b/vueJs/src/components/Notification/index.vue @@ -1,9 +1,9 @@ @@ -207,8 +58,4 @@ export default class extends Vue { .item.el-dropdown-selfdefine > .el-badge__content.el-badge__content--undefined.is-fixed { top: 10px; } -.notification > .ivu-list.ivu-list-small.ivu-list-horizontal.ivu-list-split{ - max-height: 200px; - overflow: auto; -} diff --git a/vueJs/src/lang/zh.ts b/vueJs/src/lang/zh.ts index 692e49ad1..9f451ed92 100644 --- a/vueJs/src/lang/zh.ts +++ b/vueJs/src/lang/zh.ts @@ -392,7 +392,8 @@ export default { enableRateLimiting: '启用流量控制', rateLimitCount: '最大请求数量', period: '速率限制时间', - periodTimespan: '允许错开时间重试', + periodTimespan: '允许错开时间重试(s)', + clientWhitelist: '客户端白名单', ipAllowedList: 'Ip白名单', ipBlockedList: 'Ip黑名单', authenticationProviderKey: '身份认证程序', @@ -610,5 +611,9 @@ export default { correctEmailAddress: '正确的邮件地址', correctPhoneNumber: '正确的手机号码', operatingFast: '您的操作过快,请稍后再试!' + }, + messages: { + noNotifications: '没有通知', + noMessages: '没有消息' } } diff --git a/vueJs/src/utils/request.ts b/vueJs/src/utils/request.ts index 3b53611d6..c6b9e41a2 100644 --- a/vueJs/src/utils/request.ts +++ b/vueJs/src/utils/request.ts @@ -14,6 +14,10 @@ const service = axios.create({ // Request interceptors service.interceptors.request.use( (config) => { + const tenantId = getTenant() + if (tenantId) { + config.headers.__tenant = tenantId + } if (config.url === '/connect/token') { return config } @@ -21,10 +25,6 @@ service.interceptors.request.use( if (UserModule.token) { config.headers.Authorization = UserModule.token } - const tenantId = getTenant() - if (tenantId) { - config.headers.__tenant = tenantId - } // abp官方类库用的 zh-Hans 的简体中文包 这里直接粗暴一点 const language = getLanguage() if (language?.indexOf('zh') !== -1) { @@ -97,40 +97,18 @@ service.interceptors.response.use( }, (error) => { showError(error.response.data, error.response.status) - if (error.response.status === 401) { - if (UserModule.refreshToken) { - UserModule.RefreshSession().then(() => { - return service.request(error.config) - }).catch(() => { - MessageBox.confirm( - l('login.tokenExprition'), - l('login.confirmLogout'), - { - confirmButtonText: l('login.relogin'), - cancelButtonText: l('global.cancel'), - type: 'error' - }).then(() => { - UserModule.ResetToken() - location.reload() // To prevent bugs from vue-router - return Promise.reject(error) - }) - }) - } else { - MessageBox.confirm( - l('login.tokenExprition'), - l('login.confirmLogout'), - { - confirmButtonText: l('login.relogin'), - cancelButtonText: l('global.cancel'), - type: 'error' - }).then(() => { - UserModule.ResetToken() - location.reload() // To prevent bugs from vue-router - return Promise.reject(error) - }) - } - } - return Promise.reject(error) + MessageBox.confirm( + l('login.tokenExprition'), + l('login.confirmLogout'), + { + confirmButtonText: l('login.relogin'), + cancelButtonText: l('global.cancel'), + type: 'error' + }).then(() => { + UserModule.ResetToken() + location.reload() // To prevent bugs from vue-router + return Promise.reject(error) + }) } ) diff --git a/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue b/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue index 33b1d16d0..97bf93482 100644 --- a/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue +++ b/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue @@ -442,14 +442,15 @@ /> - + - @@ -471,6 +472,14 @@ v-model="apiGateWayRoute.rateLimitOptions.period" /> + + + -
+
+ + {{ globalSetting['Abp.Localization.DefaultLanguage'].displayName }} - + + + + {{ globalSetting['Abp.Timing.TimeZone'].displayName }} + - + + + {{ globalSetting['Abp.Identity.Password.RequiredLength'].displayName }} - + + + {{ globalSetting['Abp.Identity.Password.RequiredUniqueChars'].displayName }} - + + + {{ globalSetting['Abp.Identity.Password.RequireNonAlphanumeric'].displayName }} - + + + {{ globalSetting['Abp.Identity.Password.RequireLowercase'].displayName }} - + + + {{ globalSetting['Abp.Identity.Password.RequireUppercase'].displayName }} - + + + {{ globalSetting['Abp.Identity.Password.RequireDigit'].displayName }} - + + + {{ globalSetting['Abp.Identity.Lockout.AllowedForNewUsers'].displayName }} - + + + {{ globalSetting['Abp.Identity.Lockout.MaxFailedAccessAttempts'].displayName }} - + + + {{ globalSetting['Abp.Identity.Lockout.LockoutDuration'].displayName }} - + + + {{ globalSetting['Abp.Identity.SignIn.RequireConfirmedEmail'].displayName }} - + + + {{ globalSetting['Abp.Identity.SignIn.EnablePhoneNumberConfirmation'].displayName }} - + + + {{ globalSetting['Abp.Identity.SignIn.RequireConfirmedPhoneNumber'].displayName }} - + + + {{ globalSetting['Abp.Identity.User.IsUserNameUpdateEnabled'].displayName }} - + + + {{ globalSetting['Abp.Identity.User.IsEmailUpdateEnabled'].displayName }} - + + + {{ globalSetting['Abp.Identity.OrganizationUnit.MaxUserMembershipCount'].displayName }} + + + + + {{ globalSetting['Abp.Account.SmsRegisterTemplateCode'].displayName }} - + + + {{ globalSetting['Abp.Account.SmsSigninTemplateCode'].displayName }} - + + + {{ globalSetting['Abp.Account.SmsResetPasswordTemplateCode'].displayName }} + + + + + {{ globalSetting['Abp.Account.PhoneVerifyCodeExpiration'].displayName }} - + + + {{ globalSetting['Abp.Account.IsSelfRegistrationEnabled'].displayName }} - + + + {{ globalSetting['Abp.Account.EnableLocalLogin'].displayName }} @@ -346,7 +345,8 @@ export default class extends Vue { .login-container { width: 100%; height: 100%; - overflow: hidden; + overflow-x: hidden; + overflow-y: auto; background-color: $loginBg; .svg-container { diff --git a/vueJs/src/views/register/index.vue b/vueJs/src/views/register/index.vue index 0c3e0155a..aff866bbd 100644 --- a/vueJs/src/views/register/index.vue +++ b/vueJs/src/views/register/index.vue @@ -285,7 +285,8 @@ export default class extends Vue { .login-container { width: 100%; height: 100%; - overflow: hidden; + overflow-x: hidden; + overflow-y: auto; background-color: $loginBg; .svg-container { diff --git a/vueJs/src/views/reset-password/index.vue b/vueJs/src/views/reset-password/index.vue index e3aebc090..65e422f23 100644 --- a/vueJs/src/views/reset-password/index.vue +++ b/vueJs/src/views/reset-password/index.vue @@ -265,7 +265,8 @@ export default class extends Vue { .login-container { width: 100%; height: 100%; - overflow: hidden; + overflow-x: hidden; + overflow-y: auto; background-color: $loginBg; .svg-container {