Browse Source

Merge pull request #2 from colinin/notifications

增加用户欢迎通知
pull/21/head
cKey 6 years ago
committed by GitHub
parent
commit
f99d0c9f33
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj
  2. 25
      aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs
  3. 31
      aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs
  4. 18
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/AbpMessageServiceDomainSharedModule.cs
  5. 9
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/Notifications/UserNotificationNames.cs
  6. 28
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDomainModule.cs
  7. 31
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Distributed/UserCreateEventHandler.cs
  8. 13
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateJoinIMEventHandler.cs
  9. 116
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs
  10. 3
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json
  11. 3
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json
  12. 17
      vueJs/src/components/Notification/index.vue

2
aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj

@ -6,6 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNetCore.CAP.MySql" Version="3.0.3" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="3.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

25
aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs

@ -1,20 +1,19 @@
using IdentityModel;
using DotNetCore.CAP;
using IdentityModel;
using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.IM.SignalR;
using LINGYUN.Abp.MessageService.EntityFrameworkCore;
using LINGYUN.Abp.MessageService.MultiTenancy;
using LINGYUN.Abp.Notifications.SignalR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using System;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.MultiTenancy;
@ -41,10 +40,26 @@ namespace LINGYUN.Abp.MessageService
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpIMSignalRModule),
typeof(AbpNotificationsSignalRModule),
typeof(AbpCAPEventBusModule),
typeof(AbpAutofacModule)
)]
public class AbpMessageServiceHttpApiHostModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<CapOptions>(options =>
{
options
.UseMySql(configuration.GetConnectionString("Default"))
.UseRabbitMQ(rabbitMQOptions =>
{
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions);
});
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();

31
aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs

@ -5,7 +5,6 @@ using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.SignalR;
namespace LINGYUN.Abp.IM.SignalR.Hubs
{
@ -30,9 +29,27 @@ namespace LINGYUN.Abp.IM.SignalR.Hubs
// 持久化
await _messageStore.StoreMessageAsync(chatMessage);
try
{
if (!chatMessage.GroupId.IsNullOrWhiteSpace())
{
try
await SendMessageToGroupAsync(chatMessage);
}
else
{
await SendMessageToUserAsync(chatMessage);
}
}
catch (Exception ex)
{
Logger.LogWarning("Could not send message, group: {0}, formUser: {1}, toUser: {2}",
chatMessage.GroupId, chatMessage.FormUserName,
chatMessage.ToUserId.HasValue ? chatMessage.ToUserId.ToString() : "None");
Logger.LogWarning("Send group message error: {0}", ex.Message);
}
}
protected virtual async Task SendMessageToGroupAsync(ChatMessage chatMessage)
{
var signalRClient = Clients.Group(chatMessage.GroupId);
if (signalRClient == null)
@ -43,13 +60,8 @@ namespace LINGYUN.Abp.IM.SignalR.Hubs
await signalRClient.SendAsync("getChatMessage", chatMessage);
}
catch (Exception ex)
{
Logger.LogWarning("Could not send message to group: {0}", chatMessage.GroupId);
Logger.LogWarning("Send group message error: {0}", ex.Message);
}
}
else
protected virtual async Task SendMessageToUserAsync(ChatMessage chatMessage)
{
var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId.GetValueOrDefault());
var onlineClients = OnlineClientManager.GetAllByContext(onlineClientContext);
@ -74,4 +86,3 @@ namespace LINGYUN.Abp.IM.SignalR.Hubs
}
}
}
}

18
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/AbpMessageServiceDomainSharedModule.cs

@ -0,0 +1,18 @@
using LINGYUN.Abp.MessageService.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.MessageService
{
[DependsOn(typeof(AbpLocalizationModule))]
public class AbpMessageServiceDomainSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources.Add<MessageServiceResource>("en");
});
}
}
}

9
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/Volo/Abp/Users/Notifications/UserNotificationNames.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.Users.Notifications
{
public class UserNotificationNames
{
public const string GroupName = "Volo.Abp.Users";
public const string WelcomeToApplication = GroupName + ".WelcomeToApplication";
}
}

28
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDomainModule.cs

@ -1,10 +1,16 @@
using LINGYUN.Abp.MessageService.Mapper;
using LINGYUN.Abp.MessageService.Localization;
using LINGYUN.Abp.MessageService.Mapper;
using Volo.Abp.AutoMapper;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.MessageService
{
[DependsOn(typeof(AbpAutoMapperModule))]
[DependsOn(
typeof(AbpAutoMapperModule),
typeof(AbpMessageServiceDomainSharedModule))]
public class AbpMessageServiceDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@ -13,6 +19,24 @@ namespace LINGYUN.Abp.MessageService
{
options.AddProfile<MessageServiceDomainAutoMapperProfile>(validate: true);
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpMessageServiceDomainModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<MessageServiceResource>()
.AddVirtualJson("/LINGYUN/Abp/MessageService/Localization/Resources");
});
Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Messages:Group", typeof(MessageServiceResource));
options.MapCodeNamespace("Messages:User", typeof(MessageServiceResource));
});
}
}
}

31
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Distributed/UserCreateEventHandler.cs

@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Users;
namespace LINGYUN.Abp.MessageService.EventBus.Distributed
{
public class UserCreateEventHandler : IDistributedEventHandler<EntityCreatedEto<UserEto>>, ITransientDependency
{
private readonly ILocalEventBus _localEventBus;
public UserCreateEventHandler(
ILocalEventBus localEventBus)
{
_localEventBus = localEventBus;
}
/// <summary>
/// 接收添加用户事件,发布本地事件
/// </summary>
/// <param name="eventData"></param>
/// <returns></returns>
public async Task HandleEventAsync(EntityCreatedEto<UserEto> eventData)
{
var localUserCreateEventData = new EntityCreatedEventData<UserEto>(eventData.Entity);
await _localEventBus.PublishAsync(localUserCreateEventData);
}
}
}

13
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/UserCreateEventHandler.cs → aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateJoinIMEventHandler.cs

@ -1,19 +1,20 @@
using LINGYUN.Abp.MessageService.Messages;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities.Events.Distributed;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
using Volo.Abp.Users;
namespace LINGYUN.Abp.MessageService.EventBus
namespace LINGYUN.Abp.MessageService.EventBus.Distributed
{
public class UserCreateEventHandler : IDistributedEventHandler<EntityCreatedEto<UserEto>>
public class UserCreateJoinIMEventHandler : ILocalEventHandler<EntityCreatedEventData<UserEto>>, ITransientDependency
{
private readonly ICurrentTenant _currentTenant;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IUserChatSettingRepository _userChatSettingRepository;
public UserCreateEventHandler(
public UserCreateJoinIMEventHandler(
ICurrentTenant currentTenant,
IUnitOfWorkManager unitOfWorkManager,
IUserChatSettingRepository userChatSettingRepository)
@ -27,7 +28,7 @@ namespace LINGYUN.Abp.MessageService.EventBus
/// </summary>
/// <param name="eventData"></param>
/// <returns></returns>
public async Task HandleEventAsync(EntityCreatedEto<UserEto> eventData)
public async Task HandleEventAsync(EntityCreatedEventData<UserEto> eventData)
{
using (var unitOfWork = _unitOfWorkManager.Begin())
{

116
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs

@ -0,0 +1,116 @@
using LINGYUN.Abp.MessageService.Localization;
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.Localization;
using System;
using System.Globalization;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.Localization;
using Volo.Abp.Settings;
using Volo.Abp.Users;
using Volo.Abp.Users.Notifications;
namespace LINGYUN.Abp.MessageService.EventBus
{
public class UserCreateSendWelcomeEventHandler : ILocalEventHandler<EntityCreatedEventData<UserEto>>, ITransientDependency
{
private readonly ISettingProvider _settingProvider;
private readonly IStringLocalizer _stringLocalizer;
private readonly INotificationStore _notificationStore;
private readonly INotificationDispatcher _notificationDispatcher;
// 需要模拟用户令牌
// 是否有必要
// private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
public UserCreateSendWelcomeEventHandler(
ISettingProvider settingProvider,
INotificationStore notificationStore,
INotificationDispatcher notificationDispatcher,
IStringLocalizer<MessageServiceResource> stringLocalizer
//ICurrentPrincipalAccessor currentPrincipalAccessor
)
{
_settingProvider = settingProvider;
_stringLocalizer = stringLocalizer;
_notificationStore = notificationStore;
_notificationDispatcher = notificationDispatcher;
//_currentPrincipalAccessor = currentPrincipalAccessor;
}
public async Task HandleEventAsync(EntityCreatedEventData<UserEto> eventData)
{
// 获取默认语言
var userDefaultCultureName = await _settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage);
if (!userDefaultCultureName.IsNullOrWhiteSpace())
{
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(userDefaultCultureName);
// CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(userDefaultCultureName);
}
// 订阅用户欢迎消息
await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId,
eventData.Entity.Id, UserNotificationNames.WelcomeToApplication);
var userWelcomeNotifiction = new NotificationInfo
{
CreationTime = DateTime.Now,
Name = UserNotificationNames.WelcomeToApplication,
NotificationSeverity = NotificationSeverity.Info,
NotificationType = NotificationType.System,
TenantId = eventData.Entity.TenantId
};
userWelcomeNotifiction.Data.Properties["message"] = L("WelcomeToApplicationFormUser", eventData.Entity.UserName);
await _notificationDispatcher.DispatcheAsync(userWelcomeNotifiction);
}
//public async Task HandleEventAsync(EntityCreatedEventData<UserEto> eventData)
//{
// // 模拟用户令牌
// var mockUserPrincipal = new ClaimsPrincipal();
// var mockUserIdentity = new ClaimsIdentity();
// mockUserIdentity.AddClaim(new Claim(AbpClaimTypes.UserId, eventData.Entity.Id.ToString()));
// mockUserIdentity.AddClaim(new Claim(AbpClaimTypes.UserName, eventData.Entity.UserName));
// mockUserIdentity.AddClaim(new Claim(AbpClaimTypes.Email, eventData.Entity.Email));
// mockUserIdentity.AddClaim(new Claim(AbpClaimTypes.PhoneNumber, eventData.Entity.PhoneNumber));
// if (eventData.Entity.TenantId.HasValue)
// {
// mockUserIdentity.AddClaim(new Claim(AbpClaimTypes.TenantId, eventData.Entity.TenantId.ToString()));
// }
// mockUserPrincipal.AddIdentity(mockUserIdentity);
// using (_currentPrincipalAccessor.Change(mockUserPrincipal))
// {
// // 获取默认语言
// // TODO: 是否采用系统默认语言而不是用户默认语言?
// var userDefaultCultureName = await _settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage);
// if (!userDefaultCultureName.IsNullOrWhiteSpace())
// {
// CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo(userDefaultCultureName);
// }
// // 订阅用户欢迎消息
// await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId,
// eventData.Entity.Id, UserNotificationNames.WelcomeToApplication);
// var userWelcomeNotifiction = new NotificationInfo
// {
// CreationTime = DateTime.Now,
// Name = UserNotificationNames.WelcomeToApplication,
// NotificationSeverity = NotificationSeverity.Info,
// NotificationType = NotificationType.System,
// TenantId = eventData.Entity.TenantId
// };
// userWelcomeNotifiction.Data.Properties["message"] = L("WelcomeToApplicationFormUser", eventData.Entity.UserName);
// await _notificationDispatcher.DispatcheAsync(userWelcomeNotifiction);
// }
//}
protected string L(string name, params object[] args)
{
return _stringLocalizer[name, args]?.Value;
}
}
}

3
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json

@ -6,6 +6,7 @@
"Messages:Group:1003": "The administrator has banned you from speaking!",
"Messages:User:1001": "Users do not receive anonymous comments!",
"Messages:User:1002": "The user has rejected all messages!",
"Messages:User:1003": "The user rejects the message you sent!"
"Messages:User:1003": "The user rejects the message you sent!",
"WelcomeToApplicationFormUser": "User :{0} welcome to join us!"
}
}

3
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json

@ -6,6 +6,7 @@
"Messages:Group:1003": "管理员已禁止您发言!",
"Messages:User:1001": "用户不接收匿名发言!",
"Messages:User:1002": "用户已拒接所有消息!",
"Messages:User:1003": "用户拒绝您发送的消息!"
"Messages:User:1003": "用户拒绝您发送的消息!",
"WelcomeToApplicationFormUser": "用户:{0} 欢迎您的加入!"
}
}

17
vueJs/src/components/Notification/index.vue

@ -134,8 +134,12 @@ export default class extends Vue {
this.connection.invoke('GetNotification', ReadState.UnRead, 10).then(result => {
console.log(result)
result.items.forEach((notify: any) => {
const notification = notify.data.properties
notification.id = notify.id
const notification = new Notification()
notification.id = notify.data.properties.id
notification.title = notify.data.properties.title
notification.message = notify.data.properties.message
notification.datetime = notify.creationTime
notification.severity = notify.notificationSeverity
this.notifications.push(notification)
})
})
@ -153,12 +157,17 @@ export default class extends Vue {
private onNotificationReceived(data: any) {
console.log('received signalr message...')
console.log(data)
const notification = data.data.properties
const notification = new Notification()
notification.id = data.properties.id
notification.title = data.properties.title
notification.message = data.properties.message
notification.datetime = data.creationTime
notification.severity = data.notificationSeverity
this.pushUserNotification(notification)
this.$notify({
title: notification.title,
message: notification.message,
type: this.getNofiyType(data.notificationSeverity)
type: this.getNofiyType(notification.severity)
})
}

Loading…
Cancel
Save