From c834ea543e159eaa8280e6ded5fa3e3457b90462 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 15 Oct 2025 14:59:25 +0800 Subject: [PATCH] feat(notifications): add webhook notification - add webhook notification package - add wecom webhook resolver --- .../WeChatWorkNotificationPublishProvider.cs | 46 ++---------- .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++++++++ ...p.Notifications.Webhook.WeChat.Work.csproj | 25 +++++++ ...AbpNotificationsWebhookWeChatWorkModule.cs | 18 +++++ ...bpNotificationsWebhookWeChatWorkOptions.cs | 15 ++++ ...eChatWorkWebhookNotificationContributor.cs | 74 +++++++++++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++++++++ .../LINGYUN.Abp.Notifications.Webhook.csproj | 21 ++++++ .../Webhook/AbpNotificationsWebhookModule.cs | 18 +++++ .../Webhook/AbpNotificationsWebhookOptions.cs | 11 +++ .../Webhook/IWebhookNotificationContext.cs | 9 +++ .../IWebhookNotificationContributor.cs | 8 ++ .../Webhook/WebhookNotificationContext.cs | 18 +++++ .../Webhook/WebhookNotificationData.cs | 16 ++++ .../WebhookNotificationPublishProvider.cs | 49 ++++++++++++ 17 files changed, 355 insertions(+), 39 deletions(-) create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xml create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xsd create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN.Abp.Notifications.Webhook.WeChat.Work.csproj create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkModule.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkOptions.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/WeChatWorkWebhookNotificationContributor.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xml create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xsd create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN.Abp.Notifications.Webhook.csproj create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookModule.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookOptions.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContext.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContributor.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationContext.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationData.cs create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs index ae84a648b..680fa047b 100644 --- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.WeChat.Work/LINGYUN/Abp/Notifications/WeChat/Work/WeChatWorkNotificationPublishProvider.cs @@ -55,40 +55,13 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider } var notificationData = await NotificationDataSerializer.ToStandard(notification.Data); var toTag = notification.Data.GetTagOrNull() ?? notificationDefine?.GetTagOrNull(); - if (!toTag.IsNullOrWhiteSpace()) - { - // 指定发送标签 - await PublishToAgentAsync( - agentId, - notification, - notificationData.Title, - notificationData.Message, - notificationData.Description, - toTag: toTag, - cancellationToken: cancellationToken); - return; - } var toParty = notification.Data.GetPartyOrNull() ?? notificationDefine?.GetPartyOrNull(); - if (!toParty.IsNullOrWhiteSpace()) - { - // 指定发送部门 - await PublishToAgentAsync( - agentId, - notification, - notificationData.Title, - notificationData.Message, - notificationData.Description, - toParty: toParty, - cancellationToken: cancellationToken); - return; - } + var toUsers = await WeChatWorkInternalUserFinder.FindUserIdentifierListAsync(identifiers.Select(id => id.UserId)); - var findUserList = await WeChatWorkInternalUserFinder - .FindUserIdentifierListAsync(identifiers.Select(id => id.UserId)); - - if (findUserList.Count == 0) + if (toUsers.IsNullOrEmpty() && toTag.IsNullOrWhiteSpace() && toParty.IsNullOrWhiteSpace()) { - Logger.LogWarning("Unable to send work weixin messages because findUserList is empty."); + // touser、toparty、totag不能同时为空:https://developer.work.weixin.qq.com/document/path/90236 + Logger.LogWarning("Unable to send work weixin messages because The recipient/department/label cannot be empty simultaneously."); return; } @@ -99,7 +72,9 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider notificationData.Title, notificationData.Message, notificationData.Description, - toUser: findUserList.JoinAsString("|"), + toTag: toTag, + toParty: toParty, + toUser: toUsers.JoinAsString("|"), cancellationToken: cancellationToken); } @@ -137,13 +112,6 @@ public class WeChatWorkNotificationPublishProvider : NotificationPublishProvider return; } - if (toUser.IsNullOrWhiteSpace() && toTag.IsNullOrWhiteSpace() && toParty.IsNullOrWhiteSpace()) - { - // touser、toparty、totag不能同时为空:https://developer.work.weixin.qq.com/document/path/90236 - Logger.LogWarning("Unable to send work weixin messages because The recipient/department/label cannot be empty simultaneously."); - return; - } - message.ToUser = toUser; message.ToTag = toTag; message.ToParty = toParty; diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xml b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xsd b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN.Abp.Notifications.Webhook.WeChat.Work.csproj b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN.Abp.Notifications.Webhook.WeChat.Work.csproj new file mode 100644 index 000000000..c3ab836ae --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN.Abp.Notifications.Webhook.WeChat.Work.csproj @@ -0,0 +1,25 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + LINGYUN.Abp.Notifications.Webhook.WeChat.Work + LINGYUN.Abp.Notifications.Webhook.WeChat.Work + false + false + false + + + + + + + + + + + + + diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkModule.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkModule.cs new file mode 100644 index 000000000..0879e9be4 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkModule.cs @@ -0,0 +1,18 @@ +using LINGYUN.Abp.WeChat.Work; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.Webhook.WeChat.Work; + +[DependsOn( + typeof(AbpNotificationsWebhookModule), + typeof(AbpWeChatWorkModule))] +public class AbpNotificationsWebhookWeChatWorkModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Contributors.Add(new WeChatWorkWebhookNotificationContributor()); + }); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkOptions.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkOptions.cs new file mode 100644 index 000000000..d8e9cf700 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/AbpNotificationsWebhookWeChatWorkOptions.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.Notifications.Webhook.WeChat.Work; +public class AbpNotificationsWebhookWeChatWorkOptions +{ + /// + /// 发送Markdown类型通知时是否使用MarkdownV2格式通知, 默认: true + /// + /// + /// 详见: https://developer.work.weixin.qq.com/document/path/99110#markdown-v2%E7%B1%BB%E5%9E%8B + /// + public bool UseMarkdownV2 { get; set; } + public AbpNotificationsWebhookWeChatWorkOptions() + { + UseMarkdownV2 = true; + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/WeChatWorkWebhookNotificationContributor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/WeChatWorkWebhookNotificationContributor.cs new file mode 100644 index 000000000..a3d702b23 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook.WeChat.Work/LINGYUN/Abp/Notifications/Webhook/WeChat/Work/WeChatWorkWebhookNotificationContributor.cs @@ -0,0 +1,74 @@ +using LINGYUN.Abp.WeChat.Work.Messages; +using LINGYUN.Abp.WeChat.Work.Messages.Models; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Webhook.WeChat.Work; +public class WeChatWorkWebhookNotificationContributor : IWebhookNotificationContributor +{ + public string Name => "WeChat.Work"; + + public async virtual Task ContributeAsync(IWebhookNotificationContext context) + { + var options = context.ServiceProvider.GetRequiredService>().Value; + var notificationDataSerializer = context.ServiceProvider.GetRequiredService(); + + var data = await notificationDataSerializer.ToStandard(context.Notification.Data); + var notificationContent = data.Message; + + try + { + if (context.Notification.ContentType == NotificationContentType.Html) + { + notificationContent = CommonMark.CommonMarkConverter.Convert(notificationContent); + } + + WeChatWorkWebhookMessage message; + + switch (context.Notification.ContentType) + { + case NotificationContentType.Text: + message = new WeChatWorkWebhookTextMessage( + new WebhookTextMessage(notificationContent)); + break; + case NotificationContentType.Html: + case NotificationContentType.Markdown: + if (options.UseMarkdownV2) + { + message = new WeChatWorkWebhookMarkdownV2Message( + new WebhookMarkdownV2Message(notificationContent)); + } + else + { + message = new WeChatWorkWebhookMarkdownMessage( + new WebhookMarkdownMessage(notificationContent)); + } + break; + default: + return; + } + + if (message == null) + { + context.ServiceProvider + .GetService>() + ?.LogWarning("Unable to send work weixin messages because WeChatWorkMessage is null."); + return; + } + + context.Webhook = new WebhookNotificationData( + context.Notification.Name, + message); + context.Handled = true; + } + catch (Exception ex) + { + context.ServiceProvider + .GetService>() + ?.LogWarning("Failed to parse the content of the Webhook message: {message}", ex.Message); + } + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xml b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xsd b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN.Abp.Notifications.Webhook.csproj b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN.Abp.Notifications.Webhook.csproj new file mode 100644 index 000000000..2ca416a4c --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN.Abp.Notifications.Webhook.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + LINGYUN.Abp.Notifications.Webhook + LINGYUN.Abp.Notifications.Webhook + false + false + false + + + + + + + + + diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookModule.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookModule.cs new file mode 100644 index 000000000..c11621169 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookModule.cs @@ -0,0 +1,18 @@ +using LINGYUN.Abp.Webhooks; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.Webhook; + +[DependsOn( + typeof(AbpNotificationsCoreModule), + typeof(AbpWebhooksModule))] +public class AbpNotificationsWebhookModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.PublishProviders.Add(); + }); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookOptions.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookOptions.cs new file mode 100644 index 000000000..5561b9f46 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/AbpNotificationsWebhookOptions.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications.Webhook; +public class AbpNotificationsWebhookOptions +{ + public IList Contributors { get; } + public AbpNotificationsWebhookOptions() + { + Contributors = new List(); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContext.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContext.cs new file mode 100644 index 000000000..f23a8b129 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContext.cs @@ -0,0 +1,9 @@ +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications.Webhook; +public interface IWebhookNotificationContext : IServiceProviderAccessor +{ + WebhookNotificationData Webhook { get; set; } + NotificationInfo Notification { get; } + bool Handled { get; set; } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContributor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContributor.cs new file mode 100644 index 000000000..757ff88fd --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/IWebhookNotificationContributor.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Webhook; +public interface IWebhookNotificationContributor +{ + string Name { get; } + Task ContributeAsync(IWebhookNotificationContext context); +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationContext.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationContext.cs new file mode 100644 index 000000000..f8d427640 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationContext.cs @@ -0,0 +1,18 @@ +using System; + +namespace LINGYUN.Abp.Notifications.Webhook; +public class WebhookNotificationContext : IWebhookNotificationContext +{ + public IServiceProvider ServiceProvider { get; } + public NotificationInfo Notification { get; } + public WebhookNotificationData Webhook { get; set; } + public bool Handled { get; set; } + public WebhookNotificationContext(IServiceProvider ServiceProvider, NotificationInfo notification) + { + Notification = notification; + } + public bool HasResolved() + { + return Handled || Webhook != null; + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationData.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationData.cs new file mode 100644 index 000000000..561d6324a --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationData.cs @@ -0,0 +1,16 @@ +using LINGYUN.Abp.Webhooks; +using Volo.Abp; + +namespace LINGYUN.Abp.Notifications.Webhook; +public class WebhookNotificationData +{ + public string WebhookName { get; } + public object Data { get; } + public bool SendExactSameData { get; set; } + public WebhookHeader Headers { get; set; } + public WebhookNotificationData(string webhookName, object data) + { + WebhookName = Check.NotNullOrWhiteSpace(webhookName, nameof(webhookName)); + Data = Check.NotNull(data, nameof(data)); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs new file mode 100644 index 000000000..a7441d328 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Webhook/LINGYUN/Abp/Notifications/Webhook/WebhookNotificationPublishProvider.cs @@ -0,0 +1,49 @@ +using LINGYUN.Abp.Webhooks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Webhook; +public class WebhookNotificationPublishProvider : NotificationPublishProvider +{ + public const string ProviderName = "Webhook"; + public override string Name => ProviderName; + + private readonly IServiceScopeFactory _serviceScopeFactory; + private readonly AbpNotificationsWebhookOptions _options; + private readonly IWebhookPublisher _webhookPublisher; + + public WebhookNotificationPublishProvider( + IServiceScopeFactory serviceScopeFactory, + IWebhookPublisher webhookPublisher, + IOptions options) + { + _serviceScopeFactory = serviceScopeFactory; + _webhookPublisher = webhookPublisher; + _options = options.Value; + } + + protected override async Task PublishAsync(NotificationInfo notification, IEnumerable identifiers, CancellationToken cancellationToken = default) + { + using var scope = _serviceScopeFactory.CreateScope(); + + foreach (var contributor in _options.Contributors) + { + var context = new WebhookNotificationContext(scope.ServiceProvider, notification); + + await contributor.ContributeAsync(context); + + if (context.HasResolved()) + { + await _webhookPublisher.PublishAsync( + context.Webhook.WebhookName, + context.Webhook.Data, + notification.TenantId, + context.Webhook.SendExactSameData, + context.Webhook.Headers); + } + } + } +}