66 changed files with 1570 additions and 141 deletions
@ -1,8 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.IdentityServer.WeChatValidator |
|||
{ |
|||
public class Class1 |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using LINGYUN.Abp.IdentityServer.WeChatValidator; |
|||
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(AbpIdentityServerDomainModule))] |
|||
public class AbpIdentityServerWeChatValidatorModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IIdentityServerBuilder>(builder => |
|||
{ |
|||
builder.AddExtensionGrantValidator<WeChatTokenGrantValidator>(); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
Configure<AbpWeChatValidatorOptions>(configuration.GetSection("AuthServer:WeChat")); |
|||
Configure<WeChatSignatureOptions>(configuration.GetSection("WeChat:Signature")); |
|||
|
|||
context.Services.AddHttpClient(WeChatValidatorConsts.WeChatValidatorClientName, options => |
|||
{ |
|||
options.BaseAddress = new System.Uri("https://api.weixin.qq.com/sns/jscode2session"); |
|||
}); |
|||
|
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpIdentityServerWeChatValidatorModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Get<AbpIdentityServerResource>() |
|||
.AddVirtualJson("/LINGYUN/Abp/IdentityServer/Localization/WeChatValidator"); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace LINGYUN.Abp.IdentityServer |
|||
{ |
|||
public class AbpWeChatValidatorOptions |
|||
{ |
|||
public string AppId { get; set; } |
|||
public string AppSecret { get; set; } |
|||
} |
|||
} |
|||
@ -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!" |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"InvalidGrant:GrantTypeInvalid": "不被允许的授权类型!", |
|||
"InvalidGrant:WeChatTokenInvalid": "微信认证失败!", |
|||
"InvalidGrant:WeChatCodeNotFound": "微信登录时获取的 code 为空或不存在!", |
|||
"InvalidGrant:WeChatNotRegister": "用户微信账号未绑定!" |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
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<WeChatSignatureOptions> 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("微信验证不通过"); |
|||
} |
|||
} |
|||
await next(context); |
|||
} |
|||
|
|||
protected bool CheckWeChatSignature(string token, string timestamp, string nonce, string signature) |
|||
{ |
|||
var al = new ArrayList(); |
|||
al.Add(token); |
|||
al.Add(timestamp); |
|||
al.Add(nonce); |
|||
al.Sort(); |
|||
string signatureStr = string.Empty; |
|||
for(int i = 0; i < al.Count; i++) |
|||
{ |
|||
signatureStr += al[i]; |
|||
} |
|||
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("-", ""); |
|||
if (result.Equals(signature, StringComparison.CurrentCultureIgnoreCase)) |
|||
{ |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace LINGYUN.Abp.IdentityServer |
|||
{ |
|||
public class WeChatSignatureOptions |
|||
{ |
|||
public string RequestPath { get; set; } |
|||
public string Token { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,119 @@ |
|||
using IdentityModel; |
|||
using IdentityServer4.Events; |
|||
using IdentityServer4.Models; |
|||
using IdentityServer4.Services; |
|||
using IdentityServer4.Validation; |
|||
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<WeChatTokenGrantValidator> Logger { get; } |
|||
protected AbpWeChatValidatorOptions Options { get; } |
|||
protected IHttpClientFactory HttpClientFactory{ get; } |
|||
protected IEventService EventService { get; } |
|||
protected IIdentityUserRepository UserRepository { get; } |
|||
protected UserManager<IdentityUser> UserManager { get; } |
|||
protected SignInManager<IdentityUser> SignInManager { get; } |
|||
protected IStringLocalizer<AbpIdentityServerResource> Localizer { get; } |
|||
protected PhoneNumberTokenProvider<IdentityUser> PhoneNumberTokenProvider { get; } |
|||
|
|||
|
|||
public WeChatTokenGrantValidator( |
|||
IEventService eventService, |
|||
IHttpClientFactory httpClientFactory, |
|||
UserManager<IdentityUser> userManager, |
|||
IIdentityUserRepository userRepository, |
|||
SignInManager<IdentityUser> signInManager, |
|||
IStringLocalizer<AbpIdentityServerResource> stringLocalizer, |
|||
PhoneNumberTokenProvider<IdentityUser> phoneNumberTokenProvider, |
|||
IOptionsSnapshot<AbpWeChatValidatorOptions> options, |
|||
ILogger<WeChatTokenGrantValidator> logger) |
|||
{ |
|||
Logger = logger; |
|||
Options = options.Value; |
|||
|
|||
EventService = eventService; |
|||
UserManager = userManager; |
|||
SignInManager = signInManager; |
|||
Localizer = stringLocalizer; |
|||
UserRepository = userRepository; |
|||
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 httpClient = HttpClientFactory.CreateClient(WeChatValidatorConsts.WeChatValidatorClientName); |
|||
var httpRequest = new WeChatTokenRequest |
|||
{ |
|||
Code = wechatCode, |
|||
AppId = Options.AppId, |
|||
Secret = Options.AppSecret, |
|||
BaseUrl = httpClient.BaseAddress.AbsoluteUri |
|||
}; |
|||
|
|||
var wechatTokenResponse = await httpClient.RequestWeChatCodeTokenAsync(httpRequest); |
|||
if (wechatTokenResponse.IsError) |
|||
{ |
|||
Logger.LogWarning("Authentication failed for token: {0}, reason: invalid token", wechatCode); |
|||
Logger.LogWarning("WeChat auth failed, error: {0}", wechatTokenResponse.ErrorMessage); |
|||
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, |
|||
Localizer["InvalidGrant:WeChatTokenInvalid"]); |
|||
return; |
|||
} |
|||
var currentUser = await UserManager.FindByNameAsync(wechatTokenResponse.OpenId); |
|||
if(currentUser == null) |
|||
{ |
|||
Logger.LogWarning("Invalid grant type: wechat openid: {0} not register", wechatTokenResponse.OpenId); |
|||
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, |
|||
Localizer["InvalidGrant:WeChatNotRegister"]); |
|||
return; |
|||
} |
|||
var sub = await UserManager.GetUserIdAsync(currentUser); |
|||
|
|||
var additionalClaims = new List<Claim>(); |
|||
if (currentUser.TenantId.HasValue) |
|||
{ |
|||
additionalClaims.Add(new Claim(AbpClaimTypes.TenantId, currentUser.TenantId?.ToString())); |
|||
} |
|||
additionalClaims.Add(new Claim(WeChatValidatorConsts.ClaimTypes.OpenId, wechatTokenResponse.OpenId)); |
|||
|
|||
await EventService.RaiseAsync(new UserLoginSuccessEvent(currentUser.UserName, wechatTokenResponse.OpenId, null)); |
|||
context.Result = new GrantValidationResult(sub, |
|||
WeChatValidatorConsts.AuthenticationMethods.BasedWeChatAuthentication, additionalClaims.ToArray()); |
|||
} |
|||
} |
|||
} |
|||
@ -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 = "wechat-id"; |
|||
} |
|||
|
|||
public class AuthenticationMethods |
|||
{ |
|||
public const string BasedWeChatAuthentication = "wca"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using LINGYUN.Abp.IdentityServer; |
|||
|
|||
namespace Microsoft.AspNetCore.Builder |
|||
{ |
|||
public static class IdentityServerApplicationBuilderExtensions |
|||
{ |
|||
public static IApplicationBuilder UseWeChatSignature(this IApplicationBuilder builder) |
|||
{ |
|||
builder.UseMiddleware<WeChatSignatureMiddleware>(); |
|||
return builder; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using IdentityModel.Client; |
|||
using System.Text; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace System.Net.Http |
|||
{ |
|||
public static class HttpClientTokenRequestExtensions |
|||
{ |
|||
public static async Task<WeChatTokenResponse> RequestWeChatCodeTokenAsync(this HttpMessageInvoker client, WeChatTokenRequest request, CancellationToken cancellationToken = default) |
|||
{ |
|||
var getResuestUrlBuiilder = new StringBuilder(); |
|||
getResuestUrlBuiilder.Append(request.BaseUrl); |
|||
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; |
|||
try |
|||
{ |
|||
httpResponse = await client.SendAsync(getRequest, cancellationToken).ConfigureAwait(false); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
return ProtocolResponse.FromException<WeChatTokenResponse>(ex); |
|||
} |
|||
return await ProtocolResponse.FromHttpResponseAsync<WeChatTokenResponse>(httpResponse).ConfigureAwait(false); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace System.Net.Http |
|||
{ |
|||
public class WeChatTokenRequest |
|||
{ |
|||
public string BaseUrl { get; set; } |
|||
public string AppId { get; set; } |
|||
public string Secret { get; set; } |
|||
public string Code { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
using IdentityModel.Client; |
|||
|
|||
namespace System.Net.Http |
|||
{ |
|||
public class WeChatTokenResponse : ProtocolResponse |
|||
{ |
|||
/// <summary>
|
|||
/// 用户唯一标识
|
|||
/// </summary>
|
|||
public string OpenId => TryGet("openid"); |
|||
/// <summary>
|
|||
/// 会话密钥
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// 仅仅只是要一个openid,这个没多大用吧
|
|||
/// </remarks>
|
|||
public string SessionKey => TryGet("session_key"); |
|||
/// <summary>
|
|||
/// 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回
|
|||
/// </summary>
|
|||
public string UnionId => TryGet("unionid"); |
|||
/// <summary>
|
|||
/// 微信认证成功没有errorcode或者errorcode为0
|
|||
/// </summary>
|
|||
public new bool IsError => !ErrorCode.IsNullOrWhiteSpace() && !"0".Equals(ErrorCode); |
|||
/// <summary>
|
|||
/// 错误码
|
|||
/// </summary>
|
|||
public string ErrorCode => TryGet("errcode"); |
|||
/// <summary>
|
|||
/// 错误信息
|
|||
/// </summary>
|
|||
public new string ErrorMessage |
|||
{ |
|||
get |
|||
{ |
|||
return ErrorCode switch |
|||
{ |
|||
"-1" => "系统繁忙,此时请开发者稍候再试", |
|||
"0" => string.Empty, |
|||
"40029" => "code 无效", |
|||
"45011" => "频率限制,每个用户每分钟100次", |
|||
_ => "未知的异常", |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,25 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.WeChat |
|||
{ |
|||
public class WeChatNotificationPublishProvider : NotificationPublishProvider |
|||
{ |
|||
public override string Name => "WeChat"; |
|||
|
|||
public WeChatNotificationPublishProvider( |
|||
IServiceProvider serviceProvider) |
|||
: base(serviceProvider) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public override async Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers) |
|||
{ |
|||
// step1 默认微信openid绑定的就是username,如果不是,那就根据userid去获取
|
|||
|
|||
// step2 调用微信消息推送接口
|
|||
} |
|||
} |
|||
} |
|||
@ -1,14 +1,40 @@ |
|||
using LINGYUN.Abp.Notifications.Internal; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public class AbpNotificationModule : AbpModule |
|||
{ |
|||
|
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
AutoAddDefinitionProviders(context.Services); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddTransient<INotificationDispatcher, DefaultNotificationDispatcher>(); |
|||
} |
|||
|
|||
private static void AutoAddDefinitionProviders(IServiceCollection services) |
|||
{ |
|||
var definitionProviders = new List<Type>(); |
|||
|
|||
services.OnRegistred(context => |
|||
{ |
|||
if (typeof(INotificationDefinitionProvider).IsAssignableFrom(context.ImplementationType)) |
|||
{ |
|||
definitionProviders.Add(context.ImplementationType); |
|||
} |
|||
}); |
|||
|
|||
services.Configure<AbpNotificationOptions>(options => |
|||
{ |
|||
options.DefinitionProviders.AddIfNotContains(definitionProviders); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,17 @@ |
|||
using Volo.Abp.Collections; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public class AbpNotificationOptions |
|||
{ |
|||
public ITypeList<INotificationDefinitionProvider> DefinitionProviders { get; } |
|||
|
|||
public ITypeList<INotificationPublishProvider> PublishProviders { get; } |
|||
|
|||
public AbpNotificationOptions() |
|||
{ |
|||
PublishProviders = new TypeList<INotificationPublishProvider>(); |
|||
DefinitionProviders = new TypeList<INotificationDefinitionProvider>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public interface INotificationDefinitionContext |
|||
{ |
|||
NotificationDefinition GetOrNull(string name); |
|||
|
|||
void Add(params NotificationDefinition[] definitions); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public interface INotificationDefinitionManager |
|||
{ |
|||
[NotNull] |
|||
NotificationDefinition Get([NotNull] string name); |
|||
|
|||
IReadOnlyList<NotificationDefinition> GetAll(); |
|||
|
|||
NotificationDefinition GetOrNull(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public interface INotificationDefinitionProvider |
|||
{ |
|||
void Define(INotificationDefinitionContext context); |
|||
} |
|||
} |
|||
@ -1,9 +1,27 @@ |
|||
using System.Threading.Tasks; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public interface INotificationDispatcher |
|||
{ |
|||
Task DispatcheAsync(NotificationInfo notification); |
|||
/// <summary>
|
|||
/// 发送通知
|
|||
/// </summary>
|
|||
/// <param name="notification"></param>
|
|||
/// <returns></returns>
|
|||
[Obsolete("Api已过时,请调用 DispatcheAsync(string notificationName, NotificationData data, Guid? tenantId = null)")] |
|||
Task DispatchAsync(NotificationInfo notification); |
|||
|
|||
/// <summary>
|
|||
/// 发送通知
|
|||
/// </summary>
|
|||
/// <param name="notificationName">通知名称</param>
|
|||
/// <param name="data">数据</param>
|
|||
/// <param name="tenantId">租户</param>
|
|||
/// <param name="notificationSeverity">级别</param>
|
|||
/// <returns></returns>
|
|||
Task DispatchAsync(string notificationName, NotificationData data, Guid? tenantId = null, |
|||
NotificationSeverity notificationSeverity = NotificationSeverity.Info); |
|||
} |
|||
} |
|||
|
|||
@ -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<UserIdentifier> identifiers); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public interface INotificationPublishProviderManager |
|||
{ |
|||
List<INotificationPublishProvider> Providers { get; } |
|||
} |
|||
} |
|||
@ -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<Guid> userIds); |
|||
} |
|||
} |
|||
@ -1,34 +1,107 @@ |
|||
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; |
|||
|
|||
namespace LINGYUN.Abp.Notifications.Internal |
|||
{ |
|||
internal class DefaultNotificationDispatcher : INotificationDispatcher |
|||
{ |
|||
public ILogger<DefaultNotificationDispatcher> Logger { get; set; } |
|||
|
|||
private readonly INotificationStore _notificationStore; |
|||
private readonly INotificationPublisher _notificationPublisher; |
|||
private readonly INotificationDefinitionManager _notificationDefinitionManager; |
|||
private readonly INotificationPublishProviderManager _notificationPublishProviderManager; |
|||
public DefaultNotificationDispatcher( |
|||
INotificationStore notificationStore, |
|||
INotificationPublisher notificationPublisher) |
|||
INotificationDefinitionManager notificationDefinitionManager, |
|||
INotificationPublishProviderManager notificationPublishProviderManager) |
|||
{ |
|||
_notificationStore = notificationStore; |
|||
_notificationPublisher = notificationPublisher; |
|||
_notificationDefinitionManager = notificationDefinitionManager; |
|||
_notificationPublishProviderManager = notificationPublishProviderManager; |
|||
|
|||
Logger = NullLogger<DefaultNotificationDispatcher>.Instance; |
|||
} |
|||
|
|||
public async Task DispatcheAsync(NotificationInfo notification) |
|||
public virtual async Task DispatchAsync(string notificationName, NotificationData data, Guid? tenantId = null, |
|||
NotificationSeverity notificationSeverity = NotificationSeverity.Info) |
|||
{ |
|||
// 获取自定义的通知
|
|||
var defineNotification = _notificationDefinitionManager.Get(notificationName); |
|||
|
|||
var notificationInfo = new NotificationInfo |
|||
{ |
|||
Name = defineNotification.Name, |
|||
CreationTime = DateTime.Now, |
|||
NotificationSeverity = notificationSeverity, |
|||
NotificationType = defineNotification.NotificationType, |
|||
TenantId = tenantId, |
|||
Data = data |
|||
}; |
|||
|
|||
var providers = Enumerable |
|||
.Reverse(_notificationPublishProviderManager.Providers); |
|||
|
|||
if (defineNotification.Providers.Any()) |
|||
{ |
|||
providers = providers.Where(p => defineNotification.Providers.Contains(p.Name)); |
|||
} |
|||
|
|||
await PublishFromProvidersAsync(providers, notificationInfo); |
|||
} |
|||
|
|||
public virtual async Task DispatchAsync(NotificationInfo notification) |
|||
{ |
|||
// 获取自定义的通知
|
|||
var defineNotification = _notificationDefinitionManager.Get(notification.Name); |
|||
|
|||
notification.NotificationType = defineNotification.NotificationType; |
|||
notification.Name = defineNotification.Name; |
|||
|
|||
var providers = Enumerable |
|||
.Reverse(_notificationPublishProviderManager.Providers); |
|||
|
|||
if (defineNotification.Providers.Any()) |
|||
{ |
|||
providers = providers.Where(p => defineNotification.Providers.Contains(p.Name)); |
|||
} |
|||
|
|||
await PublishFromProvidersAsync(providers, notification); |
|||
} |
|||
|
|||
protected async Task PublishFromProvidersAsync(IEnumerable<INotificationPublishProvider> providers, |
|||
NotificationInfo notificationInfo) |
|||
{ |
|||
// 持久化通知
|
|||
await _notificationStore.InsertNotificationAsync(notification); |
|||
await _notificationStore.InsertNotificationAsync(notificationInfo); |
|||
|
|||
// 获取用户订阅列表
|
|||
var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notification.TenantId, notification.Name); |
|||
var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notificationInfo.TenantId, 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)); |
|||
|
|||
// 发布用户通知
|
|||
await _notificationPublisher.PublishAsync(notification, subscriptionUserIds); |
|||
// 发送通知
|
|||
foreach (var provider in providers) |
|||
{ |
|||
try |
|||
{ |
|||
await provider.PublishAsync(notificationInfo, subscriptionUserIdentifiers); |
|||
} |
|||
catch(Exception ex) |
|||
{ |
|||
Logger.LogWarning("Send notification error with provider {0}", provider.Name); |
|||
Logger.LogWarning("Error message:{0}", ex.Message); |
|||
|
|||
Logger.LogTrace(ex, "Send notification error with provider {0}", provider.Name); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,70 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public class NotificationDefinition |
|||
{ |
|||
/// <summary>
|
|||
/// 通知名称
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public string Name { get; set; } |
|||
/// <summary>
|
|||
/// 通知显示名称
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public ILocalizableString DisplayName |
|||
{ |
|||
get => _displayName; |
|||
set => _displayName = Check.NotNull(value, nameof(value)); |
|||
} |
|||
private ILocalizableString _displayName; |
|||
/// <summary>
|
|||
/// 通知说明
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public ILocalizableString Description { get; set; } |
|||
/// <summary>
|
|||
/// 允许客户端显示订阅
|
|||
/// </summary>
|
|||
public bool AllowSubscriptionToClients { get; set; } |
|||
/// <summary>
|
|||
/// 通知类型
|
|||
/// </summary>
|
|||
public NotificationType NotificationType { get; set; } |
|||
/// <summary>
|
|||
/// 通知提供者
|
|||
/// </summary>
|
|||
public List<string> Providers { get; } |
|||
|
|||
public NotificationDefinition( |
|||
string name, |
|||
ILocalizableString displayName = null, |
|||
ILocalizableString description = null, |
|||
NotificationType notificationType = NotificationType.Application, |
|||
bool allowSubscriptionToClients = false) |
|||
{ |
|||
Name = name; |
|||
DisplayName = displayName ?? new FixedLocalizableString(name); |
|||
Description = description; |
|||
NotificationType = notificationType; |
|||
AllowSubscriptionToClients = allowSubscriptionToClients; |
|||
|
|||
Providers = new List<string>(); |
|||
} |
|||
|
|||
public virtual NotificationDefinition WithProviders(params string[] providers) |
|||
{ |
|||
if (!providers.IsNullOrEmpty()) |
|||
{ |
|||
Providers.AddRange(providers); |
|||
} |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public class NotificationDefinitionContext : INotificationDefinitionContext |
|||
{ |
|||
protected Dictionary<string, NotificationDefinition> Notifications { get; } |
|||
|
|||
public NotificationDefinitionContext(Dictionary<string, NotificationDefinition> notifications) |
|||
{ |
|||
Notifications = notifications; |
|||
} |
|||
|
|||
public void Add(params NotificationDefinition[] definitions) |
|||
{ |
|||
if (definitions.IsNullOrEmpty()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var definition in definitions) |
|||
{ |
|||
Notifications[definition.Name] = definition; |
|||
} |
|||
} |
|||
|
|||
public NotificationDefinition GetOrNull(string name) |
|||
{ |
|||
return Notifications.GetOrDefault(name); |
|||
} |
|||
} |
|||
} |
|||
@ -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<IDictionary<string, NotificationDefinition>> NotificationDefinitions { get; } |
|||
|
|||
protected AbpNotificationOptions Options { get; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; } |
|||
|
|||
public NotificationDefinitionManager( |
|||
IOptions<AbpNotificationOptions> options, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
Options = options.Value; |
|||
|
|||
NotificationDefinitions = new Lazy<IDictionary<string, NotificationDefinition>>(CreateNotificationDefinitions, true); |
|||
} |
|||
|
|||
public virtual NotificationDefinition Get([NotNull] string name) |
|||
{ |
|||
Check.NotNull(name, nameof(name)); |
|||
|
|||
var notification = GetOrNull(name); |
|||
|
|||
if (notification == null) |
|||
{ |
|||
throw new AbpException("Undefined notification: " + name); |
|||
} |
|||
|
|||
return notification; |
|||
} |
|||
|
|||
public virtual IReadOnlyList<NotificationDefinition> GetAll() |
|||
{ |
|||
return NotificationDefinitions.Value.Values.ToImmutableList(); |
|||
} |
|||
|
|||
public virtual NotificationDefinition GetOrNull(string name) |
|||
{ |
|||
return NotificationDefinitions.Value.GetOrDefault(name); |
|||
} |
|||
|
|||
protected virtual IDictionary<string, NotificationDefinition> CreateNotificationDefinitions() |
|||
{ |
|||
var notifications = new Dictionary<string, NotificationDefinition>(); |
|||
|
|||
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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.Notifications |
|||
{ |
|||
public abstract class NotificationDefinitionProvider : INotificationDefinitionProvider, ITransientDependency |
|||
{ |
|||
public abstract void Define(INotificationDefinitionContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
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 NotificationPublishProvider(IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
|
|||
public abstract Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers); |
|||
} |
|||
} |
|||
@ -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<INotificationPublishProvider> Providers => _lazyProviders.Value; |
|||
|
|||
protected AbpNotificationOptions Options { get; } |
|||
|
|||
private readonly Lazy<List<INotificationPublishProvider>> _lazyProviders; |
|||
|
|||
public NotificationPublishProviderManager( |
|||
IServiceProvider serviceProvider, |
|||
IOptions<AbpNotificationOptions> options) |
|||
{ |
|||
Options = options.Value; |
|||
|
|||
_lazyProviders = new Lazy<List<INotificationPublishProvider>>( |
|||
() => Options |
|||
.PublishProviders |
|||
.Select(type => serviceProvider.GetRequiredService(type) as INotificationPublishProvider) |
|||
.ToList(), |
|||
true |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using LINGYUN.Abp.MessageService.Localization; |
|||
using LINGYUN.Abp.Notifications; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Users.Notifications; |
|||
|
|||
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"), |
|||
allowSubscriptionToClients: true)); |
|||
} |
|||
|
|||
protected LocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<MessageServiceResource>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -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<Guid> userIds) |
|||
{ |
|||
await NotificationPublisher.PublishAsync(notification, userIds); |
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace LINGYUN.Abp.MessageService.Notifications |
|||
{ |
|||
class NotificationPublisher |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using LINGYUN.Abp.MessageService.Localization; |
|||
using LINGYUN.Abp.Notifications; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.MessageService.LINGYUN.Abp.MessageService.Notifications |
|||
{ |
|||
public class MessageServiceDefinitionProvider : NotificationDefinitionProvider |
|||
{ |
|||
public override void Define(INotificationDefinitionContext context) |
|||
{ |
|||
context.Add(new NotificationDefinition( |
|||
"TestApplicationNotofication", |
|||
L("TestApplicationNotofication"), |
|||
L("TestApplicationNotofication"), |
|||
NotificationType.Application, |
|||
true)); |
|||
} |
|||
|
|||
protected LocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<MessageServiceResource>(name); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,503 @@ |
|||
// <auto-generated />
|
|||
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("20200609151853_Create-User-Subscription-Column-UserName")] |
|||
partial class CreateUserSubscriptionColumnUserName |
|||
{ |
|||
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<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("Address") |
|||
.HasColumnType("varchar(256) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(256); |
|||
|
|||
b.Property<bool>("AllowAnonymous") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowSendMessage") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnName("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnName("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("Description") |
|||
.HasColumnType("varchar(128) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(128); |
|||
|
|||
b.Property<long>("GroupId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime?>("LastModificationTime") |
|||
.HasColumnName("LastModificationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("LastModifierId") |
|||
.HasColumnName("LastModifierId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<int>("MaxUserCount") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Name") |
|||
.IsRequired() |
|||
.HasColumnType("varchar(20) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(20); |
|||
|
|||
b.Property<string>("Notice") |
|||
.HasColumnType("varchar(64) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(64); |
|||
|
|||
b.Property<string>("Tag") |
|||
.HasColumnType("varchar(512) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(512); |
|||
|
|||
b.Property<Guid?>("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<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<bool>("AllowAddPeople") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowDissolveGroup") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowKickPeople") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowSendNotice") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowSilence") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<long>("GroupId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<bool>("IsSuperAdmin") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<DateTime?>("LastModificationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("LastModifierId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("UserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("TenantId", "GroupId"); |
|||
|
|||
b.ToTable("AppChatGroupAdmins"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupChatBlack", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<long>("GroupId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid>("ShieldUserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid?>("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<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("Content") |
|||
.IsRequired() |
|||
.HasColumnType("longtext CHARACTER SET utf8mb4") |
|||
.HasMaxLength(1048576); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnName("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<long>("GroupId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<long>("MessageId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<sbyte>("SendState") |
|||
.HasColumnType("tinyint"); |
|||
|
|||
b.Property<string>("SendUserName") |
|||
.IsRequired() |
|||
.HasColumnType("varchar(64) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(64); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<int>("Type") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("TenantId", "GroupId"); |
|||
|
|||
b.ToTable("AppGroupMessages"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatBlack", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("ShieldUserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("UserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("TenantId", "UserId"); |
|||
|
|||
b.ToTable("AppUserChatBlacks"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatGroup", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnName("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnName("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<long>("GroupId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("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<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<bool>("AllowAddFriend") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowAnonymous") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowReceiveMessage") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("AllowSendMessage") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<bool>("RequireAddFriendValition") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("UserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("TenantId", "UserId"); |
|||
|
|||
b.ToTable("AppUserChatSettings"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserMessage", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("Content") |
|||
.IsRequired() |
|||
.HasColumnType("longtext CHARACTER SET utf8mb4") |
|||
.HasMaxLength(1048576); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnName("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<long>("MessageId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid>("ReceiveUserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<sbyte>("SendState") |
|||
.HasColumnType("tinyint"); |
|||
|
|||
b.Property<string>("SendUserName") |
|||
.IsRequired() |
|||
.HasColumnType("varchar(64) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(64); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<int>("Type") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("TenantId", "ReceiveUserId"); |
|||
|
|||
b.ToTable("AppUserMessages"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserSpecialFocus", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("FocusUserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("UserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("TenantId", "UserId"); |
|||
|
|||
b.ToTable("AppUserSpecialFocuss"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.Notification", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnName("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<DateTime?>("ExpirationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("NotificationData") |
|||
.IsRequired() |
|||
.HasColumnType("longtext CHARACTER SET utf8mb4") |
|||
.HasMaxLength(1048576); |
|||
|
|||
b.Property<long>("NotificationId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("NotificationName") |
|||
.IsRequired() |
|||
.HasColumnType("varchar(100) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(100); |
|||
|
|||
b.Property<string>("NotificationTypeName") |
|||
.IsRequired() |
|||
.HasColumnType("varchar(512) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(512); |
|||
|
|||
b.Property<sbyte>("Severity") |
|||
.HasColumnType("tinyint"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<int>("Type") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("NotificationName"); |
|||
|
|||
b.ToTable("AppNotifications"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.UserNotification", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<long>("NotificationId") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<int>("ReadStatus") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("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<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnName("CreationTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("NotificationName") |
|||
.IsRequired() |
|||
.HasColumnType("varchar(100) CHARACTER SET utf8mb4") |
|||
.HasMaxLength(100); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnName("TenantId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<Guid>("UserId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("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
|
|||
} |
|||
} |
|||
} |
|||
@ -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<string>( |
|||
name: "UserName", |
|||
table: "AppUserSubscribes", |
|||
maxLength: 128, |
|||
nullable: false, |
|||
defaultValue: "/"); |
|||
} |
|||
|
|||
protected override void Down(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropColumn( |
|||
name: "UserName", |
|||
table: "AppUserSubscribes"); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue