45 changed files with 2009 additions and 9 deletions
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,23 @@ |
|||||||
|
<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.EventBus" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.Json" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.BackgroundJobs.Abstractions" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.IdGenerator\Sanhe.Abp.IdGenerator.csproj" /> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.RealTime\Sanhe.Abp.RealTime.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
|
||||||
|
</Project> |
@ -0,0 +1,46 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Sanhe.Abp.IdGenerator; |
||||||
|
using Sanhe.Abp.RealTime; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Volo.Abp.BackgroundJobs; |
||||||
|
using Volo.Abp.BackgroundWorkers; |
||||||
|
using Volo.Abp.Json; |
||||||
|
using Volo.Abp.Modularity; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
// TODO: 需要重命名 AbpNotificationsModule |
||||||
|
[DependsOn( |
||||||
|
typeof(AbpBackgroundWorkersModule), |
||||||
|
typeof(AbpBackgroundJobsAbstractionsModule), |
||||||
|
typeof(AbpIdGeneratorModule), |
||||||
|
typeof(AbpJsonModule), |
||||||
|
typeof(AbpRealTimeModule))] |
||||||
|
public class AbpNotificationsModule : AbpModule |
||||||
|
{ |
||||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
AutoAddDefinitionProviders(context.Services); |
||||||
|
} |
||||||
|
|
||||||
|
private void AutoAddDefinitionProviders(IServiceCollection services) |
||||||
|
{ |
||||||
|
var definitionProviders = new List<Type>(); |
||||||
|
|
||||||
|
services.OnRegistred(context => |
||||||
|
{ |
||||||
|
if (typeof(INotificationDefinitionProvider).IsAssignableFrom(context.ImplementationType)) |
||||||
|
{ |
||||||
|
definitionProviders.Add(context.ImplementationType); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var preActions = services.GetPreConfigureActions<AbpNotificationsOptions>(); |
||||||
|
Configure<AbpNotificationsOptions>(options => |
||||||
|
{ |
||||||
|
preActions.Configure(options); |
||||||
|
options.DefinitionProviders.AddIfNotContains(definitionProviders); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
using Volo.Abp.Collections; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知选项 |
||||||
|
/// </summary> |
||||||
|
public class AbpNotificationsOptions |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 自定义通知集合 |
||||||
|
/// </summary> |
||||||
|
public ITypeList<INotificationDefinitionProvider> DefinitionProviders { get; } |
||||||
|
/// <summary> |
||||||
|
/// 发布者集合 |
||||||
|
/// </summary> |
||||||
|
public ITypeList<INotificationPublishProvider> PublishProviders { get; } |
||||||
|
/// <summary> |
||||||
|
/// 可以自定义某个通知的格式 |
||||||
|
/// </summary> |
||||||
|
public NotificationDataMappingDictionary NotificationDataMappings { get; } |
||||||
|
|
||||||
|
public AbpNotificationsOptions() |
||||||
|
{ |
||||||
|
PublishProviders = new TypeList<INotificationPublishProvider>(); |
||||||
|
DefinitionProviders = new TypeList<INotificationDefinitionProvider>(); |
||||||
|
NotificationDataMappings = new NotificationDataMappingDictionary(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
using JetBrains.Annotations; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知定义上下文 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationDefinitionContext |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 添加通知组定义 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name"></param> |
||||||
|
/// <param name="displayName"></param> |
||||||
|
/// <param name="allowSubscriptionToClients"></param> |
||||||
|
/// <returns></returns> |
||||||
|
NotificationGroupDefinition AddGroup( |
||||||
|
[NotNull] string name, |
||||||
|
ILocalizableString displayName = null, |
||||||
|
bool allowSubscriptionToClients = true); |
||||||
|
/// <summary> |
||||||
|
/// 获取通知组定义 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name"></param> |
||||||
|
/// <returns></returns> |
||||||
|
NotificationGroupDefinition GetGroupOrNull(string name); |
||||||
|
/// <summary> |
||||||
|
/// 移除通知组 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name"></param> |
||||||
|
void RemoveGroup(string name); |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
using JetBrains.Annotations; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知定义管理者接口 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationDefinitionManager |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 获取通知定义 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name"></param> |
||||||
|
/// <returns></returns> |
||||||
|
[NotNull] |
||||||
|
NotificationDefinition Get([NotNull] string name); |
||||||
|
/// <summary> |
||||||
|
/// 获取所有通知定义 |
||||||
|
/// </summary> |
||||||
|
/// <returns></returns> |
||||||
|
IReadOnlyList<NotificationDefinition> GetAll(); |
||||||
|
/// <summary> |
||||||
|
/// 获取通知定义,如果为空返回Null |
||||||
|
/// </summary> |
||||||
|
/// <param name="name"></param> |
||||||
|
/// <returns></returns> |
||||||
|
NotificationDefinition GetOrNull(string name); |
||||||
|
/// <summary> |
||||||
|
/// 获取通知定义分组列表 |
||||||
|
/// </summary> |
||||||
|
/// <returns></returns> |
||||||
|
IReadOnlyList<NotificationGroupDefinition> GetGroups(); |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
namespace Sanhe.Abp.Notifications |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 通知定义提供者接口 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationDefinitionProvider |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 定义 |
||||||
|
/// </summary> |
||||||
|
/// <param name="context">通知定义上下文</param> |
||||||
|
void Define(INotificationDefinitionContext context); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知发布提供者接口 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationPublishProvider |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 名称 |
||||||
|
/// </summary> |
||||||
|
string Name { get; } |
||||||
|
/// <summary> |
||||||
|
/// 发布通知 |
||||||
|
/// </summary> |
||||||
|
/// <param name="notification">通知信息</param> |
||||||
|
/// <param name="identifiers">接收用户列表</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers); |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 通知发布提供者管理 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationPublishProviderManager |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 提供者列表 |
||||||
|
/// </summary> |
||||||
|
List<INotificationPublishProvider> Providers { get; } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 发送通知接口 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationSender |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 发送通知 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name">名称</param> |
||||||
|
/// <param name="data">数据</param> |
||||||
|
/// <param name="userId">用户,为空标识发给所有订阅用户</param> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="severity">严重级别</param> |
||||||
|
/// <returns>通知标识</returns> |
||||||
|
Task<string> SendNofiterAsync( |
||||||
|
string name, |
||||||
|
NotificationData data, |
||||||
|
UserIdentifier user = 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, |
||||||
|
IEnumerable<UserIdentifier> users = null, |
||||||
|
Guid? tenantId = null, |
||||||
|
NotificationSeverity severity = NotificationSeverity.Info); |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知相关储存处 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationStore |
||||||
|
{ |
||||||
|
Task InsertUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
UserIdentifier identifier, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task InsertUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task DeleteUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task DeleteAllUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task DeleteUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
IEnumerable<UserIdentifier> identifiers = null, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string userName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<bool> IsSubscribedAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task InsertNotificationAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task DeleteNotificationAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task DeleteNotificationAsync( |
||||||
|
int batchCount, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task InsertUserNotificationAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
Guid userId, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task InsertUserNotificationsAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
IEnumerable<Guid> userIds, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task DeleteUserNotificationAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
long notificationId, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<NotificationInfo> GetNotificationOrNullAsync( |
||||||
|
Guid? tenantId, |
||||||
|
long notificationId, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<NotificationInfo>> GetUserNotificationsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
NotificationReadState? readState = null, |
||||||
|
int maxResultCount = 10, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<int> GetUserNotificationsCountAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string filter = "", |
||||||
|
NotificationReadState? readState = null, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<NotificationInfo>> GetUserNotificationsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string filter = "", |
||||||
|
string sorting = nameof(NotificationInfo.CreationTime), |
||||||
|
NotificationReadState? readState = null, |
||||||
|
int skipCount = 1, |
||||||
|
int maxResultCount = 10, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task ChangeUserNotificationReadStateAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
long notificationId, |
||||||
|
NotificationReadState readState, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
} |
@ -0,0 +1,123 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知订阅管理器 |
||||||
|
/// </summary> |
||||||
|
public interface INotificationSubscriptionManager |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 是否已订阅 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="userId">用户标识</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<bool> IsSubscribedAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 订阅通知 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="identifier">用户标识</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task SubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
UserIdentifier identifier, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 订阅通知 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="identifiers">用户标识列表</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task SubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 取消所有用户订阅 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task UnsubscribeAllAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 取消订阅 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="identifier">用户标识</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task UnsubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
UserIdentifier identifier, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 取消订阅 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="identifiers">用户标识列表</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task UnsubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 获取通知被订阅用户列表 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="notificationName">通知名称</param> |
||||||
|
/// <param name="identifiers">需要检查的用户列表</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<List<NotificationSubscriptionInfo>> GetUsersSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
IEnumerable<UserIdentifier> identifiers = null, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 获取用户订阅列表 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="userId">用户标识</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 获取用户订阅列表 |
||||||
|
/// </summary> |
||||||
|
/// <param name="tenantId">租户</param> |
||||||
|
/// <param name="userName">用户名</param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string userName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
} |
@ -0,0 +1,115 @@ |
|||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||||
|
using Microsoft.Extensions.Options; |
||||||
|
using Sanhe.Abp.IdGenerator; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
using Volo.Abp.EventBus.Distributed; |
||||||
|
using Volo.Abp.Uow; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications.Internal |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 默认实现通过分布式事件发送通知 |
||||||
|
/// 可替换实现来发送实时通知 |
||||||
|
/// </summary> |
||||||
|
public class NotificationSender : INotificationSender, ITransientDependency |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Reference to <see cref="ILogger<NotificationSender>"/>. |
||||||
|
/// </summary> |
||||||
|
public ILogger<NotificationSender> Logger { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// Reference to <see cref="IDistributedEventBus"/>. |
||||||
|
/// </summary> |
||||||
|
public IDistributedEventBus DistributedEventBus { get; } |
||||||
|
/// <summary> |
||||||
|
/// Reference to <see cref="IDistributedIdGenerator"/>. |
||||||
|
/// </summary> |
||||||
|
protected IDistributedIdGenerator DistributedIdGenerator { get; } |
||||||
|
/// <summary> |
||||||
|
/// Reference to <see cref="IUnitOfWorkManager"/>. |
||||||
|
/// </summary> |
||||||
|
protected IUnitOfWorkManager UnitOfWorkManager { get; } |
||||||
|
/// <summary> |
||||||
|
/// 通知选项 |
||||||
|
/// </summary> |
||||||
|
protected AbpNotificationsOptions Options { get; } |
||||||
|
|
||||||
|
public NotificationSender( |
||||||
|
IDistributedEventBus distributedEventBus, |
||||||
|
IDistributedIdGenerator distributedIdGenerator, |
||||||
|
IUnitOfWorkManager unitOfWorkManager, |
||||||
|
IOptions<AbpNotificationsOptions> optionsAccessor) |
||||||
|
{ |
||||||
|
Options = optionsAccessor.Value; |
||||||
|
DistributedEventBus = distributedEventBus; |
||||||
|
DistributedIdGenerator = distributedIdGenerator; |
||||||
|
UnitOfWorkManager = unitOfWorkManager; |
||||||
|
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( |
||||||
|
string name, |
||||||
|
NotificationData data, |
||||||
|
IEnumerable<UserIdentifier> users = null, |
||||||
|
Guid? tenantId = null, |
||||||
|
NotificationSeverity severity = NotificationSeverity.Info) |
||||||
|
{ |
||||||
|
return await PublishNofiterAsync(name, data, users, tenantId, severity); |
||||||
|
} |
||||||
|
|
||||||
|
protected async Task<string> PublishNofiterAsync( |
||||||
|
string name, |
||||||
|
NotificationData data, |
||||||
|
IEnumerable<UserIdentifier> users = null, |
||||||
|
Guid? tenantId = null, |
||||||
|
NotificationSeverity severity = NotificationSeverity.Info) |
||||||
|
{ |
||||||
|
var eto = new NotificationEto<NotificationData>(data) |
||||||
|
{ |
||||||
|
Id = DistributedIdGenerator.Create(), |
||||||
|
TenantId = tenantId, |
||||||
|
Users = users?.ToList(), |
||||||
|
Name = name, |
||||||
|
CreationTime = DateTime.Now, |
||||||
|
Severity = severity |
||||||
|
}; |
||||||
|
|
||||||
|
if (UnitOfWorkManager.Current != null) |
||||||
|
{ |
||||||
|
UnitOfWorkManager.Current.OnCompleted(async () => |
||||||
|
{ |
||||||
|
await DistributedEventBus.PublishAsync(eto); |
||||||
|
}); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
await DistributedEventBus.PublishAsync(eto); |
||||||
|
} |
||||||
|
|
||||||
|
return eto.Id.ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications.Internal |
||||||
|
{ |
||||||
|
internal class NotificationSubscriptionManager : INotificationSubscriptionManager, ITransientDependency |
||||||
|
{ |
||||||
|
private readonly INotificationStore _store; |
||||||
|
|
||||||
|
public NotificationSubscriptionManager(INotificationStore store) |
||||||
|
{ |
||||||
|
_store = store; |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<List<NotificationSubscriptionInfo>> GetUsersSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
IEnumerable<UserIdentifier> identifiers = null, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await _store.GetUserSubscriptionsAsync(tenantId, notificationName, identifiers, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await _store.GetUserSubscriptionsAsync(tenantId, userId, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string userName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await _store.GetUserSubscriptionsAsync(tenantId, userName, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<bool> IsSubscribedAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await _store.IsSubscribedAsync(tenantId, userId, notificationName, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task SubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
UserIdentifier identifier, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
if (await IsSubscribedAsync(tenantId, identifier.UserId, notificationName, cancellationToken)) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
await _store.InsertUserSubscriptionAsync(tenantId, identifier, notificationName, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task SubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
foreach (var identifier in identifiers) |
||||||
|
{ |
||||||
|
await SubscribeAsync(tenantId, identifier, notificationName, cancellationToken); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task UnsubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
UserIdentifier identifier, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
await _store.DeleteUserSubscriptionAsync(tenantId, identifier.UserId, notificationName, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task UnsubscribeAllAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
await _store.DeleteAllUserSubscriptionAsync(tenantId, notificationName, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task UnsubscribeAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
await _store.DeleteUserSubscriptionAsync(tenantId, identifiers, notificationName, cancellationToken); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,177 @@ |
|||||||
|
using Sanhe.Abp.RealTime.Localization; |
||||||
|
using System; |
||||||
|
using Volo.Abp.Data; |
||||||
|
using Volo.Abp.EventBus; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知数据 |
||||||
|
/// </summary> |
||||||
|
/// <remarks> |
||||||
|
/// 把通知的标题和内容设计为 <see cref="LocalizableStringInfo"/> 让客户端自行本地化 |
||||||
|
/// </remarks> |
||||||
|
[Serializable] |
||||||
|
[EventName("notifications")] |
||||||
|
public class NotificationData : IHasExtraProperties |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 用来标识是否需要本地化的信息 |
||||||
|
/// </summary> |
||||||
|
public const string LocalizerKey = "L"; |
||||||
|
/// <summary> |
||||||
|
/// <see cref="Type"/>类型完全名称 |
||||||
|
/// </summary> |
||||||
|
public virtual string Type => GetType().FullName; |
||||||
|
/// <summary> |
||||||
|
/// 获取或设置扩展属性 |
||||||
|
/// </summary> |
||||||
|
/// <param name="key"></param> |
||||||
|
/// <returns></returns> |
||||||
|
public object this[string key] { |
||||||
|
get { |
||||||
|
return this.GetProperty(key); |
||||||
|
} |
||||||
|
set { |
||||||
|
this.SetProperty(key, value); |
||||||
|
} |
||||||
|
} |
||||||
|
/// <summary> |
||||||
|
/// 扩展属性 |
||||||
|
/// </summary> |
||||||
|
public ExtraPropertyDictionary ExtraProperties { get; set; } |
||||||
|
|
||||||
|
public NotificationData() |
||||||
|
{ |
||||||
|
ExtraProperties = new ExtraPropertyDictionary(); |
||||||
|
this.SetDefaultsForExtraProperties(); |
||||||
|
|
||||||
|
TrySetData(LocalizerKey, false); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 写入本地化的消息数据 |
||||||
|
/// </summary> |
||||||
|
/// <param name="title"></param> |
||||||
|
/// <param name="message"></param> |
||||||
|
/// <param name="createTime"></param> |
||||||
|
/// <param name="formUser"></param> |
||||||
|
/// <param name="description"></param> |
||||||
|
/// <returns></returns> |
||||||
|
public NotificationData WriteLocalizedData( |
||||||
|
LocalizableStringInfo title, |
||||||
|
LocalizableStringInfo message, |
||||||
|
DateTime createTime, |
||||||
|
string formUser, |
||||||
|
LocalizableStringInfo description = null) |
||||||
|
{ |
||||||
|
TrySetData("title", title); |
||||||
|
TrySetData("message", message); |
||||||
|
TrySetData("formUser", formUser); |
||||||
|
TrySetData("createTime", createTime); |
||||||
|
TrySetData(LocalizerKey, true); |
||||||
|
|
||||||
|
if (description != null) |
||||||
|
{ |
||||||
|
TrySetData("description", description); |
||||||
|
} |
||||||
|
|
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 写入标准数据 |
||||||
|
/// </summary> |
||||||
|
/// <param name="title">标题</param> |
||||||
|
/// <param name="message">内容</param> |
||||||
|
/// <param name="createTime">创建时间</param> |
||||||
|
/// <param name="formUser">来源用户</param> |
||||||
|
/// <param name="description">附加说明</param> |
||||||
|
/// <returns></returns> |
||||||
|
public NotificationData WriteStandardData(string title, string message, DateTime createTime, string formUser, string description = "") |
||||||
|
{ |
||||||
|
TrySetData("title", title); |
||||||
|
TrySetData("message", message); |
||||||
|
TrySetData("description", description); |
||||||
|
TrySetData("formUser", formUser); |
||||||
|
TrySetData("createTime", createTime); |
||||||
|
TrySetData(LocalizerKey, false); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 写入标准数据 |
||||||
|
/// </summary> |
||||||
|
/// <param name="prefix">数据前缀</param> |
||||||
|
/// <param name="key">标识</param> |
||||||
|
/// <param name="value">数据内容</param> |
||||||
|
/// <returns></returns> |
||||||
|
public NotificationData WriteStandardData(string prefix, string key, object value) |
||||||
|
{ |
||||||
|
TrySetData(string.Concat(prefix, key), value); |
||||||
|
TrySetData(LocalizerKey, false); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 转换为标准数据 |
||||||
|
/// </summary> |
||||||
|
/// <param name="sourceData">原始数据</param> |
||||||
|
/// <returns></returns> |
||||||
|
public static NotificationData ToStandardData(NotificationData sourceData) |
||||||
|
{ |
||||||
|
var data = new NotificationData(); |
||||||
|
data.TrySetData("title", sourceData.TryGetData("title")); |
||||||
|
data.TrySetData("message", sourceData.TryGetData("message")); |
||||||
|
data.TrySetData("description", sourceData.TryGetData("description")); |
||||||
|
data.TrySetData("formUser", sourceData.TryGetData("formUser")); |
||||||
|
data.TrySetData("createTime", sourceData.TryGetData("createTime")); |
||||||
|
data.TrySetData(LocalizerKey, sourceData.TryGetData(LocalizerKey)); |
||||||
|
return data; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 转换为标准数据 |
||||||
|
/// </summary> |
||||||
|
/// <param name="prefix">数据前缀</param> |
||||||
|
/// <param name="sourceData">原始数据</param> |
||||||
|
/// <returns></returns> |
||||||
|
public static NotificationData ToStandardData(string prefix, NotificationData sourceData) |
||||||
|
{ |
||||||
|
var data = ToStandardData(sourceData); |
||||||
|
|
||||||
|
foreach (var property in sourceData.ExtraProperties) |
||||||
|
{ |
||||||
|
if (property.Key.StartsWith(prefix)) |
||||||
|
{ |
||||||
|
var key = property.Key.Replace(prefix, ""); |
||||||
|
data.TrySetData(key, property.Value); |
||||||
|
} |
||||||
|
} |
||||||
|
return data; |
||||||
|
} |
||||||
|
|
||||||
|
public object TryGetData(string key) |
||||||
|
{ |
||||||
|
return this.GetProperty(key); |
||||||
|
} |
||||||
|
|
||||||
|
public void TrySetData(string key, object value) |
||||||
|
{ |
||||||
|
this.SetProperty(key, value); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 需要本地化 |
||||||
|
/// </summary> |
||||||
|
/// <returns></returns> |
||||||
|
public bool NeedLocalizer() |
||||||
|
{ |
||||||
|
var localizer = TryGetData(LocalizerKey); |
||||||
|
if (localizer != null && localizer is bool needLocalizer) |
||||||
|
{ |
||||||
|
return needLocalizer; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
using Sanhe.Abp.RealTime.Localization; |
||||||
|
using Newtonsoft.Json; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
public class NotificationDataConverter |
||||||
|
{ |
||||||
|
public static NotificationData Convert(NotificationData notificationData) |
||||||
|
{ |
||||||
|
if (notificationData != null) |
||||||
|
{ |
||||||
|
if (notificationData.NeedLocalizer()) |
||||||
|
{ |
||||||
|
// 潜在的空对象引用修复 |
||||||
|
if (notificationData.ExtraProperties.TryGetValue("title", out var title) && title != null) |
||||||
|
{ |
||||||
|
var titleObj = JsonConvert.DeserializeObject<LocalizableStringInfo>(title.ToString()); |
||||||
|
notificationData.TrySetData("title", titleObj); |
||||||
|
} |
||||||
|
if (notificationData.ExtraProperties.TryGetValue("message", out var message) && message != null) |
||||||
|
{ |
||||||
|
var messageObj = JsonConvert.DeserializeObject<LocalizableStringInfo>(message.ToString()); |
||||||
|
notificationData.TrySetData("message", messageObj); |
||||||
|
} |
||||||
|
|
||||||
|
if (notificationData.ExtraProperties.TryGetValue("description", out var description) && description != null) |
||||||
|
{ |
||||||
|
notificationData.TrySetData("description", JsonConvert.DeserializeObject<LocalizableStringInfo>(description.ToString())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
notificationData = new NotificationData(); |
||||||
|
} |
||||||
|
return notificationData; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications |
||||||
|
{ |
||||||
|
public class NotificationDataMappingDictionary : Dictionary<string, List<NotificationDataMappingDictionaryItem>> |
||||||
|
{ |
||||||
|
public static string DefaultKey { get; set; } = "Default"; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 处理某个通知的数据 |
||||||
|
/// 特定于一个提供程序 |
||||||
|
/// </summary> |
||||||
|
/// <param name="provider"></param> |
||||||
|
/// <param name="name"></param> |
||||||
|
/// <param name="func"></param> |
||||||
|
public void Mapping(string provider, string name, Func<NotificationData, NotificationData> func) |
||||||
|
{ |
||||||
|
if (!ContainsKey(provider)) |
||||||
|
{ |
||||||
|
this[provider] = new List<NotificationDataMappingDictionaryItem>(); |
||||||
|
} |
||||||
|
|
||||||
|
var mapItem = this[provider].FirstOrDefault(item => item.Name.Equals(name)); |
||||||
|
|
||||||
|
if (mapItem == null) |
||||||
|
{ |
||||||
|
this[provider].Add(new NotificationDataMappingDictionaryItem(name, func)); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
mapItem.Replace(func); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 处理所有通知的数据 |
||||||
|
/// 特定于一个提供程序 |
||||||
|
/// </summary> |
||||||
|
/// <param name="provider"></param> |
||||||
|
/// <param name="func"></param> |
||||||
|
public void MappingDefault(string provider, Func<NotificationData, NotificationData> func) |
||||||
|
{ |
||||||
|
Mapping(provider, DefaultKey, func); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 获取需要处理数据的方法 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name"></param> |
||||||
|
/// <param name="provider"></param> |
||||||
|
/// <returns></returns> |
||||||
|
public NotificationDataMappingDictionaryItem GetMapItemOrDefault(string provider, string name) |
||||||
|
{ |
||||||
|
if (ContainsKey(provider)) |
||||||
|
{ |
||||||
|
return this[provider].GetOrNullDefault(name); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
public class NotificationDataMappingDictionaryItem |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 通知名称 |
||||||
|
/// </summary> |
||||||
|
public string Name { get; } |
||||||
|
/// <summary> |
||||||
|
/// 转换方法 |
||||||
|
/// </summary> |
||||||
|
public Func<NotificationData, NotificationData> MappingFunc { get; private set; } |
||||||
|
|
||||||
|
public NotificationDataMappingDictionaryItem(string name, Func<NotificationData, NotificationData> func) |
||||||
|
{ |
||||||
|
Name = name; |
||||||
|
MappingFunc = func; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 替换 |
||||||
|
/// </summary> |
||||||
|
/// <param name="func"></param> |
||||||
|
public void Replace(Func<NotificationData, NotificationData> func) |
||||||
|
{ |
||||||
|
MappingFunc = func; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications |
||||||
|
{ |
||||||
|
public static class NotificationDataMappingDictionaryItemExtensions |
||||||
|
{ |
||||||
|
public static NotificationDataMappingDictionaryItem GetOrNullDefault( |
||||||
|
this IEnumerable<NotificationDataMappingDictionaryItem> items, |
||||||
|
string name) |
||||||
|
{ |
||||||
|
var item = items.FirstOrDefault(i => i.Name.Equals(name)); |
||||||
|
if (item == null) |
||||||
|
{ |
||||||
|
return items.FirstOrDefault(i => i.Name.Equals(NotificationDataMappingDictionary.DefaultKey)); |
||||||
|
} |
||||||
|
return item; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
using JetBrains.Annotations; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Volo.Abp; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知定义 |
||||||
|
/// </summary> |
||||||
|
public class NotificationDefinition |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 通知名称 |
||||||
|
/// </summary> |
||||||
|
[NotNull] |
||||||
|
public string Name { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知显示名称 |
||||||
|
/// </summary> |
||||||
|
[NotNull] |
||||||
|
public ILocalizableString DisplayName { |
||||||
|
get => _displayName; |
||||||
|
set => _displayName = Check.NotNull(value, nameof(value)); |
||||||
|
} |
||||||
|
private ILocalizableString _displayName; |
||||||
|
/// <summary> |
||||||
|
/// 通知说明 |
||||||
|
/// </summary> |
||||||
|
[CanBeNull] |
||||||
|
public ILocalizableString Description { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 允许客户端显示订阅 |
||||||
|
/// </summary> |
||||||
|
public bool AllowSubscriptionToClients { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 存活类型 |
||||||
|
/// </summary> |
||||||
|
public NotificationLifetime NotificationLifetime { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知类型 |
||||||
|
/// </summary> |
||||||
|
public NotificationType NotificationType { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知提供者 |
||||||
|
/// </summary> |
||||||
|
public List<string> Providers { get; } |
||||||
|
/// <summary> |
||||||
|
/// 额外属性 |
||||||
|
/// </summary> |
||||||
|
[NotNull] |
||||||
|
public Dictionary<string, object> Properties { get; } |
||||||
|
|
||||||
|
public NotificationDefinition( |
||||||
|
string name, |
||||||
|
ILocalizableString displayName = null, |
||||||
|
ILocalizableString description = null, |
||||||
|
NotificationType notificationType = NotificationType.Application, |
||||||
|
NotificationLifetime lifetime = NotificationLifetime.Persistent, |
||||||
|
bool allowSubscriptionToClients = false) |
||||||
|
{ |
||||||
|
Name = name; |
||||||
|
DisplayName = displayName ?? new FixedLocalizableString(name); |
||||||
|
Description = description; |
||||||
|
NotificationLifetime = lifetime; |
||||||
|
NotificationType = notificationType; |
||||||
|
AllowSubscriptionToClients = allowSubscriptionToClients; |
||||||
|
|
||||||
|
Providers = new List<string>(); |
||||||
|
Properties = new Dictionary<string, object>(); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual NotificationDefinition WithProviders(params string[] providers) |
||||||
|
{ |
||||||
|
if (!providers.IsNullOrEmpty()) |
||||||
|
{ |
||||||
|
Providers.AddRange(providers); |
||||||
|
} |
||||||
|
|
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual NotificationDefinition WithProperty(string key, object value) |
||||||
|
{ |
||||||
|
Properties[key] = value; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return $"[{nameof(NotificationDefinition)} {Name}]"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
using JetBrains.Annotations; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Volo.Abp; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
public class NotificationDefinitionContext : INotificationDefinitionContext |
||||||
|
{ |
||||||
|
internal Dictionary<string, NotificationGroupDefinition> Groups { get; } |
||||||
|
|
||||||
|
public NotificationDefinitionContext() |
||||||
|
{ |
||||||
|
Groups = new Dictionary<string, NotificationGroupDefinition>(); |
||||||
|
} |
||||||
|
|
||||||
|
public NotificationGroupDefinition AddGroup( |
||||||
|
[NotNull] string name, |
||||||
|
ILocalizableString displayName = null, |
||||||
|
bool allowSubscriptionToClients = true) |
||||||
|
{ |
||||||
|
Check.NotNull(name, nameof(name)); |
||||||
|
|
||||||
|
if (Groups.ContainsKey(name)) |
||||||
|
{ |
||||||
|
throw new AbpException($"There is already an existing notification group with name: {name}"); |
||||||
|
} |
||||||
|
|
||||||
|
return Groups[name] = new NotificationGroupDefinition(name, displayName, allowSubscriptionToClients); |
||||||
|
} |
||||||
|
|
||||||
|
public NotificationGroupDefinition GetGroupOrNull(string name) |
||||||
|
{ |
||||||
|
Check.NotNull(name, nameof(name)); |
||||||
|
|
||||||
|
if (!Groups.ContainsKey(name)) |
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return Groups[name]; |
||||||
|
} |
||||||
|
|
||||||
|
public void RemoveGroup(string name) |
||||||
|
{ |
||||||
|
Check.NotNull(name, nameof(name)); |
||||||
|
|
||||||
|
if (!Groups.ContainsKey(name)) |
||||||
|
{ |
||||||
|
throw new AbpException($"Undefined notification group: '{name}'."); |
||||||
|
} |
||||||
|
|
||||||
|
Groups.Remove(name); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.Options; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using System.Linq; |
||||||
|
using Volo.Abp; |
||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知定义管理者接口 |
||||||
|
/// </summary> |
||||||
|
public class NotificationDefinitionManager : INotificationDefinitionManager, ISingletonDependency |
||||||
|
{ |
||||||
|
protected AbpNotificationsOptions Options { get; } |
||||||
|
|
||||||
|
protected IDictionary<string, NotificationGroupDefinition> NotificationGroupDefinitions => _lazyNotificationGroupDefinitions.Value; |
||||||
|
private readonly Lazy<Dictionary<string, NotificationGroupDefinition>> _lazyNotificationGroupDefinitions; |
||||||
|
|
||||||
|
protected IDictionary<string, NotificationDefinition> NotificationDefinitions => _lazyNotificationDefinitions.Value; |
||||||
|
private readonly Lazy<Dictionary<string, NotificationDefinition>> _lazyNotificationDefinitions; |
||||||
|
|
||||||
|
private readonly IServiceScopeFactory _serviceScopeFactory; |
||||||
|
|
||||||
|
public NotificationDefinitionManager( |
||||||
|
IOptions<AbpNotificationsOptions> optionsAccessor, |
||||||
|
IServiceScopeFactory serviceScopeFactory) |
||||||
|
{ |
||||||
|
_serviceScopeFactory = serviceScopeFactory; |
||||||
|
Options = optionsAccessor.Value; |
||||||
|
|
||||||
|
_lazyNotificationDefinitions = new Lazy<Dictionary<string, NotificationDefinition>>( |
||||||
|
CreateNotificationDefinitions, |
||||||
|
isThreadSafe: true |
||||||
|
); |
||||||
|
|
||||||
|
_lazyNotificationGroupDefinitions = new Lazy<Dictionary<string, NotificationGroupDefinition>>( |
||||||
|
CreateNotificationGroupDefinitions, |
||||||
|
isThreadSafe: true |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual NotificationDefinition Get(string name) |
||||||
|
{ |
||||||
|
Check.NotNull(name, nameof(name)); |
||||||
|
|
||||||
|
var feature = GetOrNull(name); |
||||||
|
|
||||||
|
if (feature == null) |
||||||
|
{ |
||||||
|
throw new AbpException("Undefined notification: " + name); |
||||||
|
} |
||||||
|
|
||||||
|
return feature; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual IReadOnlyList<NotificationDefinition> GetAll() |
||||||
|
{ |
||||||
|
return NotificationDefinitions.Values.ToImmutableList(); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual NotificationDefinition GetOrNull(string name) |
||||||
|
{ |
||||||
|
return NotificationDefinitions.GetOrDefault(name); |
||||||
|
} |
||||||
|
|
||||||
|
public IReadOnlyList<NotificationGroupDefinition> GetGroups() |
||||||
|
{ |
||||||
|
return NotificationGroupDefinitions.Values.ToImmutableList(); |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual Dictionary<string, NotificationDefinition> CreateNotificationDefinitions() |
||||||
|
{ |
||||||
|
var notifications = new Dictionary<string, NotificationDefinition>(); |
||||||
|
|
||||||
|
foreach (var groupDefinition in NotificationGroupDefinitions.Values) |
||||||
|
{ |
||||||
|
foreach (var notification in groupDefinition.Notifications) |
||||||
|
{ |
||||||
|
if (notifications.ContainsKey(notification.Name)) |
||||||
|
{ |
||||||
|
throw new AbpException("Duplicate notification name: " + notification.Name); |
||||||
|
} |
||||||
|
|
||||||
|
notifications[notification.Name] = notification; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return notifications; |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual Dictionary<string, NotificationGroupDefinition> CreateNotificationGroupDefinitions() |
||||||
|
{ |
||||||
|
var context = new NotificationDefinitionContext(); |
||||||
|
|
||||||
|
using (var scope = _serviceScopeFactory.CreateScope()) |
||||||
|
{ |
||||||
|
var providers = Options |
||||||
|
.DefinitionProviders |
||||||
|
.Select(p => scope.ServiceProvider.GetRequiredService(p) as INotificationDefinitionProvider) |
||||||
|
.ToList(); |
||||||
|
|
||||||
|
foreach (var provider in providers) |
||||||
|
{ |
||||||
|
provider.Define(context); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return context.Groups; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知定义提供者抽象类 |
||||||
|
/// </summary> |
||||||
|
public abstract class NotificationDefinitionProvider : INotificationDefinitionProvider, ITransientDependency |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 定义 |
||||||
|
/// </summary> |
||||||
|
/// <param name="context"></param> |
||||||
|
public abstract void Define(INotificationDefinitionContext context); |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
using Sanhe.Abp.RealTime; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using Volo.Abp.EventBus; |
||||||
|
using Volo.Abp.MultiTenancy; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知事件传输对象 |
||||||
|
/// </summary> |
||||||
|
/// <typeparam name="T"></typeparam> |
||||||
|
[Serializable] |
||||||
|
[GenericEventName(Prefix = "abp.realtime.")] |
||||||
|
public class NotificationEto<T> : RealTimeEto<T>, IMultiTenant |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 通知标识 |
||||||
|
/// 自动计算 |
||||||
|
/// </summary> |
||||||
|
public long Id { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 租户 |
||||||
|
/// </summary> |
||||||
|
public Guid? TenantId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知名称 |
||||||
|
/// </summary> |
||||||
|
public string Name { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 创建时间 |
||||||
|
/// </summary> |
||||||
|
public DateTime CreationTime { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 紧急级别 |
||||||
|
/// </summary> |
||||||
|
public NotificationSeverity Severity { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 指定的接收用户信息集合 |
||||||
|
/// </summary> |
||||||
|
/// <remarks> |
||||||
|
/// 注:<br/> |
||||||
|
/// 如果指定了用户列表,应该在事件订阅程序中通过此集合过滤订阅用户<br/> |
||||||
|
/// 如果未指定用户列表,应该在事件订阅程序中过滤所有订阅此通知的用户 |
||||||
|
/// </remarks> |
||||||
|
public List<UserIdentifier> Users { get; set; } = new List<UserIdentifier>(); |
||||||
|
|
||||||
|
public NotificationEto() : base() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public NotificationEto(T data) : base(data) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
using JetBrains.Annotations; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Immutable; |
||||||
|
using Volo.Abp; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知组定义 |
||||||
|
/// </summary> |
||||||
|
public class NotificationGroupDefinition |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 通知组名称 |
||||||
|
/// </summary> |
||||||
|
[NotNull] |
||||||
|
public string Name { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知组显示名称 |
||||||
|
/// </summary> |
||||||
|
[NotNull] |
||||||
|
public ILocalizableString DisplayName { |
||||||
|
get => _displayName; |
||||||
|
set => _displayName = Check.NotNull(value, nameof(value)); |
||||||
|
} |
||||||
|
private ILocalizableString _displayName; |
||||||
|
/// <summary> |
||||||
|
/// 通知组说明 |
||||||
|
/// </summary> |
||||||
|
[CanBeNull] |
||||||
|
public ILocalizableString Description { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 允许客户端显示订阅 |
||||||
|
/// </summary> |
||||||
|
public bool AllowSubscriptionToClients { get; set; } |
||||||
|
|
||||||
|
public IReadOnlyList<NotificationDefinition> Notifications => _notifications.ToImmutableList(); |
||||||
|
private readonly List<NotificationDefinition> _notifications; |
||||||
|
|
||||||
|
protected internal NotificationGroupDefinition( |
||||||
|
string name, |
||||||
|
ILocalizableString displayName = null, |
||||||
|
bool allowSubscriptionToClients = false) |
||||||
|
{ |
||||||
|
Name = name; |
||||||
|
DisplayName = displayName ?? new FixedLocalizableString(Name); |
||||||
|
AllowSubscriptionToClients = allowSubscriptionToClients; |
||||||
|
|
||||||
|
_notifications = new List<NotificationDefinition>(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 添加通知 |
||||||
|
/// </summary> |
||||||
|
/// <param name="name">通知组名称</param> |
||||||
|
/// <param name="displayName">通知组显示名称</param> |
||||||
|
/// <param name="description">通知组说明</param> |
||||||
|
/// <param name="notificationType">通知类型</param> |
||||||
|
/// <param name="lifetime">通知存活时间</param> |
||||||
|
/// <param name="allowSubscriptionToClients">允许客户端显示订阅</param> |
||||||
|
/// <returns></returns> |
||||||
|
public virtual NotificationDefinition AddNotification( |
||||||
|
string name, |
||||||
|
ILocalizableString displayName = null, |
||||||
|
ILocalizableString description = null, |
||||||
|
NotificationType notificationType = NotificationType.Application, |
||||||
|
NotificationLifetime lifetime = NotificationLifetime.Persistent, |
||||||
|
bool allowSubscriptionToClients = false) |
||||||
|
{ |
||||||
|
var notification = new NotificationDefinition( |
||||||
|
name, |
||||||
|
displayName, |
||||||
|
description, |
||||||
|
notificationType, |
||||||
|
lifetime, |
||||||
|
allowSubscriptionToClients |
||||||
|
); |
||||||
|
|
||||||
|
_notifications.Add(notification); |
||||||
|
|
||||||
|
return notification; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知信息 |
||||||
|
/// </summary> |
||||||
|
public class NotificationInfo |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 租户Id |
||||||
|
/// </summary> |
||||||
|
public Guid? TenantId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 名称 |
||||||
|
/// </summary> |
||||||
|
public string Name { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// Id |
||||||
|
/// </summary> |
||||||
|
public string Id { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知数据 |
||||||
|
/// </summary> |
||||||
|
public NotificationData Data { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 创建时间 |
||||||
|
/// </summary> |
||||||
|
public DateTime CreationTime { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知存活时间 |
||||||
|
/// </summary> |
||||||
|
public NotificationLifetime Lifetime { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知类型 |
||||||
|
/// </summary> |
||||||
|
public NotificationType Type { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知严重级别 |
||||||
|
/// </summary> |
||||||
|
public NotificationSeverity Severity { get; set; } |
||||||
|
|
||||||
|
public NotificationInfo() |
||||||
|
{ |
||||||
|
Data = new NotificationData(); |
||||||
|
Lifetime = NotificationLifetime.Persistent; |
||||||
|
Type = NotificationType.Application; |
||||||
|
Severity = NotificationSeverity.Info; |
||||||
|
|
||||||
|
CreationTime = DateTime.Now; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 设置Id |
||||||
|
/// </summary> |
||||||
|
/// <param name="id"></param> |
||||||
|
public void SetId(long id) |
||||||
|
{ |
||||||
|
if (Id.IsNullOrWhiteSpace()) |
||||||
|
{ |
||||||
|
Id = id.ToString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 获取Id |
||||||
|
/// </summary> |
||||||
|
/// <returns></returns> |
||||||
|
public long GetId() |
||||||
|
{ |
||||||
|
return long.Parse(Id); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知存活时间 |
||||||
|
/// 发送之后取消用户订阅,类似于微信小程序 |
||||||
|
/// </summary> |
||||||
|
public enum NotificationLifetime |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 持久化 |
||||||
|
/// </summary> |
||||||
|
Persistent = 0, |
||||||
|
/// <summary> |
||||||
|
/// 一次性 |
||||||
|
/// </summary> |
||||||
|
OnlyOne = 1 |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 内置通知提供者 |
||||||
|
/// </summary> |
||||||
|
public static class NotificationProviderNames |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// SignalR 实时通知 |
||||||
|
/// </summary> |
||||||
|
public const string SignalR = "SignalR"; |
||||||
|
/// <summary> |
||||||
|
/// 短信通知 |
||||||
|
/// </summary> |
||||||
|
public const string Sms = "Sms"; |
||||||
|
/// <summary> |
||||||
|
/// 邮件通知 |
||||||
|
/// </summary> |
||||||
|
public const string Emailing = "Emailing"; |
||||||
|
/// <summary> |
||||||
|
/// 微信小程序模板通知 |
||||||
|
/// </summary> |
||||||
|
public const string WechatMiniProgram = "WeChat.MiniProgram"; |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
using Volo.Abp.Threading; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知发布提供者抽象类 |
||||||
|
/// </summary> |
||||||
|
public abstract class NotificationPublishProvider : INotificationPublishProvider, ITransientDependency |
||||||
|
{ |
||||||
|
public abstract string Name { get; } |
||||||
|
|
||||||
|
protected IServiceProvider ServiceProvider { get; } |
||||||
|
|
||||||
|
protected readonly object ServiceProviderLock = new(); |
||||||
|
|
||||||
|
public ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory); |
||||||
|
private ILoggerFactory _loggerFactory; |
||||||
|
|
||||||
|
protected ILogger Logger => LazyLogger.Value; |
||||||
|
private Lazy<ILogger> LazyLogger => new(() => 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 async Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers) |
||||||
|
{ |
||||||
|
await PublishAsync(notification, identifiers, CancellationTokenProvider.Token); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 重写实现通知发布 |
||||||
|
/// </summary> |
||||||
|
/// <param name="notification"></param> |
||||||
|
/// <param name="identifiers"></param> |
||||||
|
/// <param name="cancellationToken"></param> |
||||||
|
/// <returns></returns> |
||||||
|
protected abstract Task PublishAsync(NotificationInfo notification, IEnumerable<UserIdentifier> identifiers, CancellationToken cancellationToken = default); |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.Options; |
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
public class NotificationPublishProviderManager : INotificationPublishProviderManager, ISingletonDependency |
||||||
|
{ |
||||||
|
public List<INotificationPublishProvider> Providers => _lazyProviders.Value; |
||||||
|
|
||||||
|
protected AbpNotificationsOptions Options { get; } |
||||||
|
|
||||||
|
private readonly Lazy<List<INotificationPublishProvider>> _lazyProviders; |
||||||
|
|
||||||
|
public NotificationPublishProviderManager( |
||||||
|
IServiceProvider serviceProvider, |
||||||
|
IOptions<AbpNotificationsOptions> optionsAccessor) |
||||||
|
{ |
||||||
|
Options = optionsAccessor.Value; |
||||||
|
|
||||||
|
_lazyProviders = new Lazy<List<INotificationPublishProvider>>( |
||||||
|
() => Options |
||||||
|
.PublishProviders |
||||||
|
.Select(type => serviceProvider.GetRequiredService(type) as INotificationPublishProvider) |
||||||
|
.ToList(), |
||||||
|
true |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 读取状态 |
||||||
|
/// </summary> |
||||||
|
public enum NotificationReadState |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 已读 |
||||||
|
/// </summary> |
||||||
|
Read = 0, |
||||||
|
/// <summary> |
||||||
|
/// 未读 |
||||||
|
/// </summary> |
||||||
|
UnRead = 1 |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 严重级别 |
||||||
|
/// </summary> |
||||||
|
public enum NotificationSeverity : sbyte |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 成功 |
||||||
|
/// </summary> |
||||||
|
Success = 0, |
||||||
|
/// <summary> |
||||||
|
/// 信息 |
||||||
|
/// </summary> |
||||||
|
Info = 10, |
||||||
|
/// <summary> |
||||||
|
/// 警告 |
||||||
|
/// </summary> |
||||||
|
Warn = 20, |
||||||
|
/// <summary> |
||||||
|
/// 错误 |
||||||
|
/// </summary> |
||||||
|
Error = 30, |
||||||
|
/// <summary> |
||||||
|
/// 致命错误 |
||||||
|
/// </summary> |
||||||
|
Fatal = 40 |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知订阅信息 |
||||||
|
/// </summary> |
||||||
|
public class NotificationSubscriptionInfo |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 租户Id |
||||||
|
/// </summary> |
||||||
|
public Guid? TenantId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 用户Id |
||||||
|
/// </summary> |
||||||
|
public Guid UserId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 用户名 |
||||||
|
/// </summary> |
||||||
|
public string UserName { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 通知名 |
||||||
|
/// </summary> |
||||||
|
public string NotificationName { get; set; } |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 通知类型 |
||||||
|
/// </summary> |
||||||
|
public enum NotificationType |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 应用(对应租户) |
||||||
|
/// </summary> |
||||||
|
Application = 0, |
||||||
|
/// <summary> |
||||||
|
/// 系统(对应宿主) |
||||||
|
/// </summary> |
||||||
|
System = 10, |
||||||
|
/// <summary> |
||||||
|
/// 用户(对应用户) |
||||||
|
/// </summary> |
||||||
|
User = 20 |
||||||
|
} |
@ -0,0 +1,189 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Volo.Abp.DependencyInjection; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 空实现通知相关储存处 |
||||||
|
/// </summary> |
||||||
|
[Dependency(TryRegister = true)] |
||||||
|
public class NullNotificationStore : INotificationStore, ISingletonDependency |
||||||
|
{ |
||||||
|
public Task ChangeUserNotificationReadStateAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
long notificationId, |
||||||
|
NotificationReadState readState, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task DeleteAllUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task DeleteNotificationAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task DeleteNotificationAsync( |
||||||
|
int batchCount, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task DeleteUserNotificationAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
long notificationId, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task DeleteUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task DeleteUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task<NotificationInfo> GetNotificationOrNullAsync( |
||||||
|
Guid? tenantId, |
||||||
|
long notificationId, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new NotificationInfo()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string notificationName, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new List<NotificationSubscriptionInfo>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<List<NotificationInfo>> GetUserNotificationsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
NotificationReadState? readState = null, |
||||||
|
int maxResultCount = 10, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new List<NotificationInfo>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<int> GetUserNotificationsCountAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string filter = "", |
||||||
|
NotificationReadState? readState = null, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(0); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<List<NotificationInfo>> GetUserNotificationsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string filter = "", |
||||||
|
string sorting = nameof(NotificationInfo.CreationTime), |
||||||
|
NotificationReadState? readState = null, |
||||||
|
int skipCount = 1, |
||||||
|
int maxResultCount = 10, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new List<NotificationInfo>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new List<NotificationSubscriptionInfo>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync( |
||||||
|
Guid? tenantId, |
||||||
|
string userName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new List<NotificationSubscriptionInfo>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task InsertNotificationAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task InsertUserNotificationAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
Guid userId, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task InsertUserNotificationsAsync( |
||||||
|
NotificationInfo notification, |
||||||
|
IEnumerable<Guid> userIds, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task InsertUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
UserIdentifier identifier, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task InsertUserSubscriptionAsync( |
||||||
|
Guid? tenantId, |
||||||
|
IEnumerable<UserIdentifier> identifiers, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.CompletedTask; |
||||||
|
} |
||||||
|
|
||||||
|
public Task<bool> IsSubscribedAsync( |
||||||
|
Guid? tenantId, |
||||||
|
Guid userId, |
||||||
|
string notificationName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(false); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
using System; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Notifications; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 用户信息 |
||||||
|
/// </summary> |
||||||
|
public class UserIdentifier |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 用户标识 |
||||||
|
/// </summary> |
||||||
|
public Guid UserId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 用户名 |
||||||
|
/// </summary> |
||||||
|
public string UserName { get; set; } |
||||||
|
|
||||||
|
public UserIdentifier(Guid userId, string userName) |
||||||
|
{ |
||||||
|
UserId = userId; |
||||||
|
UserName = userName; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue