Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder)
}

builder.WebhookEvents().AddCms(true, webhookPayloadType);

builder.WebhookPayloadProviders();
builder.ContentTypeFilters();
}

Expand Down Expand Up @@ -269,4 +269,7 @@ public static ContentIndexHandlerCollectionBuilder ContentIndexHandlers(this IUm
/// <param name="builder">The builder.</param>
public static ContentTypeFilterCollectionBuilder ContentTypeFilters(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder<ContentTypeFilterCollectionBuilder>();

public static WebhookPayloadProviderCollectionBuilder WebhookPayloadProviders(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder<WebhookPayloadProviderCollectionBuilder>();
}
8 changes: 8 additions & 0 deletions src/Umbraco.Core/Webhooks/IWebhookPayloadProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Core.Webhooks;

public interface IWebhookPayloadProvider
{
bool CanHandle(WebhookContext ctx);

object BuildPayload(WebhookContext ctx);
}
9 changes: 9 additions & 0 deletions src/Umbraco.Core/Webhooks/WebhookContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Umbraco.Cms.Core.Models;

namespace Umbraco.Cms.Core.Webhooks;
public sealed record WebhookContext(
Uri Endpoint,
string EventAlias,
object Notification,
IWebhook Webhook
);
42 changes: 41 additions & 1 deletion src/Umbraco.Core/Webhooks/WebhookEventBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System.Net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
Expand All @@ -15,6 +18,8 @@ public abstract class WebhookEventBase<TNotification> : IWebhookEvent, INotifica
{
private readonly IServerRoleAccessor _serverRoleAccessor;

private readonly WebhookPayloadProviderCollection _webhookPayloadProviderCollection;

public abstract string Alias { get; }

public string EventName { get; set; }
Expand All @@ -34,11 +39,25 @@ protected WebhookEventBase(
IWebhookService webhookService,
IOptionsMonitor<WebhookSettings> webhookSettings,
IServerRoleAccessor serverRoleAccessor)
: this(
webhookFiringService,
webhookService, webhookSettings, serverRoleAccessor,
StaticServiceProvider.Instance.GetRequiredService<WebhookPayloadProviderCollection>())
{
}


protected WebhookEventBase(
IWebhookFiringService webhookFiringService,
IWebhookService webhookService,
IOptionsMonitor<WebhookSettings> webhookSettings,
IServerRoleAccessor serverRoleAccessor,
WebhookPayloadProviderCollection webhookPayloadProviderCollection)
{
WebhookFiringService = webhookFiringService;
WebhookService = webhookService;
_serverRoleAccessor = serverRoleAccessor;
_webhookPayloadProviderCollection = webhookPayloadProviderCollection;

// assign properties based on the attribute, if it is found
WebhookEventAttribute? attribute = GetType().GetCustomAttribute<WebhookEventAttribute>(false);
Expand All @@ -62,8 +81,29 @@ public virtual async Task ProcessWebhooks(TNotification notification, IEnumerabl
continue;
}

await WebhookFiringService.FireAsync(webhook, Alias, ConvertNotificationToRequestPayload(notification), cancellationToken);
if (!Uri.TryCreate(webhook.Url, UriKind.Absolute, out Uri? endPoint))
{
continue;
}
var ctx = new WebhookContext(endPoint, Alias, notification, webhook);

IWebhookPayloadProvider? provider = GetPayloadProviderProvider(notification, webhook);
var payload = provider is null
? ConvertNotificationToRequestPayload(notification)
: provider.BuildPayload(ctx);

await WebhookFiringService.FireAsync(webhook, Alias, payload, cancellationToken);
}
}

protected IWebhookPayloadProvider? GetPayloadProviderProvider(TNotification notification, IWebhook webhook)
{
if (!Uri.TryCreate(webhook.Url, UriKind.Absolute, out Uri? endPoint))
{
return null;
}
var ctx = new WebhookContext(endPoint, Alias, notification, webhook);
return _webhookPayloadProviderCollection.FirstOrDefault(x => x.CanHandle(ctx));
}

/// <summary>
Expand Down
15 changes: 14 additions & 1 deletion src/Umbraco.Core/Webhooks/WebhookEventContentBase.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net;
using Microsoft.Extensions.Options;

using Umbraco.Cms.Core.Configuration.Models;
Expand Down Expand Up @@ -37,7 +38,19 @@
continue;
}

await WebhookFiringService.FireAsync(webhook, Alias, ConvertEntityToRequestPayload(entity), cancellationToken);
if (!Uri.TryCreate(webhook.Url, UriKind.Absolute, out Uri? endPoint))
{
continue;
}

var ctx = new WebhookContext(endPoint, Alias, notification, webhook);

IWebhookPayloadProvider? provider = GetPayloadProviderProvider(notification, webhook);
var payload = provider is null
? ConvertEntityToRequestPayload(entity)
: provider.BuildPayload(ctx);

await WebhookFiringService.FireAsync(webhook, Alias, payload, cancellationToken);

Check warning on line 53 in src/Umbraco.Core/Webhooks/WebhookEventContentBase.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Complex Method

ProcessWebhooks has a cyclomatic complexity of 11, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/Umbraco.Core/Webhooks/WebhookPayloadProviderBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;

namespace Umbraco.Cms.Core.Webhooks;

public abstract class WebhookPayloadProviderBase<TNotification> : IWebhookPayloadProvider where TNotification : class, INotification
{
public bool CanHandle(WebhookContext ctx) => ctx.Notification is TNotification n && CanHandle(ctx.Endpoint, ctx.EventAlias, n, ctx.Webhook);

object IWebhookPayloadProvider.BuildPayload(WebhookContext ctx)
=> BuildPayload((TNotification)ctx.Notification, ctx.Endpoint, ctx.EventAlias, ctx.Webhook);

protected abstract bool CanHandle(Uri endpoint, string eventAlias, TNotification notification, IWebhook webhook);
protected abstract object BuildPayload(TNotification notification, Uri endpoint, string eventAlias, IWebhook webhook);
}
5 changes: 5 additions & 0 deletions src/Umbraco.Core/Webhooks/WebhookPayloadProviderCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Umbraco.Cms.Core.Composing;

namespace Umbraco.Cms.Core.Webhooks;

public class WebhookPayloadProviderCollection(Func<IEnumerable<IWebhookPayloadProvider>> items) : BuilderCollectionBase<IWebhookPayloadProvider>(items);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Umbraco.Cms.Core.Composing;

namespace Umbraco.Cms.Core.Webhooks;

public class WebhookPayloadProviderCollectionBuilder : LazyCollectionBuilderBase<WebhookPayloadProviderCollectionBuilder, WebhookPayloadProviderCollection, IWebhookPayloadProvider>
{
protected override WebhookPayloadProviderCollectionBuilder This => this;
}
12 changes: 12 additions & 0 deletions src/Umbraco.Web.UI/MyComposer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Webhooks;

namespace Umbraco.Cms.Web.UI;

public class MyComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<WebhookPayloadProviderCollectionBuilder>().Add<MyCustomWebhookPayloadProvider>();
}
}
20 changes: 20 additions & 0 deletions src/Umbraco.Web.UI/MyCustomWebhookPayloadProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Webhooks;

namespace Umbraco.Cms.Web.UI;

public class MyCustomWebhookPayloadProvider : WebhookPayloadProviderBase<ContentPublishedNotification>
{
protected override bool CanHandle(Uri endpoint, string eventAlias, ContentPublishedNotification notification,
IWebhook webhook)
{
var host = endpoint.Host.ToLowerInvariant();
var isWebhookSite = host.Contains("webhook.site");
return isWebhookSite;
}

protected override object BuildPayload(ContentPublishedNotification notification, Uri endpoint, string eventAlias,
IWebhook webhook)
=> new {messgage = "Published new Content"};
}
Loading