Browse Source

feat: 增加模板通知接口

pull/604/head
cKey 4 years ago
parent
commit
46e98ae74b
  1. 11
      aspnet-core/LINGYUN.MicroService.All.sln
  2. 2
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/Notifications/AbpNotificationsExceptionSubscriber.cs
  3. 2
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.Emailing/LINGYUN/Abp/Notifications/Emailing/EmailingNotificationPublishProvider.cs
  4. 15
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs
  5. 9
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.Sms/LINGYUN/Abp/Notifications/Sms/SmsNotificationPublishProvider.cs
  6. 2
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.Sms/LINGYUN/Abp/Notifications/Sms/SmsNotificationSender.cs
  7. 3
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/FodyWeavers.xml
  8. 19
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/LINGYUN.Abp.Notifications.TextTemplating.csproj
  9. 12
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/LINGYUN/Abp/Notifications/TextTemplating/AbpNotificationsTextTemplatingModule.cs
  10. 16
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/LINGYUN/Abp/Notifications/TextTemplating/NotificationTemplateContentContributor.cs
  11. 28
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs
  12. 66
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSenderExtensions.cs
  13. 7
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs
  14. 9
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationTemplateStore.cs
  15. 47
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSender.cs
  16. 1
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs
  17. 35
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs
  18. 53
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationTemplate.cs
  19. 12
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NullNotificationStore.cs
  20. 16
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NullNotificationTemplateStore.cs
  21. 10
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json
  22. 10
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json
  23. 12
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application.Contracts/LINGYUN/Abp/MessageService/Notifications/Dto/NotificationMarkReadStateInput.cs
  24. 16
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application.Contracts/LINGYUN/Abp/MessageService/Notifications/Dto/UserNotificationDto.cs
  25. 7
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application.Contracts/LINGYUN/Abp/MessageService/Notifications/IMyNotificationAppService.cs
  26. 28
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application/LINGYUN/Abp/MessageService/AbpMessageServiceApplicationAutoMapperProfile.cs
  27. 11
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application/LINGYUN/Abp/MessageService/AbpMessageServiceApplicationModule.cs
  28. 40
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application/LINGYUN/Abp/MessageService/Notifications/MyNotificationAppService.cs
  29. 12
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/en.json
  30. 13
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json
  31. 10
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs
  32. 13
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs
  33. 27
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs
  34. 11
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationTemplate.cs
  35. 18
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotificationInfo.cs
  36. 103
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs
  37. 18
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN/Abp/MessageService/Notifications/MyNotificationController.cs
  38. 1
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json
  39. 1
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json
  40. 3
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json
  41. 3
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json
  42. 2
      aspnet-core/modules/wechat/LINGYUN.Abp.Notifications.WeChat.MiniProgram/LINGYUN/Abp/Notifications/WeChat/MiniProgram/WeChatMiniProgramNotificationPublishProvider.cs
  43. 32
      aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/BackgroundJobs/NotificationPublishJob.cs
  44. 84
      aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs

11
aspnet-core/LINGYUN.MicroService.All.sln

@ -404,9 +404,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.Organi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications.Emailing", "modules\common\LINGYUN.Abp.Notifications.Emailing\LINGYUN.Abp.Notifications.Emailing.csproj", "{88502844-D83C-4541-96AC-A8291E261F63}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Platform.Theme.VueVbenAdmin", "modules\platform\LINGYUN.Platform.Theme.VueVbenAdmin\LINGYUN.Platform.Theme.VueVbenAdmin.csproj", "{67DC7FA0-506A-4977-95F6-BC739B2BC4BA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Platform.Theme.VueVbenAdmin", "modules\platform\LINGYUN.Platform.Theme.VueVbenAdmin\LINGYUN.Platform.Theme.VueVbenAdmin.csproj", "{67DC7FA0-506A-4977-95F6-BC739B2BC4BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Platform.Settings.VueVbenAdmin", "modules\platform\LINGYUN.Platform.Settings.VueVbenAdmin\LINGYUN.Platform.Settings.VueVbenAdmin.csproj", "{8DF55DAB-4C1D-46F7-9324-0050F47B3BED}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Platform.Settings.VueVbenAdmin", "modules\platform\LINGYUN.Platform.Settings.VueVbenAdmin\LINGYUN.Platform.Settings.VueVbenAdmin.csproj", "{8DF55DAB-4C1D-46F7-9324-0050F47B3BED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Notifications.TextTemplating", "modules\common\LINGYUN.Abp.Notifications.TextTemplating\LINGYUN.Abp.Notifications.TextTemplating.csproj", "{06FF5EFA-DEDA-4E12-A482-8FCE4077F68A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -1054,6 +1056,10 @@ Global
{8DF55DAB-4C1D-46F7-9324-0050F47B3BED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DF55DAB-4C1D-46F7-9324-0050F47B3BED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DF55DAB-4C1D-46F7-9324-0050F47B3BED}.Release|Any CPU.Build.0 = Release|Any CPU
{06FF5EFA-DEDA-4E12-A482-8FCE4077F68A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06FF5EFA-DEDA-4E12-A482-8FCE4077F68A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06FF5EFA-DEDA-4E12-A482-8FCE4077F68A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06FF5EFA-DEDA-4E12-A482-8FCE4077F68A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1253,6 +1259,7 @@ Global
{88502844-D83C-4541-96AC-A8291E261F63} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E}
{67DC7FA0-506A-4977-95F6-BC739B2BC4BA} = {F4923692-D343-4318-AECA-96F580B1A563}
{8DF55DAB-4C1D-46F7-9324-0050F47B3BED} = {F4923692-D343-4318-AECA-96F580B1A563}
{06FF5EFA-DEDA-4E12-A482-8FCE4077F68A} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718}

2
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/Notifications/AbpNotificationsExceptionSubscriber.cs

@ -38,7 +38,7 @@ namespace LINGYUN.Abp.ExceptionHandling.Notifications
await notificationSender.SendNofiterAsync(
AbpExceptionHandlingNotificationNames.NotificationName,
notificationData,
null,
user: null,
CurrentTenant.Id,
NotificationSeverity.Error);
}

2
aspnet-core/modules/common/LINGYUN.Abp.Notifications.Emailing/LINGYUN/Abp/Notifications/Emailing/EmailingNotificationPublishProvider.cs

@ -28,13 +28,11 @@ public class EmailingNotificationPublishProvider : NotificationPublishProvider
protected INotificationDefinitionManager NotificationDefinitionManager { get; }
public EmailingNotificationPublishProvider(
IServiceProvider serviceProvider,
IEmailSender emailSender,
ITemplateRenderer templateRenderer,
IStringLocalizerFactory localizerFactory,
IIdentityUserRepository userRepository,
INotificationDefinitionManager notificationDefinitionManager)
: base(serviceProvider)
{
EmailSender = emailSender;
TemplateRenderer = templateRenderer;

15
aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs

@ -7,7 +7,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications.SignalR
{
public class SignalRNotificationPublishProvider : NotificationPublishProvider
@ -19,16 +19,17 @@ namespace LINGYUN.Abp.Notifications.SignalR
private readonly AbpNotificationsSignalROptions _options;
public SignalRNotificationPublishProvider(
IHubContext<NotificationsHub> hubContext,
IOptions<AbpNotificationsSignalROptions> options,
IServiceProvider serviceProvider)
: base(serviceProvider)
IHubContext<NotificationsHub> hubContext,
IOptions<AbpNotificationsSignalROptions> options)
{
_options = options.Value;
_hubContext = hubContext;
}
protected override async Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers, CancellationToken cancellationToken = default)
protected async override Task PublishAsync(
NotificationInfo notification,
IEnumerable<UserIdentifier> identifiers,
CancellationToken cancellationToken = default)
{
if (identifiers?.Count() == 0)
{
@ -53,6 +54,6 @@ namespace LINGYUN.Abp.Notifications.SignalR
Logger.LogWarning("Send to user notifications error: {0}", ex.Message);
}
}
}
}
}
}

9
aspnet-core/modules/common/LINGYUN.Abp.Notifications.Sms/LINGYUN/Abp/Notifications/Sms/SmsNotificationPublishProvider.cs

@ -1,5 +1,4 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -11,18 +10,14 @@ namespace LINGYUN.Abp.Notifications.Sms
{
public const string ProviderName = NotificationProviderNames.Sms;
private IUserPhoneFinder _userPhoneFinder;
protected IUserPhoneFinder UserPhoneFinder => LazyGetRequiredService(ref _userPhoneFinder);
protected IUserPhoneFinder UserPhoneFinder => ServiceProvider.LazyGetRequiredService<IUserPhoneFinder>();
protected ISmsNotificationSender Sender { get; }
protected AbpNotificationsSmsOptions Options { get; }
public SmsNotificationPublishProvider(
IServiceProvider serviceProvider,
ISmsNotificationSender sender,
IOptions<AbpNotificationsSmsOptions> options)
: base(serviceProvider)
{
Sender = sender;
Options = options.Value;
@ -46,6 +41,6 @@ namespace LINGYUN.Abp.Notifications.Sms
return;
}
await Sender.SendAsync(notification, sendToPhones.JoinAsString(","));
}
}
}
}

2
aspnet-core/modules/common/LINGYUN.Abp.Notifications.Sms/LINGYUN/Abp/Notifications/Sms/SmsNotificationSender.cs

@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Sms;
@ -40,6 +41,7 @@ namespace LINGYUN.Abp.Notifications.Sms
// TODO: 后期增强功能,增加短信模板、通知模板功能
message.Properties.Add("TemplateCode", templateCode);
message.Properties.Add("SignName", notification.Data.TryGetData("SignName"));
message.Properties.AddIfNotContains(notification.Data.ExtraProperties);
await SmsSender.SendAsync(message);
}

3
aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

19
aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/LINGYUN.Abp.Notifications.TextTemplating.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.TextTemplating.Core" Version="$(VoloAbpPackageVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" />
</ItemGroup>
</Project>

12
aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/LINGYUN/Abp/Notifications/TextTemplating/AbpNotificationsTextTemplatingModule.cs

@ -0,0 +1,12 @@
using Volo.Abp.Modularity;
using Volo.Abp.TextTemplating;
namespace LINGYUN.Abp.Notifications.TextTemplating;
[DependsOn(
typeof(AbpNotificationModule),
typeof(AbpTextTemplatingCoreModule))]
public class AbpNotificationsTextTemplatingModule : AbpModule
{
}

16
aspnet-core/modules/common/LINGYUN.Abp.Notifications.TextTemplating/LINGYUN/Abp/Notifications/TextTemplating/NotificationTemplateContentContributor.cs

@ -0,0 +1,16 @@
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.TextTemplating;
namespace LINGYUN.Abp.Notifications.TextTemplating;
public class NotificationTemplateContentContributor : ITemplateContentContributor, ITransientDependency
{
public async virtual Task<string> GetOrNullAsync(TemplateContentContributorContext context)
{
var store = context.ServiceProvider.GetRequiredService<INotificationTemplateStore>();
return await store.GetOrNullAsync(context.TemplateDefinition.Name, context.Culture);
}
}

28
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs

@ -14,28 +14,28 @@ namespace LINGYUN.Abp.Notifications
/// </summary>
/// <param name="name">名称</param>
/// <param name="data">数据</param>
/// <param name="userId">用户,为空标识发给所有订阅用户</param>
/// <param name="users">用户列表,为空标识发给所有订阅用户</param>
/// <param name="tenantId">租户</param>
/// <param name="severity">严重级别</param>
/// <returns>通知标识</returns>
Task<string> SendNofiterAsync(
string name,
NotificationData data,
UserIdentifier user = null,
IEnumerable<UserIdentifier> users = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info);
/// <summary>
/// 发送通知
/// </summary>
/// <param name="name">名称</param>
/// <param name="data">数据</param>
/// <param name="users">用户列表,为空标识发给所有订阅用户</param>
/// <param name="tenantId">租户</param>
/// <param name="severity">严重级别</param>
/// <returns>通知标识</returns>
Task<string> SendNofitersAsync(
string name,
NotificationData data,
/// <summary>
/// 发送模板通知
/// </summary>
/// <param name="name">名称</param>
/// <param name="template">模板对象</param>
/// <param name="users">用户列表,为空标识发给所有订阅用户</param>
/// <param name="tenantId">租户</param>
/// <param name="severity">严重级别</param>
/// <returns></returns>
Task<string> SendNofiterAsync(
string name,
NotificationTemplate template,
IEnumerable<UserIdentifier> users = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info);

66
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSenderExtensions.cs

@ -0,0 +1,66 @@
using JetBrains.Annotations;
using System;
using System.Threading.Tasks;
using Volo.Abp;
namespace LINGYUN.Abp.Notifications;
public static class INotificationSenderExtensions
{
/// <summary>
/// 发送通知
/// </summary>
/// <param name="sender">发送接口</param>
/// <param name="name">名称</param>
/// <param name="data">数据</param>
/// <param name="user">用户,为空标识发给所有订阅用户</param>
/// <param name="tenantId">租户</param>
/// <param name="severity">严重级别</param>
/// <returns>通知标识</returns>
public async static Task<string> SendNofiterAsync(
[NotNull] this INotificationSender sender,
[NotNull] string name,
[NotNull] NotificationData data,
UserIdentifier user = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info)
{
Check.NotNull(sender, nameof(sender));
Check.NotNullOrWhiteSpace(name, nameof(name));
Check.NotNull(data, nameof(data));
if (user == null)
{
return await sender.SendNofiterAsync(name, data, tenantId: tenantId, severity: severity);
}
return await sender.SendNofiterAsync(name, data, new[] { user },tenantId: tenantId, severity: severity);
}
/// <summary>
/// 发送模板通知
/// </summary>
/// <param name="sender">发送接口</param>
/// <param name="name">名称</param>
/// <param name="template">模板对象</param>
/// <param name="user">用户,为空发给所有订阅用户</param>
/// <param name="tenantId">租户</param>
/// <param name="severity">严重级别</param>
/// <returns>通知标识</returns>
public async static Task<string> SendNofiterAsync(
[NotNull] this INotificationSender sender,
[NotNull] string name,
[NotNull] NotificationTemplate template,
UserIdentifier user = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info)
{
Check.NotNull(sender, nameof(sender));
Check.NotNullOrWhiteSpace(name, nameof(name));
Check.NotNull(template, nameof(template));
if (user == null)
{
return await sender.SendNofiterAsync(name, template, tenantId: tenantId, severity: severity);
}
return await sender.SendNofiterAsync(name, template, new[] { user }, tenantId: tenantId, severity: severity);
}
}

7
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs

@ -121,5 +121,12 @@ namespace LINGYUN.Abp.Notifications
long notificationId,
NotificationReadState readState,
CancellationToken cancellationToken = default);
Task ChangeUserNotificationsReadStateAsync(
Guid? tenantId,
Guid userId,
IEnumerable<long> notificationIds,
NotificationReadState readState,
CancellationToken cancellationToken = default);
}
}

9
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationTemplateStore.cs

@ -0,0 +1,9 @@
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications;
public interface INotificationTemplateStore
{
Task<string> GetOrNullAsync(string templateName, string culture = null, CancellationToken cancellationToken = default);
}

47
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/NotificationSender.cs

@ -1,5 +1,4 @@
using LINGYUN.Abp.IdGenerator;
using LINGYUN.Abp.RealTime;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@ -50,25 +49,7 @@ namespace LINGYUN.Abp.Notifications
Logger = NullLogger<NotificationSender>.Instance;
}
public async Task<string> SendNofiterAsync(
string name,
NotificationData data,
UserIdentifier user = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info)
{
if (user == null)
{
return await PublishNofiterAsync(name, data, null, tenantId, severity);
}
else
{
return await PublishNofiterAsync(name, data, new List<UserIdentifier> { user }, tenantId, severity);
}
}
public async Task<string> SendNofitersAsync(
public async virtual Task<string> SendNofiterAsync(
string name,
NotificationData data,
IEnumerable<UserIdentifier> users = null,
@ -76,16 +57,26 @@ namespace LINGYUN.Abp.Notifications
NotificationSeverity severity = NotificationSeverity.Info)
{
return await PublishNofiterAsync(name, data, users, tenantId, severity);
}
protected async Task<string> PublishNofiterAsync(
string name,
NotificationData data,
}
public async virtual Task<string> SendNofiterAsync(
string name,
NotificationTemplate template,
IEnumerable<UserIdentifier> users = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info)
{
return await PublishNofiterAsync(name, template, users, tenantId, severity);
}
protected async virtual Task<string> PublishNofiterAsync<TData>(
string name,
TData data,
IEnumerable<UserIdentifier> users = null,
Guid? tenantId = null,
NotificationSeverity severity = NotificationSeverity.Info)
{
var eto = new NotificationEto<NotificationData>(data)
{
var eto = new NotificationEto<TData>(data)
{
Id = DistributedIdGenerator.Create(),
TenantId = tenantId,
@ -108,6 +99,6 @@ namespace LINGYUN.Abp.Notifications
}
return eto.Id.ToString();
}
}
}
}

1
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs

@ -49,7 +49,6 @@ namespace LINGYUN.Abp.Notifications
/// 通知提供者
/// </summary>
public List<string> Providers { get; }
/// <summary>
/// 额外属性
/// </summary>

35
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs

@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
@ -14,40 +13,14 @@ namespace LINGYUN.Abp.Notifications
{
public abstract string Name { get; }
protected IServiceProvider ServiceProvider { get; }
public IAbpLazyServiceProvider ServiceProvider { protected get; set; }
protected readonly object ServiceProviderLock = new object();
public ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory);
private ILoggerFactory _loggerFactory;
public ILoggerFactory LoggerFactory => ServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected ILogger Logger => _lazyLogger.Value;
private Lazy<ILogger> _lazyLogger => new Lazy<ILogger>(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true);
protected TService LazyGetRequiredService<TService>(ref TService reference)
{
if (reference == null)
{
lock (ServiceProviderLock)
{
if (reference == null)
{
reference = ServiceProvider.GetRequiredService<TService>();
}
}
}
return reference;
}
public ICancellationTokenProvider CancellationTokenProvider { get; set; }
protected NotificationPublishProvider(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
CancellationTokenProvider = NullCancellationTokenProvider.Instance;
}
public ICancellationTokenProvider CancellationTokenProvider => ServiceProvider.LazyGetService<ICancellationTokenProvider>(NullCancellationTokenProvider.Instance);
public async Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers)
{

53
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationTemplate.cs

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.EventBus;
namespace LINGYUN.Abp.Notifications;
/// <summary>
/// 通知模板消息
/// </summary>
[Serializable]
[EventName("notifications.template")]
public class NotificationTemplate : IHasExtraProperties
{
public string Name { get; set; }
public string Title { get; set; }
public string Culture { get; set; }
public string FormUser { get; set; }
public object this[string key]
{
get {
return this.GetProperty(key);
}
set {
this.SetProperty(key, value);
}
}
public ExtraPropertyDictionary ExtraProperties { get; set; }
public NotificationTemplate(
string name,
string title,
string culture = null,
string formUser = null,
IDictionary<string, object> data = null)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
Title = title;
Culture = culture;
FormUser = formUser;
if (data != null)
{
ExtraProperties = new ExtraPropertyDictionary(data);
}
else
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
}
}

12
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NullNotificationStore.cs

@ -9,6 +9,8 @@ namespace LINGYUN.Abp.Notifications
[Dependency(TryRegister = true)]
public class NullNotificationStore : INotificationStore, ISingletonDependency
{
public readonly static INotificationStore Instance = new NullNotificationStore();
public Task ChangeUserNotificationReadStateAsync(
Guid? tenantId,
Guid userId,
@ -19,6 +21,16 @@ namespace LINGYUN.Abp.Notifications
return Task.CompletedTask;
}
public Task ChangeUserNotificationsReadStateAsync(
Guid? tenantId,
Guid userId,
IEnumerable<long> notificationIds,
NotificationReadState readState,
CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public Task DeleteAllUserSubscriptionAsync(
Guid? tenantId,
string notificationName,

16
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NullNotificationTemplateStore.cs

@ -0,0 +1,16 @@
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Notifications;
[Dependency(TryRegister = true)]
public class NullNotificationTemplateStore : INotificationTemplateStore, ISingletonDependency
{
public readonly static INotificationTemplateStore Instance = new NullNotificationTemplateStore();
public Task<string> GetOrNullAsync(string templateName, string culture = null, CancellationToken cancellationToken = default)
{
return Task.FromResult<string>(null);
}
}

10
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/en.json

@ -59,6 +59,14 @@
"DisplayName:SmsVerifyCode": "SMS verification code",
"DisplayName:EmailVerifyCode": "Mail verification code",
"DisplayName:WeChatCode": "Wechat login code",
"SendRepeatSmsVerifyCode": "Phone verification code cannot be sent repeatedly within {0} minutes!"
"SendRepeatSmsVerifyCode": "Phone verification code cannot be sent repeatedly within {0} minutes!",
"LockTime": "Lock Time",
"LockType": "Lock Type",
"Confirmed": "Confirmed",
"UnConfirmed": "UnConfirmed",
"UnActived": "UnActived",
"LockoutEnd": "Lockout End",
"Public": "Public",
"Static": "Static"
}
}

10
aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/Localization/zh-Hans.json

@ -59,6 +59,14 @@
"DisplayName:SmsVerifyCode": "短信验证码",
"DisplayName:EmailVerifyCode": "邮件验证码",
"DisplayName:WeChatCode": "微信登录凭证",
"SendRepeatSmsVerifyCode": "手机验证码不能在 {0} 分钟内重复发送!"
"SendRepeatSmsVerifyCode": "手机验证码不能在 {0} 分钟内重复发送!",
"LockTime": "锁定时间",
"LockType": "锁定类型",
"Confirmed": "已确认",
"UnConfirmed": "未确认",
"UnActived": "未启用",
"LockoutEnd": "锁定截止期",
"Public": "公用",
"Static": "内置"
}
}

12
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application.Contracts/LINGYUN/Abp/MessageService/Notifications/Dto/NotificationMarkReadStateInput.cs

@ -0,0 +1,12 @@
using LINGYUN.Abp.Notifications;
using System.ComponentModel.DataAnnotations;
namespace LINGYUN.Abp.MessageService.Notifications;
public class NotificationMarkReadStateInput
{
[Required]
public long[] IdList { get; set; }
public NotificationReadState State { get; set; }
}

16
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application.Contracts/LINGYUN/Abp/MessageService/Notifications/Dto/UserNotificationDto.cs

@ -0,0 +1,16 @@
using LINGYUN.Abp.Notifications;
using System;
namespace LINGYUN.Abp.MessageService.Notifications;
public class UserNotificationDto
{
public string Name { get; set; }
public string Id { get; set; }
public NotificationData Data { get; set; }
public DateTime CreationTime { get; set; }
public NotificationLifetime Lifetime { get; set; }
public NotificationType Type { get; set; }
public NotificationSeverity Severity { get; set; }
public NotificationReadState State { get; set; }
}

7
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application.Contracts/LINGYUN/Abp/MessageService/Notifications/IMyNotificationAppService.cs

@ -1,5 +1,4 @@
using LINGYUN.Abp.Notifications;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
@ -8,12 +7,14 @@ namespace LINGYUN.Abp.MessageService.Notifications
public interface IMyNotificationAppService :
IReadOnlyAppService<
NotificationInfo,
UserNotificationDto,
long,
UserNotificationGetByPagedDto
>,
IDeleteAppService<long>
{
Task MarkReadStateAsync(NotificationMarkReadStateInput input);
Task<ListResultDto<NotificationGroupDto>> GetAssignableNotifiersAsync();
}
}

28
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application/LINGYUN/Abp/MessageService/AbpMessageServiceApplicationAutoMapperProfile.cs

@ -0,0 +1,28 @@
using AutoMapper;
using LINGYUN.Abp.MessageService.Notifications;
using LINGYUN.Abp.Notifications;
using System;
namespace LINGYUN.Abp.MessageService
{
public class AbpMessageServiceApplicationAutoMapperProfile : Profile
{
public AbpMessageServiceApplicationAutoMapperProfile()
{
CreateMap<UserNotificationInfo, UserNotificationDto>()
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.Id.ToString()))
.ForMember(dto => dto.Lifetime, map => map.Ignore())
.ForMember(dto => dto.Data, map => map.MapFrom((src, nfi) =>
{
var dataType = Type.GetType(src.NotificationTypeName);
var data = Activator.CreateInstance(dataType);
if (data is NotificationData notificationData)
{
notificationData.ExtraProperties = src.ExtraProperties;
return notificationData;
}
return new NotificationData();
}));
}
}
}

11
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application/LINGYUN/Abp/MessageService/AbpMessageServiceApplicationModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Modularity;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.MessageService
{
@ -7,6 +8,12 @@ namespace LINGYUN.Abp.MessageService
typeof(AbpMessageServiceDomainModule))]
public class AbpMessageServiceApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpMessageServiceApplicationAutoMapperProfile>(validate: true);
});
}
}
}

40
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Application/LINGYUN/Abp/MessageService/Notifications/MyNotificationAppService.cs

@ -15,19 +15,23 @@ namespace LINGYUN.Abp.MessageService.Notifications
protected INotificationStore NotificationStore { get; }
protected IUserNotificationRepository UserNotificationRepository { get; }
protected INotificationDefinitionManager NotificationDefinitionManager { get; }
public MyNotificationAppService(
INotificationStore notificationStore,
INotificationSender notificationSender,
IUserNotificationRepository userNotificationRepository,
INotificationDefinitionManager notificationDefinitionManager)
{
NotificationStore = notificationStore;
NotificationSender = notificationSender;
UserNotificationRepository = userNotificationRepository;
NotificationDefinitionManager = notificationDefinitionManager;
}
public virtual async Task SendNofiterAsync(NotificationSendDto input)
public async virtual Task SendNofiterAsync(NotificationSendDto input)
{
UserIdentifier user = null;
if (input.ToUserId.HasValue)
@ -43,7 +47,16 @@ namespace LINGYUN.Abp.MessageService.Notifications
input.Severity);
}
public virtual async Task DeleteAsync(long id)
public async virtual Task MarkReadStateAsync(NotificationMarkReadStateInput input)
{
await NotificationStore.ChangeUserNotificationsReadStateAsync(
CurrentTenant.Id,
CurrentUser.GetId(),
input.IdList,
input.State);
}
public async virtual Task DeleteAsync(long id)
{
await NotificationStore
.DeleteUserNotificationAsync(
@ -94,28 +107,29 @@ namespace LINGYUN.Abp.MessageService.Notifications
return Task.FromResult(new ListResultDto<NotificationGroupDto>(groups));
}
public virtual async Task<NotificationInfo> GetAsync(long id)
public async virtual Task<UserNotificationDto> GetAsync(long id)
{
return await NotificationStore
.GetNotificationOrNullAsync(CurrentTenant.Id, id);
var notification = await UserNotificationRepository.GetByIdAsync(CurrentUser.GetId(), id);
return ObjectMapper.Map<UserNotificationInfo, UserNotificationDto>(notification);
}
public virtual async Task<PagedResultDto<NotificationInfo>> GetListAsync(UserNotificationGetByPagedDto input)
public async virtual Task<PagedResultDto<UserNotificationDto>> GetListAsync(UserNotificationGetByPagedDto input)
{
var notificationCount = await NotificationStore
.GetUserNotificationsCountAsync(
CurrentTenant.Id,
var totalCount = await UserNotificationRepository
.GetCountAsync(
CurrentUser.GetId(),
input.Filter,
input.ReadState);
var notifications = await NotificationStore
.GetUserNotificationsAsync(
CurrentTenant.Id, CurrentUser.GetId(),
var notifications = await UserNotificationRepository
.GetListAsync(
CurrentUser.GetId(),
input.Filter, input.Sorting,
input.ReadState, input.SkipCount, input.MaxResultCount);
return new PagedResultDto<NotificationInfo>(notificationCount, notifications);
return new PagedResultDto<UserNotificationDto>(totalCount,
ObjectMapper.Map<List<UserNotificationInfo>, List<UserNotificationDto>>(notifications));
}
}
}

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

@ -18,6 +18,18 @@
"LINGYUN.Abp.Message:03404": "Sending the message failed: the user does not exist or is deactivated!",
"LINGYUN.Abp.Message:03410": "Users refuse to add friends",
"LINGYUN.Abp.Message:03411": "The other party is already your friend or has sent an authentication request. The operation cannot be repeated!",
"MarkSelectedAsRead": "Mark selected as read",
"MarkAs": "Mark as",
"Read": "Read",
"UnRead": "Un Read",
"Notifications": "Notifications",
"Notifications:Title": "Title",
"Notifications:Content": "Content",
"Notifications:Type": "Type",
"Notifications:SendTime": "SendTime",
"Notifications:System": "System",
"Notifications:Application": "Platform",
"Notifications:User": "User",
"Notifications:MultiTenancy": "Multi Tenancy",
"Notifications:Users": "Users",
"Notifications:NewTenantRegisterd": "Tenant creation notification",

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

@ -18,6 +18,18 @@
"LINGYUN.Abp.Message:03404": "发送消息失败: 用户不存在或已注销账号!",
"LINGYUN.Abp.Message:03410": "用户拒绝添加好友",
"LINGYUN.Abp.Message:03411": "对方已是您的好友或已发送验证请求,不能重复操作!",
"MarkSelectedAsRead": "标记选中已读",
"MarkAs": "标记为",
"Read": "已读",
"UnRead": "未读",
"Notifications": "通知列表",
"Notifications:Title": "标题",
"Notifications:Content": "内容",
"Notifications:Type": "类型",
"Notifications:SendTime": "发送时间",
"Notifications:System": "系统",
"Notifications:Application": "平台",
"Notifications:User": "用户",
"Notifications:MultiTenancy": "租户通知",
"Notifications:Users": "用户通知",
"Notifications:NewTenantRegisterd": "租户创建通知",
@ -33,5 +45,6 @@
"AddNewFriendBySearchId": "通过账号搜索添加",
"WelcomeToApplicationFormUser": "用户:{User} 欢迎您的加入!",
"Messages:NewFriend": "我已经添加您为好友,让我们一起聊天吧!"
}
}

10
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs

@ -17,12 +17,13 @@ namespace LINGYUN.Abp.MessageService.Mapper
{
public MessageServiceDomainAutoMapperProfile()
{
CreateMap<Notification, NotificationInfo>()
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.NotificationId))
.ForMember(dto => dto.Name, map => map.MapFrom(src => src.NotificationName))
CreateMap<UserNotificationInfo, NotificationInfo>()
.ForMember(dto => dto.Id, map => map.MapFrom(src => src.Id.ToString()))
.ForMember(dto => dto.Name, map => map.MapFrom(src => src.Name))
.ForMember(dto => dto.Lifetime, map => map.Ignore())
.ForMember(dto => dto.Type, map => map.MapFrom(src => src.Type))
.ForMember(dto => dto.Severity, map => map.MapFrom(src => src.Severity))
.ForMember(dto => dto.CreationTime, map => map.MapFrom(src => src.CreationTime))
.ForMember(dto => dto.Data, map => map.MapFrom((src, nfi) =>
{
var dataType = Type.GetType(src.NotificationTypeName);
@ -35,9 +36,6 @@ namespace LINGYUN.Abp.MessageService.Mapper
return new NotificationData();
}));
//CreateMap<Notification, NotificationInfo>()
// .ConvertUsing<NotificationTypeConverter>();
CreateMap<UserSubscribe, NotificationSubscriptionInfo>();
CreateMessageMap<GroupMessage, ChatMessage>()

13
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs

@ -14,16 +14,17 @@ namespace LINGYUN.Abp.MessageService.Notifications
long notificationId,
CancellationToken cancellationToken = default);
Task InsertUserNotificationsAsync(
IEnumerable<UserNotification> userNotifications,
Task<UserNotificationInfo> GetByIdAsync(
Guid userId,
long notificationId,
CancellationToken cancellationToken = default);
Task<UserNotification> GetByIdAsync(
Task<List<UserNotification>> GetListAsync(
Guid userId,
long notificationId,
IEnumerable<long> notificationIds,
CancellationToken cancellationToken = default);
Task<List<Notification>> GetNotificationsAsync(
Task<List<UserNotificationInfo>> GetNotificationsAsync(
Guid userId,
NotificationReadState? readState = null,
int maxResultCount = 10,
@ -35,7 +36,7 @@ namespace LINGYUN.Abp.MessageService.Notifications
NotificationReadState? readState = null,
CancellationToken cancellationToken = default);
Task<List<Notification>> GetListAsync(
Task<List<UserNotificationInfo>> GetListAsync(
Guid userId,
string filter = "",
string sorting = nameof(Notification.CreationTime),

27
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs

@ -57,15 +57,27 @@ namespace LINGYUN.Abp.MessageService.Notifications
long notificationId,
NotificationReadState readState,
CancellationToken cancellationToken = default)
{
await ChangeUserNotificationsReadStateAsync(
tenantId, userId, new long[] { notificationId }, readState, cancellationToken);
}
public async virtual Task ChangeUserNotificationsReadStateAsync(
Guid? tenantId,
Guid userId,
IEnumerable<long> notificationIds,
NotificationReadState readState,
CancellationToken cancellationToken = default)
{
using (var unitOfWork = _unitOfWorkManager.Begin())
using (_currentTenant.Change(tenantId))
{
var notification = await _userNotificationRepository.GetByIdAsync(userId, notificationId);
if (notification != null)
var notifications = await _userNotificationRepository.GetListAsync(userId, notificationIds);
if (notifications.Any())
{
notification.ChangeReadState(readState);
await _userNotificationRepository.UpdateAsync(notification);
notifications.ForEach(notification => notification.ChangeReadState(readState));
await _userNotificationRepository.UpdateManyAsync(notifications);
await unitOfWork.CompleteAsync();
}
@ -221,7 +233,7 @@ namespace LINGYUN.Abp.MessageService.Notifications
var notifications = await _userNotificationRepository
.GetNotificationsAsync(userId, readState, maxResultCount, cancellationToken);
return _objectMapper.Map<List<Notification>, List<NotificationInfo>>(notifications);
return _objectMapper.Map<List<UserNotificationInfo>, List<NotificationInfo>>(notifications);
}
}
@ -254,7 +266,7 @@ namespace LINGYUN.Abp.MessageService.Notifications
var notifications = await _userNotificationRepository
.GetListAsync(userId, filter, sorting, readState, skipCount, maxResultCount, cancellationToken);
return _objectMapper.Map<List<Notification>, List<NotificationInfo>>(notifications);
return _objectMapper.Map<List<UserNotificationInfo>, List<NotificationInfo>>(notifications);
}
}
@ -426,8 +438,7 @@ namespace LINGYUN.Abp.MessageService.Notifications
userNofitications.Add(userNofitication);
}
}
await _userNotificationRepository
.InsertUserNotificationsAsync(userNofitications, cancellationToken);
await _userNotificationRepository.InsertManyAsync(userNofitications, cancellationToken: cancellationToken);
await unitOfWork.CompleteAsync(cancellationToken);
}

11
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationTemplate.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Domain.Entities.Auditing;
namespace LINGYUN.Abp.MessageService.Notifications;
public class NotificationTemplate : AuditedAggregateRoot<Guid>
{
}

18
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotificationInfo.cs

@ -0,0 +1,18 @@
using LINGYUN.Abp.Notifications;
using System;
using Volo.Abp.Data;
namespace LINGYUN.Abp.MessageService.Notifications;
public class UserNotificationInfo
{
public Guid? TenantId { get; set; }
public string Name { get; set; }
public long Id { get; set; }
public ExtraPropertyDictionary ExtraProperties { get; set; }
public string NotificationTypeName { get; set; }
public DateTime CreationTime { get; set; }
public NotificationType Type { get; set; }
public NotificationSeverity Severity { get; set; }
public NotificationReadState State { get; set; }
}

103
aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs

@ -32,26 +32,49 @@ namespace LINGYUN.Abp.MessageService.Notifications
GetCancellationToken(cancellationToken));
}
public virtual async Task InsertUserNotificationsAsync(
IEnumerable<UserNotification> userNotifications,
public virtual async Task<UserNotificationInfo> GetByIdAsync(
Guid userId,
long notificationId,
CancellationToken cancellationToken = default)
{
await (await GetDbSetAsync()).AddRangeAsync(userNotifications, GetCancellationToken(cancellationToken));
var dbContext = await GetDbContextAsync();
var userNotifilerQuery = dbContext.Set<UserNotification>()
.Where(x => x.UserId == userId);
var notificationQuery = dbContext.Set<Notification>();
var notifilerQuery = from un in userNotifilerQuery
join n in dbContext.Set<Notification>()
on un.NotificationId equals n.NotificationId
where n.Id.Equals(notificationId)
select new UserNotificationInfo
{
Id = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
CreationTime = n.CreationTime,
NotificationTypeName = n.NotificationTypeName,
Severity = n.Severity,
State = un.ReadStatus,
Type = n.Type
};
return await notifilerQuery
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<UserNotification> GetByIdAsync(
public async virtual Task<List<UserNotification>> GetListAsync(
Guid userId,
long notificationId,
IEnumerable<long> notificationIds,
CancellationToken cancellationToken = default)
{
var userNofitication = await (await GetDbSetAsync())
.Where(x => x.NotificationId.Equals(notificationId) && x.UserId.Equals(userId))
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
return userNofitication;
return await (await GetDbSetAsync())
.Where(x => x.UserId.Equals(userId) && notificationIds.Contains(x.Id))
.ToListAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<Notification>> GetNotificationsAsync(
public virtual async Task<List<UserNotificationInfo>> GetNotificationsAsync(
Guid userId,
NotificationReadState? readState = null,
int maxResultCount = 10,
@ -65,7 +88,18 @@ namespace LINGYUN.Abp.MessageService.Notifications
var notifilerQuery = from un in userNotifilerQuery
join n in dbContext.Set<Notification>()
on un.NotificationId equals n.NotificationId
select n;
select new UserNotificationInfo
{
Id = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
CreationTime = n.CreationTime,
NotificationTypeName = n.NotificationTypeName,
Severity = n.Severity,
State = un.ReadStatus,
Type = n.Type
};
return await notifilerQuery
.OrderBy(nameof(Notification.CreationTime) + " DESC")
@ -82,22 +116,24 @@ namespace LINGYUN.Abp.MessageService.Notifications
{
var dbContext = await GetDbContextAsync();
var userNotifilerQuery = dbContext.Set<UserNotification>()
.Where(x => x.UserId == userId)
.WhereIf(readState.HasValue, x => x.ReadStatus == readState.Value);
.Where(x => x.UserId == userId)
.WhereIf(readState.HasValue, x => x.ReadStatus == readState.Value);
var notificationQuery = dbContext.Set<Notification>()
.WhereIf(!filter.IsNullOrWhiteSpace(), nf =>
nf.NotificationName.Contains(filter) ||
nf.NotificationTypeName.Contains(filter));
var notifilerQuery = from un in userNotifilerQuery
join n in dbContext.Set<Notification>()
join n in notificationQuery
on un.NotificationId equals n.NotificationId
select n;
return await notifilerQuery
.WhereIf(!filter.IsNullOrWhiteSpace(), nf =>
nf.NotificationName.Contains(filter) ||
nf.NotificationTypeName.Contains(filter))
.CountAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task<List<Notification>> GetListAsync(
public virtual async Task<List<UserNotificationInfo>> GetListAsync(
Guid userId,
string filter = "",
string sorting = nameof(Notification.CreationTime),
@ -109,18 +145,31 @@ namespace LINGYUN.Abp.MessageService.Notifications
sorting ??= $"{nameof(Notification.CreationTime)} DESC";
var dbContext = await GetDbContextAsync();
var userNotifilerQuery = dbContext.Set<UserNotification>()
.Where(x => x.UserId == userId)
.WhereIf(readState.HasValue, x => x.ReadStatus == readState.Value);
.Where(x => x.UserId == userId)
.WhereIf(readState.HasValue, x => x.ReadStatus == readState.Value);
var notificationQuery = dbContext.Set<Notification>()
.WhereIf(!filter.IsNullOrWhiteSpace(), nf =>
nf.NotificationName.Contains(filter) ||
nf.NotificationTypeName.Contains(filter));
var notifilerQuery = from un in userNotifilerQuery
join n in dbContext.Set<Notification>()
on un.NotificationId equals n.NotificationId
select n;
join n in notificationQuery
on un.NotificationId equals n.NotificationId
select new UserNotificationInfo
{
Id = n.NotificationId,
TenantId = n.TenantId,
Name = n.NotificationName,
ExtraProperties = n.ExtraProperties,
CreationTime = n.CreationTime,
NotificationTypeName = n.NotificationTypeName,
Severity = n.Severity,
State = un.ReadStatus,
Type = n.Type
};
return await notifilerQuery
.WhereIf(!filter.IsNullOrWhiteSpace(), nf =>
nf.NotificationName.Contains(filter) ||
nf.NotificationTypeName.Contains(filter))
.OrderBy(sorting)
.PageBy(skipCount, maxResultCount)
.AsNoTracking()

18
aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN/Abp/MessageService/Notifications/MyNotificationController.cs

@ -1,5 +1,4 @@
using LINGYUN.Abp.Notifications;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
@ -17,31 +16,38 @@ namespace LINGYUN.Abp.MessageService.Notifications
IMyNotificationAppService myNotificationAppService)
{
MyNotificationAppService = myNotificationAppService;
}
[HttpPut]
[Route("mark-read-state")]
public async virtual Task MarkReadStateAsync(NotificationMarkReadStateInput input)
{
await MyNotificationAppService.MarkReadStateAsync(input);
}
[HttpDelete]
[Route("{id}")]
public virtual async Task DeleteAsync(long id)
public async virtual Task DeleteAsync(long id)
{
await MyNotificationAppService.DeleteAsync(id);
}
[HttpGet]
[Route("assignables")]
public virtual async Task<ListResultDto<NotificationGroupDto>> GetAssignableNotifiersAsync()
public async virtual Task<ListResultDto<NotificationGroupDto>> GetAssignableNotifiersAsync()
{
return await MyNotificationAppService.GetAssignableNotifiersAsync();
}
[HttpGet]
[Route("{id}")]
public virtual async Task<NotificationInfo> GetAsync(long id)
public async virtual Task<UserNotificationDto> GetAsync(long id)
{
return await MyNotificationAppService.GetAsync(id);
}
[HttpGet]
public virtual async Task<PagedResultDto<NotificationInfo>> GetListAsync(UserNotificationGetByPagedDto input)
public async virtual Task<PagedResultDto<UserNotificationDto>> GetListAsync(UserNotificationGetByPagedDto input)
{
return await MyNotificationAppService.GetListAsync(input);
}

1
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/en.json

@ -38,6 +38,7 @@
"Features:DisplayName:PublicAccess": "Public Access",
"Features:Description:PublicAccess": "Whether to allow unauthorized users to access public directories",
"Features:DisplayName:OssObject": "Oss Objects",
"Features:Description:OssObject": "Managing Object Storage",
"Features:DisplayName:DownloadFile": "Download file",
"Features:Description:DownloadFile": "Whether to allow users to download files",
"Features:DisplayName:DownloadLimit": "Limit Of Downloads",

1
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.Domain.Shared/LINGYUN/Abp/OssManagement/Localization/Resources/zh-Hans.json

@ -38,6 +38,7 @@
"Features:DisplayName:PublicAccess": "公共访问",
"Features:Description:PublicAccess": "是否允许未经授权的用户访问公共目录",
"Features:DisplayName:OssObject": "Oss管理",
"Features:Description:OssObject": "管理对象存储",
"Features:DisplayName:DownloadFile": "下载文件",
"Features:Description:DownloadFile": "是否允许用户下载文件",
"Features:DisplayName:DownloadLimit": "限制下载文件次数",

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

@ -39,6 +39,7 @@
"DisplayName:AdminEmailAddress": "Admin Email Address",
"DisplayName:AdminPassword": "Admin Password",
"TenantNotFoundById": "Tenant: {0} not found!",
"TenantNotFoundByName": "Tenant: {0} not found!"
"TenantNotFoundByName": "Tenant: {0} not found!",
"UnActived": "UnActived"
}
}

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

@ -39,6 +39,7 @@
"DisplayName:AdminEmailAddress": "管理员电子邮件地址",
"DisplayName:AdminPassword": "管理员密码",
"TenantNotFoundById": "租户: {0} 不存在!",
"TenantNotFoundByName": "租户: {0} 不存在!"
"TenantNotFoundByName": "租户: {0} 不存在!",
"UnActived": "未启用"
}
}

2
aspnet-core/modules/wechat/LINGYUN.Abp.Notifications.WeChat.MiniProgram/LINGYUN/Abp/Notifications/WeChat/MiniProgram/WeChatMiniProgramNotificationPublishProvider.cs

@ -19,10 +19,8 @@ namespace LINGYUN.Abp.Notifications.WeChat.MiniProgram
protected ISubscribeMessager SubscribeMessager { get; }
protected AbpNotificationsWeChatMiniProgramOptions Options { get; }
public WeChatMiniProgramNotificationPublishProvider(
IServiceProvider serviceProvider,
ISubscribeMessager subscribeMessager,
IOptions<AbpNotificationsWeChatMiniProgramOptions> options)
: base(serviceProvider)
{
Options = options.Value;
SubscribeMessager = subscribeMessager;

32
aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/BackgroundJobs/NotificationPublishJob.cs

@ -11,35 +11,35 @@ namespace LY.MicroService.RealtimeMessage.BackgroundJobs;
public class NotificationPublishJob : AsyncBackgroundJob<NotificationPublishJobArgs>, ITransientDependency
{
protected AbpNotificationOptions Options { get; }
protected INotificationStore Store { get; }
protected IServiceProvider ServiceProvider { get; }
protected IServiceScopeFactory ServiceScopeFactory { get; }
public NotificationPublishJob(
IOptions<AbpNotificationOptions> options,
INotificationStore store,
IServiceProvider serviceProvider)
IServiceScopeFactory serviceScopeFactory)
{
Store = store;
Options = options.Value;
ServiceProvider = serviceProvider;
ServiceScopeFactory = serviceScopeFactory;
}
public override async Task ExecuteAsync(NotificationPublishJobArgs args)
{
var providerType = Type.GetType(args.ProviderType);
if (ServiceProvider.GetRequiredService(providerType) is INotificationPublishProvider publishProvider)
using (var scope = ServiceScopeFactory.CreateScope())
{
var notification = await Store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId);
notification.Data = NotificationDataConverter.Convert(notification.Data);
var notifacationDataMapping = Options.NotificationDataMappings
.GetMapItemOrDefault(notification.Name, publishProvider.Name);
if (notifacationDataMapping != null)
if (scope.ServiceProvider.GetRequiredService(providerType) is INotificationPublishProvider publishProvider)
{
notification.Data = notifacationDataMapping.MappingFunc(notification.Data);
var store = scope.ServiceProvider.GetRequiredService<INotificationStore>();
var notification = await store.GetNotificationOrNullAsync(args.TenantId, args.NotificationId);
notification.Data = NotificationDataConverter.Convert(notification.Data);
var notifacationDataMapping = Options.NotificationDataMappings
.GetMapItemOrDefault(notification.Name, publishProvider.Name);
if (notifacationDataMapping != null)
{
notification.Data = notifacationDataMapping.MappingFunc(notification.Data);
}
await publishProvider.PublishAsync(notification, args.UserIdentifiers);
}
await publishProvider.PublishAsync(notification, args.UserIdentifiers);
}
}
}

84
aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs

@ -1,5 +1,6 @@
using LINGYUN.Abp.Notifications;
using LY.MicroService.RealtimeMessage.BackgroundJobs;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@ -12,6 +13,7 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.TextTemplating;
using Volo.Abp.Uow;
namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
@ -23,7 +25,10 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
/// 作用在于SignalR客户端只会与一台服务器建立连接,
/// 只有启用了SignlR服务端的才能真正将消息发布到客户端
/// </remarks>
public class NotificationEventHandler : IDistributedEventHandler<NotificationEto<NotificationData>>, ITransientDependency
public class NotificationEventHandler :
IDistributedEventHandler<NotificationEto<NotificationData>>,
IDistributedEventHandler<NotificationEto<NotificationTemplate>>,
ITransientDependency
{
/// <summary>
/// Reference to <see cref="ILogger<DefaultNotificationDispatcher>"/>.
@ -46,10 +51,18 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
/// </summary>
protected IBackgroundJobManager BackgroundJobManager { get; }
/// <summary>
/// Reference to <see cref="ITemplateRenderer"/>.
/// </summary>
protected ITemplateRenderer TemplateRenderer { get; }
/// <summary>
/// Reference to <see cref="INotificationStore"/>.
/// </summary>
protected INotificationStore NotificationStore { get; }
/// <summary>
/// Reference to <see cref="IStringLocalizerFactory"/>.
/// </summary>
protected IStringLocalizerFactory StringLocalizerFactory { get; }
/// <summary>
/// Reference to <see cref="INotificationDefinitionManager"/>.
/// </summary>
protected INotificationDefinitionManager NotificationDefinitionManager { get; }
@ -68,7 +81,9 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
public NotificationEventHandler(
ICurrentTenant currentTenant,
IJsonSerializer jsonSerializer,
ITemplateRenderer templateRenderer,
IBackgroundJobManager backgroundJobManager,
IStringLocalizerFactory stringLocalizerFactory,
IOptions<AbpNotificationOptions> options,
INotificationStore notificationStore,
INotificationDefinitionManager notificationDefinitionManager,
@ -78,7 +93,9 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
Options = options.Value;
CurrentTenant = currentTenant;
JsonSerializer = jsonSerializer;
TemplateRenderer = templateRenderer;
BackgroundJobManager = backgroundJobManager;
StringLocalizerFactory = stringLocalizerFactory;
NotificationStore = notificationStore;
NotificationDefinitionManager = notificationDefinitionManager;
NotificationSubscriptionManager = notificationSubscriptionManager;
@ -88,7 +105,65 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
}
[UnitOfWork]
public virtual async Task HandleEventAsync(NotificationEto<NotificationData> eventData)
public async virtual Task HandleEventAsync(NotificationEto<NotificationTemplate> eventData)
{
using (CurrentTenant.Change(eventData.TenantId))
{
var notification = NotificationDefinitionManager.GetOrNull(eventData.Name);
if (notification == null)
{
return;
}
var notificationInfo = new NotificationInfo
{
Name = notification.Name,
CreationTime = eventData.CreationTime,
Severity = eventData.Severity,
Lifetime = notification.NotificationLifetime,
TenantId = eventData.TenantId,
Type = notification.NotificationType
};
notificationInfo.SetId(eventData.Id);
var title = eventData.Data.Title;
if (title.IsNullOrWhiteSpace())
{
title = notification.DisplayName.Localize(StringLocalizerFactory);
}
var message = await TemplateRenderer.RenderAsync(
templateName: eventData.Data.Name,
cultureName: eventData.Data.Culture,
globalContext: eventData.Data.ExtraProperties);
var notificationData = new NotificationData();
notificationData.WriteStandardData(
title: title,
message: message,
createTime: eventData.CreationTime,
formUser: eventData.Data.FormUser);
notificationInfo.Data = notificationData;
Logger.LogDebug($"Persistent notification {notificationInfo.Name}");
// 持久化通知
await NotificationStore.InsertNotificationAsync(notificationInfo);
var providers = Enumerable.Reverse(NotificationPublishProviderManager.Providers);
// 过滤用户指定提供者
if (notification.Providers.Any())
{
providers = providers.Where(p => notification.Providers.Contains(p.Name));
}
await PublishFromProvidersAsync(providers, eventData.Users, notificationInfo);
}
}
[UnitOfWork]
public async virtual Task HandleEventAsync(NotificationEto<NotificationData> eventData)
{
using (CurrentTenant.Change(eventData.TenantId))
{
@ -119,8 +194,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
// 持久化通知
await NotificationStore.InsertNotificationAsync(notificationInfo);
var providers = Enumerable
.Reverse(NotificationPublishProviderManager.Providers);
var providers = Enumerable.Reverse(NotificationPublishProviderManager.Providers);
// 过滤用户指定提供者
if (notification.Providers.Any())
@ -196,7 +270,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed
{
Logger.LogDebug($"Sending notification with provider {provider.Name}");
var notifacationDataMapping = Options.NotificationDataMappings
.GetMapItemOrDefault(notificationInfo.Name, provider.Name);
.GetMapItemOrDefault(provider.Name, notificationInfo.Name);
if (notifacationDataMapping != null)
{
notificationInfo.Data = notifacationDataMapping.MappingFunc(notificationInfo.Data);

Loading…
Cancel
Save