From 52a7047b118641d778c8fdb5f899e2bb5cb9fdda Mon Sep 17 00:00:00 2001 From: cKey <35512826+colinin@users.noreply.github.com> Date: Sat, 30 May 2020 21:07:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=88=86=E5=B8=83=E5=BC=8F?= =?UTF-8?q?=E9=94=81=E6=A8=A1=E5=9D=97;=E6=96=B0=E5=A2=9E=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LINGYUN.Abp.DistributedLock.csproj | 8 + .../Distributed/DistributedLockException.cs | 13 + .../Abp/Distributed/IDistributedLock.cs | 61 +++ .../Abp/IM/SignalR/OnlineClientHubBase.cs | 11 +- .../LINGYUN/Abp/IM/IOnlineClient.cs | 2 + .../LINGYUN/Abp/IM/OnlineClient.cs | 6 +- .../LINGYUN/Abp/IM/OnlineClientContext.cs | 5 +- .../LINGYUN/Abp/IM/OnlineClientManager.cs | 1 + .../Location/Baidu/BaiduLocationHttpClient.cs | 2 +- .../LINGYUN.Abp.Notifications.csproj | 12 + .../Notifications/INotificationDispatcher.cs | 9 + .../Notifications/INotificationPublisher.cs | 11 + .../Abp/Notifications/INotificationSender.cs | 12 + .../Abp/Notifications/INotificationStore.cs | 31 ++ .../Abp/Notifications/NotificationData.cs | 49 +++ .../Abp/Notifications/NotificationInfo.cs | 21 + .../Notifications/NotificationReadState.cs | 17 + .../Abp/Notifications/NotificationSeverity.cs | 29 ++ .../NotificationSubscriptionInfo.cs | 11 + .../Abp/Notifications/NotificationType.cs | 17 + .../LINGYUN.Abp.RedisLock.csproj | 19 + .../Distributed/Redis/AbpRedisLockModule.cs | 14 + .../Distributed/Redis/RedisDistributedLock.cs | 316 +++++++++++++++ .../Abp/Distributed/Redis/RedisLockOptions.cs | 26 ++ ...UN.Abp.MessageService.Domain.Shared.csproj | 4 + .../{Messages => }/ReadStatus.cs | 2 +- .../{Messages => }/SendStatus.cs | 2 +- .../LINGYUN.Abp.MessageService.Domain.csproj | 5 +- .../Notifications/INotificationStore.cs | 11 + .../Notifications/Notification.cs | 30 ++ .../Notifications/NotificationConsts.cs | 13 + .../Notifications/NotificationDispatcher.cs | 47 +++ .../Notifications/NotificationPublisher.cs | 10 + .../Notifications/UserNotification.cs | 20 + .../Subscriptions/ISubscribeRepository.cs | 18 + .../Subscriptions/ISubscribeStore.cs | 13 + .../Subscriptions/RoleSubscribe.cs | 17 + .../MessageService/Subscriptions/Subscribe.cs | 14 +- .../Subscriptions/SubscribeConsts.cs | 9 + .../Subscriptions/SubscribeStore.cs | 41 ++ .../Subscriptions/UserSubscribe.cs | 17 + .../Utils/ISnowflakeIdGenerator.cs | 7 + .../LINGYUN.Abp.MessageService.SignalR.csproj | 1 + .../SignalR/AbpMessageServiceSignalRModule.cs | 11 + .../MessageService/SignalR/ChatMessaheHub.cs | 10 - .../SignalR/Hubs/AbpMessageHub.cs | 8 + .../SignalRNotificationPublisher.cs | 60 +++ vueJs/src/api/users.ts | 14 +- .../TenantBox/index.vue} | 0 vueJs/src/permission.ts | 2 +- vueJs/src/router/index.ts | 5 + .../components/GlobalSettingEditForm.vue | 26 +- vueJs/src/views/login/index.vue | 30 +- vueJs/src/views/register/index.vue | 375 ++++++++++++++++++ 54 files changed, 1476 insertions(+), 49 deletions(-) create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN.Abp.DistributedLock.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/DistributedLockException.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/IDistributedLock.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationReadState.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSeverity.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSubscriptionInfo.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN.Abp.RedisLock.csproj create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/AbpRedisLockModule.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisDistributedLock.cs create mode 100644 aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisLockOptions.cs rename aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/{Messages => }/ReadStatus.cs (84%) rename aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/{Messages => }/SendStatus.cs (90%) create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationPublisher.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/AbpMessageServiceSignalRModule.cs delete mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/ChatMessaheHub.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Hubs/AbpMessageHub.cs create mode 100644 aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs rename vueJs/src/{views/login/components/TenantSelect.vue => components/TenantBox/index.vue} (100%) create mode 100644 vueJs/src/views/register/index.vue diff --git a/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN.Abp.DistributedLock.csproj b/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN.Abp.DistributedLock.csproj new file mode 100644 index 000000000..9115b80b6 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN.Abp.DistributedLock.csproj @@ -0,0 +1,8 @@ + + + + netstandard2.0 + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/DistributedLockException.cs b/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/DistributedLockException.cs new file mode 100644 index 000000000..883bb7973 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/DistributedLockException.cs @@ -0,0 +1,13 @@ +using System; + +namespace LINGYUN.Abp.Distributed +{ + public class DistributedLockException : Exception + { + public DistributedLockException(string message) + : base(message) + { + + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/IDistributedLock.cs b/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/IDistributedLock.cs new file mode 100644 index 000000000..fc46c4a74 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.DistributedLock/LINGYUN/Abp/Distributed/IDistributedLock.cs @@ -0,0 +1,61 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Distributed +{ + /// + /// 分布式锁接口 + /// + public interface IDistributedLock + { + /// + /// 分布式锁 + /// 需要手动释放锁 + /// + /// 锁键名 + /// 锁定对象 + /// 锁定时间(秒) + /// + bool Lock(string lockKey, string lockValue, int lockSecond = 30); + /// + /// 分布式锁 + /// using块自动释放锁 + /// + /// 锁键名 + /// 锁定时间(秒) + /// + IDisposable Lock(string lockKey, int lockSecond = 30); + /// + /// 分布式锁 + /// using块自动释放锁 + /// + /// 锁键名 + /// 锁定时间(秒) + /// + Task LockAsync(string lockKey, int lockSecond = 30, CancellationToken token = default(CancellationToken)); + /// + /// 分布式锁 + /// 需要手动释放锁 + /// + /// 锁键名 + /// 锁定对象 + /// 锁定时间(秒) + /// + Task LockAsync(string lockKey, string lockValue, int lockSecond = 30, CancellationToken token = default(CancellationToken)); + /// + /// 释放锁资源 + /// + /// 锁键名 + /// 锁定对象 + /// + bool Release(string lockKey, string lockValue); + /// + /// 释放锁资源 + /// + /// 锁键名 + /// 锁定对象 + /// + Task ReleaseAsync(string lockKey, string lockValue, CancellationToken token = default(CancellationToken)); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs index 0f4228206..ad432a11e 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs @@ -38,19 +38,14 @@ namespace LINGYUN.Abp.IM.SignalR protected virtual IOnlineClient CreateClientForCurrentConnection() { - return new OnlineClient(Context.ConnectionId, GetIpAddressOfClient(), - CurrentTenant.Id, CurrentUser.Id) + return new OnlineClient(Context.ConnectionId, GetClientIpAddress(), + CurrentTenant.Id, CurrentUser.Id, CurrentUser.Roles) { ConnectTime = Clock.Now }; } - protected virtual string GetIpAddressOfClient() - { - return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); - } - - protected virtual string GetClientIpAddress(HttpContext httpContext) + protected virtual string GetClientIpAddress() { try { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs index 446ea1d9a..9106ad1b3 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs @@ -13,6 +13,8 @@ namespace LINGYUN.Abp.IM Guid? UserId { get; } + string[] Roles { get; } + DateTime ConnectTime { get; } object this[string key] { get; set; } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs index 503ec7e5a..0771f485d 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs @@ -20,6 +20,8 @@ namespace LINGYUN.Abp.IM public Guid? UserId { get; set; } + public string[] Roles { get; set; } + public DateTime ConnectTime { get; set; } private Dictionary _properties; @@ -39,16 +41,18 @@ namespace LINGYUN.Abp.IM public OnlineClient() { + Roles = new string[0]; ConnectTime = DateTime.Now; } - public OnlineClient(string connectionId, string ipAddress, Guid? tenantId, Guid? userId) + public OnlineClient(string connectionId, string ipAddress, Guid? tenantId, Guid? userId, params string[] roles) : this() { ConnectionId = connectionId; IpAddress = ipAddress; TenantId = tenantId; UserId = userId; + Roles = roles; Properties = new Dictionary(); } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs index e6d4eedd7..e27877c3e 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs @@ -4,17 +4,14 @@ namespace LINGYUN.Abp.IM { public class OnlineClientContext { - public string ConnectionId { get; } - public Guid? TenantId { get; } public Guid UserId { get; } - public OnlineClientContext(string connectionId, Guid userId, Guid? tenantId) + public OnlineClientContext(Guid userId, Guid? tenantId) { UserId = userId; TenantId = tenantId; - ConnectionId = connectionId; } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs index 0a7d6b3b8..c82594930 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs @@ -102,6 +102,7 @@ namespace LINGYUN.Abp.IM return GetAllClients() .Where(c => c.UserId == context.UserId && c.TenantId == context.TenantId) + .WhereIf(context.Roles.Length > 0, c => c.Roles.Any(role => context.Roles.Contains(role))) .ToImmutableList(); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Location.Baidu/LINGYUN/Abp/Location/Baidu/BaiduLocationHttpClient.cs b/aspnet-core/modules/common/LINGYUN.Abp.Location.Baidu/LINGYUN/Abp/Location/Baidu/BaiduLocationHttpClient.cs index d4e18c8f3..45490093b 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Location.Baidu/LINGYUN/Abp/Location/Baidu/BaiduLocationHttpClient.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Location.Baidu/LINGYUN/Abp/Location/Baidu/BaiduLocationHttpClient.cs @@ -120,7 +120,7 @@ namespace LINGYUN.Abp.Location.Baidu { var localizerFactory = ServiceProvider.GetRequiredService(); var localizerErrorMessage = baiduLocationResponse.GetErrorMessage().Localize(localizerFactory); - var localizerErrorDescription = baiduLocationResponse.GetErrorMessage().Localize(localizerFactory); + var localizerErrorDescription = baiduLocationResponse.GetErrorDescription().Localize(localizerFactory); var localizer = ServiceProvider.GetRequiredService>(); localizerErrorMessage = localizer["ResolveLocationFailed", localizerErrorMessage, localizerErrorDescription]; if (Options.VisableErrorToClient) 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 new file mode 100644 index 000000000..268dae169 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + 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 new file mode 100644 index 000000000..180f82d59 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationDispatcher + { + Task DispatcheAsync(NotificationInfo notification); + } +} 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 new file mode 100644 index 000000000..523856eea --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationPublisher + { + Task PublishAsync(NotificationData data, IEnumerable userIds, Guid? tenantId); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs new file mode 100644 index 000000000..aed195b60 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationSender + { + Task SendAsync(NotificationData data, Guid userId, Guid? tenantId); + Task SendAsync(NotificationData data, IEnumerable userIds, Guid? tenantId); + } +} 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 new file mode 100644 index 000000000..e35c2a4aa --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications +{ + public interface INotificationStore + { + Task InsertUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName); + + Task DeleteUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName); + + Task> GetSubscriptionsAsync(Guid? tenantId, string notificationName); + + Task> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId); + + Task IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName); + + Task InsertNotificationAsync(NotificationInfo notification); + + Task DeleteNotificationAsync(NotificationInfo notification); + + Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId); + + Task DeleteUserNotificationAsync(Guid? tenantId, Guid userId, long notificationId); + + Task GetNotificationOrNullAsync(Guid? tenantId, long notificationId); + + Task ChangeUserNotificationReadStateAsync(Guid? tenantId, Guid userId, string notificationName, NotificationReadState readState); + } +} 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 new file mode 100644 index 000000000..2ed903b2d --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationData + { + public virtual string Type => GetType().FullName; + + public object this[string key] + { + get + { + if(Properties.TryGetValue(key, out object @obj)) + { + return @obj; + } + return null; + } + set { Properties[key] = value; } + } + + public Dictionary Properties + { + get { return _properties; } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + foreach (var keyValue in value) + { + if (!_properties.ContainsKey(keyValue.Key)) + { + _properties[keyValue.Key] = keyValue.Value; + } + } + } + } + private readonly Dictionary _properties; + + public NotificationData() + { + _properties = new Dictionary(); + } + } +} 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 new file mode 100644 index 000000000..3f1826be9 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs @@ -0,0 +1,21 @@ +using System; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationInfo + { + public Guid? TenantId { get; set; } + public string Name { get; set; } + public NotificationData Data { get; set; } + public DateTime? ExpirationTime { get; set; } + public DateTime CreationTime { get; set; } + public NotificationType NotificationType { get; set; } + public NotificationSeverity NotificationSeverity { get; set; } + public NotificationInfo() + { + Data = new NotificationData(); + NotificationType = NotificationType.Application; + NotificationSeverity = NotificationSeverity.Info; + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationReadState.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationReadState.cs new file mode 100644 index 000000000..b1319e865 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationReadState.cs @@ -0,0 +1,17 @@ +namespace LINGYUN.Abp.Notifications +{ + /// + /// 读取状态 + /// + public enum NotificationReadState + { + /// + /// 已读 + /// + Read = 0, + /// + /// 未读 + /// + UnRead = 1 + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSeverity.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSeverity.cs new file mode 100644 index 000000000..0b13ccfb4 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSeverity.cs @@ -0,0 +1,29 @@ +namespace LINGYUN.Abp.Notifications +{ + /// + /// 严重级别 + /// + public enum NotificationSeverity : sbyte + { + /// + /// 成功 + /// + Success = 0, + /// + /// 信息 + /// + Info = 10, + /// + /// 警告 + /// + Warn = 20, + /// + /// 错误 + /// + Error = 30, + /// + /// 致命错误 + /// + Fatal = 40 + } +} 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 new file mode 100644 index 000000000..0122731fc --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationSubscriptionInfo.cs @@ -0,0 +1,11 @@ +using System; + +namespace LINGYUN.Abp.Notifications +{ + public class NotificationSubscriptionInfo + { + public Guid? TenantId { get; set; } + public Guid UserId { get; set; } + public string NotificationName { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs new file mode 100644 index 000000000..ce5db6c6c --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs @@ -0,0 +1,17 @@ +namespace LINGYUN.Abp.Notifications +{ + /// + /// 通知类型 + /// + public enum NotificationType + { + /// + /// 应用 + /// + Application = 0, + /// + /// 系统 + /// + System = 10 + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN.Abp.RedisLock.csproj b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN.Abp.RedisLock.csproj new file mode 100644 index 000000000..b9df59cc8 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN.Abp.RedisLock.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/AbpRedisLockModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/AbpRedisLockModule.cs new file mode 100644 index 000000000..156df84c2 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/AbpRedisLockModule.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Distributed.Redis +{ + public class AbpRedisLockModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(configuration.GetSection("DistributedLock:Redis")); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisDistributedLock.cs b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisDistributedLock.cs new file mode 100644 index 000000000..417dbe73e --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisDistributedLock.cs @@ -0,0 +1,316 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Polly; +using StackExchange.Redis; +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Distributed.Redis +{ + [ExposeServices(typeof(IDistributedLock))] + [Dependency(ServiceLifetime.Singleton, TryRegister = true)] + public class RedisDistributedLock : IDistributedLock + { + public ILogger Logger { protected get; set; } + + private volatile ConnectionMultiplexer _connection; + private IDatabase _redis; + + private readonly RedisLockOptions _options; + private readonly string _instance; + + private readonly SemaphoreSlim _connectionLock = new SemaphoreSlim(initialCount: 1, maxCount: 1); + + public RedisDistributedLock(IOptions optionsAccessor) + { + if (optionsAccessor == null) + { + throw new ArgumentNullException(nameof(optionsAccessor)); + } + + _options = optionsAccessor.Value; + + _instance = _options.InstanceName ?? string.Empty; + + Logger = NullLogger.Instance; + } + + private void RegistenConnectionEvent(ConnectionMultiplexer connection) + { + if (connection != null) + { + connection.ConnectionFailed += OnConnectionFailed; + connection.ConnectionRestored += OnConnectionRestored; + connection.ErrorMessage += OnErrorMessage; + connection.ConfigurationChanged += OnConfigurationChanged; + connection.HashSlotMoved += OnHashSlotMoved; + connection.InternalError += OnInternalError; + connection.ConfigurationChangedBroadcast += OnConfigurationChangedBroadcast; + } + } + + public bool Lock(string lockKey, string lockValue, int lockSecond = 30) + { + Connect(); + return LockTakeSync(lockKey, lockValue, TimeSpan.FromSeconds(lockSecond)); + } + + public async Task LockAsync(string lockKey, string lockValue, int lockSecond = 30, CancellationToken token = default) + { + await ConnectAsync(token); + return await LockTakeAsync(lockKey, lockValue, TimeSpan.FromSeconds(lockSecond)); + } + + public IDisposable Lock(string lockKey, int lockSecond = 30) + { + Connect(); + var redisLockToken = Environment.MachineName; + var redisLockKey = _instance + lockKey; + var lockResult = LockTakeSync(redisLockKey, redisLockToken, TimeSpan.FromSeconds(lockSecond)); + if (lockResult) + { + return new DisposeAction(() => + { + LockReleaseSync(redisLockKey, redisLockToken); + }); + } + Logger.LogWarning("Redis lock failed of key: {0}", redisLockKey); + throw new DistributedLockException(redisLockKey); + } + + public async Task LockAsync(string lockKey, int lockSecond = 30, CancellationToken token = default(CancellationToken)) + { + await ConnectAsync(token); + var redisLockToken = Environment.MachineName; + var redisLockKey = _instance + lockKey; + var lockResult = await LockTakeAsync(redisLockKey, redisLockToken, TimeSpan.FromSeconds(lockSecond)); + + if (lockResult) + { + return new DisposeAction(async () => + { + await LockReleaseAsync(redisLockKey, redisLockToken); + }); + } + Logger.LogWarning("Redis lock failed of key: {0}", redisLockKey); + throw new DistributedLockException(redisLockKey); + } + + public bool Release(string lockKey, string lockValue) + { + Connect(); + return LockReleaseSync(lockKey, lockValue); + } + + public async Task ReleaseAsync(string lockKey, string lockValue, CancellationToken token = default) + { + await ConnectAsync(token); + return await LockReleaseAsync(lockKey, lockValue); + } + /// + /// 同步加锁 + /// + /// + /// + /// + /// + protected virtual bool LockTakeSync(RedisKey key, RedisValue value, TimeSpan expiry) + { + // 定义重试策略 + var policy = Policy + .HandleResult(result => !result) + .WaitAndRetry( + retryCount: _options.FailedRetryCount, + sleepDurationProvider: sleep => TimeSpan.FromMilliseconds(_options.FailedRetryInterval), + onRetry: (result, timeSpan) => + { + Logger.LogWarning("Redis lock take failed, retry policy timeSpan:{0}", timeSpan.ToString()); + }); + // 加锁 + var lockResult = policy.Execute(() => _redis.LockTake(key, value, expiry)); + + return lockResult; + } + /// + /// 异步加锁 + /// + /// + /// + /// + /// + protected virtual async Task LockTakeAsync(RedisKey key, RedisValue value, TimeSpan expiry) + { + // 定义重试策略 + var policy = Policy + .HandleResult(result => !result) + .WaitAndRetryAsync( + retryCount: _options.FailedRetryCount, + sleepDurationProvider: sleep => TimeSpan.FromMilliseconds(_options.FailedRetryInterval), + onRetry: (result, timeSpan) => + { + Logger.LogWarning("Redis lock take failed, retry policy timeSpan:{0}", timeSpan.ToString()); + }); + // 加锁 + var lockResult = await policy.ExecuteAsync(async () => + await _redis.LockTakeAsync(key, value, expiry)); + + return lockResult; + } + /// + /// 同步释放锁 + /// + /// + /// + /// + protected virtual bool LockReleaseSync(RedisKey key, RedisValue value) + { + // 定义重试策略 + var policy = Policy + .HandleResult(result => !result) + .WaitAndRetry( + retryCount: _options.FailedRetryCount, + sleepDurationProvider: sleep => TimeSpan.FromMilliseconds(_options.FailedRetryInterval), + onRetry: (result, timeSpan) => + { + Logger.LogWarning("Redis lock release failed, retry policy timeSpan:{0}", timeSpan.ToString()); + }); + // 释放锁 + var lockReleaseResult = policy.Execute(() => _redis.LockRelease(key, value)); + + return lockReleaseResult; + } + /// + /// 异步释放锁 + /// + /// + /// + /// + protected virtual async Task LockReleaseAsync(RedisKey key, RedisValue value) + { + // 定义重试策略 + var policy = Policy + .HandleResult(result => !result) + .WaitAndRetryAsync( + retryCount: _options.FailedRetryCount, + sleepDurationProvider: sleep => TimeSpan.FromMilliseconds(_options.FailedRetryInterval), + onRetry: (result, timeSpan) => + { + Logger.LogWarning("Redis lock release failed, retry policy timeSpan:{0}", timeSpan.ToString()); + }); + // 释放锁 + var lockReleaseResult = await policy.ExecuteAsync(async () => + await _redis.LockReleaseAsync(key, value)); + + return lockReleaseResult; + } + + private void Connect() + { + if (_redis != null) + { + return; + } + + _connectionLock.Wait(); + try + { + if (_redis == null) + { + if (_options.ConfigurationOptions != null) + { + _connection = ConnectionMultiplexer.Connect(_options.ConfigurationOptions); + } + else + { + _connection = ConnectionMultiplexer.Connect(_options.Configuration); + } + RegistenConnectionEvent(_connection); + _redis = _connection.GetDatabase(); + } + } + finally + { + _connectionLock.Release(); + } + } + + + private async Task ConnectAsync(CancellationToken token = default(CancellationToken)) + { + token.ThrowIfCancellationRequested(); + + if (_redis != null) + { + return; + } + + await _connectionLock.WaitAsync(token); + try + { + if (_redis == null) + { + if (_options.ConfigurationOptions != null) + { + _connection = await ConnectionMultiplexer.ConnectAsync(_options.ConfigurationOptions); + } + else + { + _connection = await ConnectionMultiplexer.ConnectAsync(_options.Configuration); + } + RegistenConnectionEvent(_connection); + _redis = _connection.GetDatabase(); + } + } + finally + { + _connectionLock.Release(); + } + } + + private void OnConfigurationChangedBroadcast(object sender, EndPointEventArgs e) + { + Logger.LogInformation("Redis lock server master/slave changes"); + } + + private void OnInternalError(object sender, InternalErrorEventArgs e) + { + Logger.LogError("Redis lock internal error, origin:{0}, connectionType:{1}", + e.Origin, e.ConnectionType); + Logger.LogError(e.Exception, "Redis lock internal error"); + + } + + private void OnHashSlotMoved(object sender, HashSlotMovedEventArgs e) + { + Logger.LogInformation("Redis lock configuration changed"); + } + + private void OnConfigurationChanged(object sender, EndPointEventArgs e) + { + Logger.LogInformation("Redis lock configuration changed"); + } + + private void OnErrorMessage(object sender, RedisErrorEventArgs e) + { + Logger.LogWarning("Redis lock error, message:{0}", e.Message); + } + + private void OnConnectionRestored(object sender, ConnectionFailedEventArgs e) + { + Logger.LogWarning("Redis lock connection restored, failureType:{0}, connectionType:{1}", + e.FailureType, e.ConnectionType); + } + + private void OnConnectionFailed(object sender, ConnectionFailedEventArgs e) + { + Logger.LogError("Redis lock connection failed, failureType:{0}, connectionType:{1}", + e.FailureType, e.ConnectionType); + Logger.LogError(e.Exception, "Redis lock connection failed"); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisLockOptions.cs b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisLockOptions.cs new file mode 100644 index 000000000..e24941885 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.RedisLock/LINGYUN/Abp/Distributed/Redis/RedisLockOptions.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Options; +using StackExchange.Redis; + +namespace LINGYUN.Abp.Distributed.Redis +{ + public class RedisLockOptions : IOptions + { + public string Configuration { get; set; } + public ConfigurationOptions ConfigurationOptions { get; set; } + public string InstanceName { get; set; } + /// + /// 失败重试次数 + /// default: 3 + /// + public int FailedRetryCount { get; set; } = 3; + /// + /// 失败重试间隔 ms + /// default: 1000 + /// + public int FailedRetryInterval { get; set; } = 1000; + RedisLockOptions IOptions.Value + { + get { return this; } + } + } +} 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 83d348032..1cf822808 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 @@ -5,4 +5,8 @@ + + + + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/ReadStatus.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/ReadStatus.cs similarity index 84% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/ReadStatus.cs rename to aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/ReadStatus.cs index 331c2bc17..0fe9e94df 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/ReadStatus.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/ReadStatus.cs @@ -1,4 +1,4 @@ -namespace LINGYUN.Abp.MessageService.Messages +namespace LINGYUN.Abp.MessageService { /// /// 读取状态 diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/SendStatus.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/SendStatus.cs similarity index 90% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/SendStatus.cs rename to aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/SendStatus.cs index 9f4ec4ea0..7795118ab 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/SendStatus.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/SendStatus.cs @@ -1,4 +1,4 @@ -namespace LINGYUN.Abp.MessageService.Messages +namespace LINGYUN.Abp.MessageService { /// /// 消息状态 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 ddb361411..cb3747869 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 @@ -10,10 +10,7 @@ - - - - + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs new file mode 100644 index 000000000..3d6ae41b6 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs @@ -0,0 +1,11 @@ +using LINGYUN.Abp.Notifications; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public interface INotificationStore + { + Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId); + } +} 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 new file mode 100644 index 000000000..911511771 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs @@ -0,0 +1,30 @@ +using LINGYUN.Abp.Notifications; +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class Notification : Entity, IMultiTenant, IHasCreationTime + { + public virtual Guid? TenantId { get; protected set; } + public virtual NotificationSeverity Severity { get; protected set; } + public virtual long NotificationId { 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) + { + NotificationId = id; + Severity = severity; + NotificationName = name; + NotificationData = data; + NotificationTypeName = dataType; + CreationTime = DateTime.Now; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs new file mode 100644 index 000000000..62b2da9d0 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs @@ -0,0 +1,13 @@ +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class NotificationConsts + { + public const int MaxNameLength = 100; + + public const int MaxDataLength = 1024 * 1024; + + public const int MaxTypeNameLength = 256; + + public const int MaxAssemblyQualifiedNameLength = 512; + } +} 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 new file mode 100644 index 000000000..df76ef4af --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs @@ -0,0 +1,47 @@ +using LINGYUN.Abp.MessageService.Subscriptions; +using LINGYUN.Abp.MessageService.Utils; +using LINGYUN.Abp.Notifications; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class NotificationDispatcher : INotificationDispatcher, ITransientDependency + { + protected IJsonSerializer JsonSerializer { get; } + protected ICurrentTenant CurrentTenant { get; } + protected ISubscribeStore SubscribeStore { get; } + protected INotificationStore NotificationStore { get; } + protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager.Current; + protected IUnitOfWorkManager UnitOfWorkManager { get; } + protected INotificationPublisher NotificationPublisher { get; } + + protected ISnowflakeIdGenerator SnowflakeIdGenerator { get; } + + [UnitOfWork] + public virtual async Task DispatcheAsync(NotificationInfo notification) + { + using (CurrentTenant.Change(notification.TenantId)) + { + var subscribeUsers = await SubscribeStore.GetUserSubscribesAsync(notification.Name); + foreach(var userId in subscribeUsers) + { + await NotificationStore.InsertUserNotificationAsync(notification, userId); + } + await CurrentUnitOfWork.SaveChangesAsync(); + + await NotifyAsync(notification.Data, notification.TenantId, subscribeUsers); + } + } + + protected virtual async Task NotifyAsync(NotificationData data, Guid? tenantId, IEnumerable userIds) + { + await NotificationPublisher.PublishAsync(data, userIds, tenantId); + } + } +} 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 new file mode 100644 index 000000000..2288cf3b6 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationPublisher.cs @@ -0,0 +1,10 @@ +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/UserNotification.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs new file mode 100644 index 000000000..76741a1b7 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs @@ -0,0 +1,20 @@ +using System; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class UserNotification : Entity, IMultiTenant + { + public virtual Guid? TenantId { get; protected set; } + public virtual Guid UserId { get; protected set; } + public virtual long NotificationId { get; protected set; } + public virtual ReadStatus ReadStatus { get; protected set; } + protected UserNotification() { } + public UserNotification(long notificationId, Guid userId) + { + UserId = userId; + NotificationId = notificationId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs new file mode 100644 index 000000000..13c264548 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.MessageService.Subscriptions +{ + public interface ISubscribeRepository : IBasicRepository + { + Task UserSubscribeExistsAysnc(string notificationName, Guid userId); + + Task GetUserSubscribeAsync(string notificationName, Guid userId); + + Task> GetUserSubscribesAsync(Guid userId); + + Task> GetUserSubscribesAsync(string notificationName); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs new file mode 100644 index 000000000..b3a7fef01 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.MessageService.Subscriptions +{ + public interface ISubscribeStore + { + Task> GetUserSubscribesAsync(string notificationName); + Task UserSubscribeAsync(string notificationName, Guid userId); + Task UserUnSubscribeAsync(string notificationName, Guid userId); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs new file mode 100644 index 000000000..23f052e20 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs @@ -0,0 +1,17 @@ +using System; +using Volo.Abp.Auditing; + +namespace LINGYUN.Abp.MessageService.Subscriptions +{ + public class RoleSubscribe : Subscribe, IHasCreationTime + { + public virtual string RoleName { get; set; } + public virtual DateTime CreationTime { get; set; } + protected RoleSubscribe() { } + public RoleSubscribe(string notificationName, string roleName) : base(notificationName) + { + RoleName = roleName; + CreationTime = DateTime.Now; + } + } +} 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 ad146fe15..2fdc1306d 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 @@ -1,13 +1,19 @@ using System; -using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; namespace LINGYUN.Abp.MessageService.Subscriptions { - public class Subscribe : CreationAuditedEntity, IMultiTenant + public abstract class Subscribe : Entity, IMultiTenant { public virtual Guid? TenantId { get; protected set; } - public virtual string EventType { get; protected set; } - public virtual string RoleName { get; protected set; } + public virtual string NotificationName { get; protected set; } + + protected Subscribe() { } + + protected Subscribe(string notificationName) + { + NotificationName = notificationName; + } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs new file mode 100644 index 000000000..ad3011801 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs @@ -0,0 +1,9 @@ +namespace LINGYUN.Abp.MessageService.Subscriptions +{ + public class SubscribeConsts + { + public const int MaxNotificationNameLength = 100; + + public const int MaxRoleNameLength = 64; + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs new file mode 100644 index 000000000..cefc653f6 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.MessageService.Subscriptions +{ + public class SubscribeStore : ISubscribeStore, ITransientDependency + { + protected ISubscribeRepository SubscribeRepository { get; } + + public SubscribeStore(ISubscribeRepository subscribeRepository) + { + SubscribeRepository = subscribeRepository; + } + + public virtual async Task> GetUserSubscribesAsync(string notificationName) + { + return await SubscribeRepository.GetUserSubscribesAsync(notificationName); + } + + public virtual async Task UserSubscribeAsync(string notificationName, Guid userId) + { + var userSubscribeExists = await SubscribeRepository.UserSubscribeExistsAysnc(notificationName, userId); + if (!userSubscribeExists) + { + var userSbuscribe = new UserSubscribe(notificationName, userId); + await SubscribeRepository.InsertAsync(userSbuscribe); + } + } + + public virtual async Task UserUnSubscribeAsync(string notificationName, Guid userId) + { + var userSubscribe = await SubscribeRepository.GetUserSubscribeAsync(notificationName, userId); + if (userSubscribe != null) + { + await SubscribeRepository.DeleteAsync(userSubscribe); + } + } + } +} 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 new file mode 100644 index 000000000..a3012dd17 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs @@ -0,0 +1,17 @@ +using System; +using Volo.Abp.Auditing; + +namespace LINGYUN.Abp.MessageService.Subscriptions +{ + public class UserSubscribe : Subscribe, IHasCreationTime + { + public virtual DateTime CreationTime { get; set; } + public virtual Guid UserId { get; set; } + protected UserSubscribe() { } + public UserSubscribe(string notificationName, Guid userId) : base(notificationName) + { + CreationTime = DateTime.Now; + UserId = userId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs new file mode 100644 index 000000000..22609c5e0 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.MessageService.Utils +{ + public interface ISnowflakeIdGenerator + { + long NextId(); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj index 2e4cdc23e..d014cb2da 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj @@ -7,6 +7,7 @@ + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/AbpMessageServiceSignalRModule.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/AbpMessageServiceSignalRModule.cs new file mode 100644 index 000000000..5f4372d1d --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/AbpMessageServiceSignalRModule.cs @@ -0,0 +1,11 @@ +using LINGYUN.Abp.IM.SignalR; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.MessageService.SignalR +{ + [DependsOn(typeof(AbpIMSignalRModule))] + public class AbpMessageServiceSignalRModule : AbpModule + { + + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/ChatMessaheHub.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/ChatMessaheHub.cs deleted file mode 100644 index 6f573bcda..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/ChatMessaheHub.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using LINGYUN.Abp.AspNetCore.SignalR; - -namespace LINGYUN.Abp.MessageService.SignalR -{ - public abstract class ChatMessaheHub : OnlineClientHubBase - { - - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Hubs/AbpMessageHub.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Hubs/AbpMessageHub.cs new file mode 100644 index 000000000..d4d01ec12 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Hubs/AbpMessageHub.cs @@ -0,0 +1,8 @@ +using LINGYUN.Abp.IM.SignalR; + +namespace LINGYUN.Abp.MessageService.SignalR.Hubs +{ + public class AbpMessageHub : OnlineClientHubBase + { + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs new file mode 100644 index 000000000..98da317ef --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs @@ -0,0 +1,60 @@ +using LINGYUN.Abp.IM; +using LINGYUN.Abp.MessageService.Notifications; +using LINGYUN.Abp.MessageService.SignalR.Hubs; +using LINGYUN.Abp.Notifications; +using Microsoft.AspNetCore.SignalR; +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.MessageService.SignalR.Notifications +{ + public class SignalRNotificationPublisher : INotificationPublisher, ITransientDependency + { + public ILogger Logger { protected get; set; } + + private readonly IOnlineClientManager _onlineClientManager; + + private readonly IHubContext _hubContext; + + public SignalRNotificationPublisher( + IOnlineClientManager onlineClientManager, + IHubContext hubContext) + { + _hubContext = hubContext; + _onlineClientManager = onlineClientManager; + + Logger = NullLogger.Instance; + } + + public async Task PublishAsync(NotificationData data, IEnumerable userIds, Guid? tenantId) + { + try + { + foreach(var userId in userIds) + { + var onlineClientContext = new OnlineClientContext(userId, tenantId); + var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); + foreach (var onlineClient in onlineClients) + { + 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; + } + await signalRClient.SendAsync("getNotification", data); + } + } + } + catch(Exception ex) + { + //Logger.LogWarning("Could not send notification to user: " + userId); + Logger.LogWarning(ex.ToString(), ex); + } + } + } +} diff --git a/vueJs/src/api/users.ts b/vueJs/src/api/users.ts index d57b913d3..70cf9e68f 100644 --- a/vueJs/src/api/users.ts +++ b/vueJs/src/api/users.ts @@ -80,9 +80,9 @@ export default class UserApiService { } public static userRegister(registerData: UserRegisterData) { - const _url = '/api/account/register' + const _url = '/api/account/phone/register' return ApiService.HttpRequest({ - baseURL: IdentityServerUrl, + baseURL: IdentityServiceUrl, url: _url, method: 'POST', data: registerData @@ -201,10 +201,14 @@ export class UsersGetPagedDto extends PagedAndSortedResultRequestDto { /** 用户注册对象 */ export class UserRegisterData { - /** 应用名称 */ - appName!: string + /** 手机号码 */ + phoneNumber!: string + /** 手机验证码 */ + verifyCode!: string + /** 名称 */ + name?: string /** 用户名 */ - userName!: string + userName?: string /** 密码 */ password!: string /** 邮件地址 */ diff --git a/vueJs/src/views/login/components/TenantSelect.vue b/vueJs/src/components/TenantBox/index.vue similarity index 100% rename from vueJs/src/views/login/components/TenantSelect.vue rename to vueJs/src/components/TenantBox/index.vue diff --git a/vueJs/src/permission.ts b/vueJs/src/permission.ts index e70bab3c7..317cd3a51 100644 --- a/vueJs/src/permission.ts +++ b/vueJs/src/permission.ts @@ -11,7 +11,7 @@ import settings from './settings' NProgress.configure({ showSpinner: false }) -const whiteList = ['/login', '/auth-redirect'] +const whiteList = ['/login', '/auth-redirect', '/register'] const getPageTitle = (key: string) => { const hasKey = i18n.te(`route.${key}`) diff --git a/vueJs/src/router/index.ts b/vueJs/src/router/index.ts index 38763a00f..da2763797 100644 --- a/vueJs/src/router/index.ts +++ b/vueJs/src/router/index.ts @@ -61,6 +61,11 @@ export const constantRoutes: RouteConfig[] = [ component: () => import(/* webpackChunkName: "login" */ '@/views/login/index.vue'), meta: { hidden: true } }, + { + path: '/register', + component: () => import(/* webpackChunkName: "login" */ '@/views/register/index.vue'), + meta: { hidden: true } + }, { path: '/auth-redirect', component: () => import(/* webpackChunkName: "auth-redirect" */ '@/views/login/auth-redirect.vue'), diff --git a/vueJs/src/views/admin/settings/components/GlobalSettingEditForm.vue b/vueJs/src/views/admin/settings/components/GlobalSettingEditForm.vue index 1adb06e79..96cbe86d1 100644 --- a/vueJs/src/views/admin/settings/components/GlobalSettingEditForm.vue +++ b/vueJs/src/views/admin/settings/components/GlobalSettingEditForm.vue @@ -1,7 +1,6 @@