Skip to content

Commit 2297404

Browse files
MigaroezAndyButlandkjac
committed
Normalize webhook payloads (#19110)
Co-authored-by: Andy Butland <[email protected]> Co-authored-by: Kenn Jacobsen <[email protected]>
1 parent 0d080bd commit 2297404

File tree

170 files changed

+3396
-353
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+3396
-353
lines changed

src/Umbraco.Core/Configuration/Models/WebhookSettings.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.ComponentModel;
1+
using System.ComponentModel;
2+
using Umbraco.Cms.Core.Webhooks;
23

34
namespace Umbraco.Cms.Core.Configuration.Models;
45

@@ -10,6 +11,7 @@ public class WebhookSettings
1011
internal const string StaticPeriod = "00:00:10";
1112
private const bool StaticEnableLoggingCleanup = true;
1213
private const int StaticKeepLogsForDays = 30;
14+
private const WebhookPayloadType StaticPayloadType = Constants.Webhooks.DefaultPayloadType;
1315

1416

1517
/// <summary>
@@ -63,4 +65,16 @@ public class WebhookSettings
6365
/// </remarks>
6466
[DefaultValue(StaticKeepLogsForDays)]
6567
public int KeepLogsForDays { get; set; } = StaticKeepLogsForDays;
68+
69+
/// <summary>
70+
/// Gets or sets a value indicating the type of payload used for sending webhooks
71+
/// </summary>
72+
/// <remarks>
73+
/// <para>
74+
/// By default, Legacy payloads are used see <see cref="WebhookPayloadType"/> for more info.
75+
/// This default will change to minimal starting from v17.
76+
/// </para>
77+
/// </remarks>
78+
[DefaultValue(StaticPayloadType)]
79+
public WebhookPayloadType PayloadType { get; set; } = StaticPayloadType;
6680
}

src/Umbraco.Core/Constants-Configuration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public static class Configuration
6161
public const string ConfigDataTypes = ConfigPrefix + "DataTypes";
6262
public const string ConfigPackageManifests = ConfigPrefix + "PackageManifests";
6363
public const string ConfigWebhook = ConfigPrefix + "Webhook";
64+
public const string ConfigWebhookPayloadType = ConfigWebhook + ":PayloadType";
6465
public const string ConfigCache = ConfigPrefix + "Cache";
6566

6667
public static class NamedOptions
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Umbraco.Cms.Core.Webhooks;
2+
3+
namespace Umbraco.Cms.Core;
4+
5+
public static partial class Constants
6+
{
7+
public static class Webhooks
8+
{
9+
/// <summary>
10+
/// Gets the default webhook payload type.
11+
/// </summary>
12+
/// <remarks>
13+
/// Currently, the default payload type is <see cref="WebhookPayloadType.Legacy"/> for backward compatibility until Umbraco 17.
14+
/// From Umbraco 17 this will be changed to <see cref="WebhookPayloadType.Minimal"/>.
15+
/// </remarks>
16+
public const WebhookPayloadType DefaultPayloadType = WebhookPayloadType.Legacy;
17+
}
18+
}

src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
using Microsoft.Extensions.Configuration;
12
using Umbraco.Cms.Core.Actions;
23
using Umbraco.Cms.Core.Cache;
34
using Umbraco.Cms.Core.Composing;
5+
using Umbraco.Cms.Core.Configuration.Models;
46
using Umbraco.Cms.Core.DeliveryApi;
57
using Umbraco.Cms.Core.DynamicRoot.Origin;
68
using Umbraco.Cms.Core.DynamicRoot.QuerySteps;
@@ -91,7 +93,15 @@ internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder)
9193
builder.FilterHandlers().Add(() => builder.TypeLoader.GetTypes<IFilterHandler>());
9294
builder.SortHandlers().Add(() => builder.TypeLoader.GetTypes<ISortHandler>());
9395
builder.ContentIndexHandlers().Add(() => builder.TypeLoader.GetTypes<IContentIndexHandler>());
94-
builder.WebhookEvents().AddCms(true);
96+
97+
WebhookPayloadType webhookPayloadType = Constants.Webhooks.DefaultPayloadType;
98+
if (builder.Config.GetSection(Constants.Configuration.ConfigWebhookPayloadType).Value is not null)
99+
{
100+
webhookPayloadType = builder.Config.GetValue<WebhookPayloadType>(Constants.Configuration.ConfigWebhookPayloadType);
101+
}
102+
103+
builder.WebhookEvents().AddCms(true, webhookPayloadType);
104+
95105
builder.ContentTypeFilters();
96106
}
97107

src/Umbraco.Core/Webhooks/Events/Content/ContentCopiedWebhookEvent.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ public ContentCopiedWebhookEvent(
2828
{
2929
return new
3030
{
31-
notification.Copy,
32-
notification.Original,
33-
notification.ParentId,
34-
notification.RelateToOriginal
31+
Id = notification.Copy.Key,
32+
Original = notification.Original.Key,
33+
Parent = notification.ParentKey,
34+
notification.RelateToOriginal,
3535
};
3636
}
3737
}

src/Umbraco.Core/Webhooks/Events/Content/ContentDeletedBlueprintWebhookEvent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ public ContentDeletedBlueprintWebhookEvent(
2828
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentDeletedBlueprintNotification notification) =>
2929
notification.DeletedBlueprints;
3030

31-
protected override object ConvertEntityToRequestPayload(IContent entity) => entity;
31+
protected override object ConvertEntityToRequestPayload(IContent entity) => new DefaultPayloadModel { Id = entity.Key };
3232
}
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -9,17 +10,21 @@ namespace Umbraco.Cms.Core.Webhooks.Events;
910
[WebhookEvent("Content Versions Deleted", Constants.WebhookEvents.Types.Content)]
1011
public class ContentDeletedVersionsWebhookEvent : WebhookEventBase<ContentDeletedVersionsNotification>
1112
{
13+
private readonly IIdKeyMap _idKeyMap;
14+
1215
public ContentDeletedVersionsWebhookEvent(
1316
IWebhookFiringService webhookFiringService,
1417
IWebhookService webhookService,
1518
IOptionsMonitor<WebhookSettings> webhookSettings,
16-
IServerRoleAccessor serverRoleAccessor)
19+
IServerRoleAccessor serverRoleAccessor,
20+
IIdKeyMap idKeyMap)
1721
: base(
1822
webhookFiringService,
1923
webhookService,
2024
webhookSettings,
2125
serverRoleAccessor)
2226
{
27+
_idKeyMap = idKeyMap;
2328
}
2429

2530
public override string Alias => Constants.WebhookEvents.Aliases.ContentDeletedVersions;
@@ -28,10 +33,10 @@ public ContentDeletedVersionsWebhookEvent(
2833
{
2934
return new
3035
{
31-
notification.Id,
36+
Id = _idKeyMap.GetKeyForId(notification.Id, UmbracoObjectTypes.Document).Result,
3237
notification.DeletePriorVersions,
3338
notification.SpecificVersion,
34-
notification.DateToRetain
39+
notification.DateToRetain,
3540
};
3641
}
3742
}

src/Umbraco.Core/Webhooks/Events/Content/ContentDeletedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ public ContentDeletedWebhookEvent(
2828
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentDeletedNotification notification) =>
2929
notification.DeletedEntities;
3030

31-
protected override object ConvertEntityToRequestPayload(IContent entity) => new DefaultPayloadModel { Id = entity.Key };
31+
protected override object ConvertEntityToRequestPayload(IContent entity)
32+
=> new DefaultPayloadModel { Id = entity.Key };
3233
}

src/Umbraco.Core/Webhooks/Events/Content/ContentEmptiedRecycleBinWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ public ContentEmptiedRecycleBinWebhookEvent(
3434
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentEmptiedRecycleBinNotification notification) =>
3535
notification.DeletedEntities;
3636

37-
protected override object? ConvertEntityToRequestPayload(IContent entity) => entity;
37+
protected override object? ConvertEntityToRequestPayload(IContent entity)
38+
=> new DefaultPayloadModel { Id = entity.Key };
3839
}

src/Umbraco.Core/Webhooks/Events/Content/ContentMovedToRecycleBinWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -25,5 +26,5 @@ public ContentMovedToRecycleBinWebhookEvent(
2526
public override string Alias => Constants.WebhookEvents.Aliases.ContentMovedToRecycleBin;
2627

2728
public override object? ConvertNotificationToRequestPayload(ContentMovedToRecycleBinNotification notification)
28-
=> notification.MoveInfoCollection;
29+
=> notification.MoveInfoCollection.Select(moveInfo => new DefaultPayloadModel { Id = moveInfo.Entity.Key });
2930
}

src/Umbraco.Core/Webhooks/Events/Content/ContentMovedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -25,5 +26,5 @@ public ContentMovedWebhookEvent(
2526
public override string Alias => Constants.WebhookEvents.Aliases.ContentMoved;
2627

2728
public override object? ConvertNotificationToRequestPayload(ContentMovedNotification notification)
28-
=> notification.MoveInfoCollection;
29+
=> notification.MoveInfoCollection.Select(moveInfo => new DefaultPayloadModel { Id = moveInfo.Entity.Key });
2930
}

src/Umbraco.Core/Webhooks/Events/Content/ContentPublishedWebhookEvent.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Umbraco.Cms.Core.PublishedCache;
88
using Umbraco.Cms.Core.Services;
99
using Umbraco.Cms.Core.Sync;
10+
using Umbraco.Extensions;
1011

1112
namespace Umbraco.Cms.Core.Webhooks.Events;
1213

@@ -38,8 +39,13 @@ public ContentPublishedWebhookEvent(
3839
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities;
3940

4041
protected override object? ConvertEntityToRequestPayload(IContent entity)
41-
{
42-
IPublishedContent? publishedContent = _publishedContentCache.GetById(entity.Key);
43-
return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent);
44-
}
42+
=> new
43+
{
44+
Id = entity.Key,
45+
Cultures = entity.PublishCultureInfos?.Values.Select(cultureInfo => new
46+
{
47+
cultureInfo.Culture,
48+
cultureInfo.Date,
49+
}),
50+
};
4551
}

src/Umbraco.Core/Webhooks/Events/Content/ContentRolledBack.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,5 @@ protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentRoll
3939
new List<IContent> { notification.Entity };
4040

4141
protected override object? ConvertEntityToRequestPayload(IContent entity)
42-
{
43-
// Get preview/saved version of content for a rollback
44-
IPublishedContent? publishedContent = _contentCache.GetById(true, entity.Key);
45-
return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent);
46-
}
42+
=> new DefaultPayloadModel { Id = entity.Key };
4743
}

src/Umbraco.Core/Webhooks/Events/Content/ContentSavedBlueprintWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ protected override IEnumerable<IContent>
2929
GetEntitiesFromNotification(ContentSavedBlueprintNotification notification)
3030
=> new List<IContent> { notification.SavedBlueprint };
3131

32-
protected override object ConvertEntityToRequestPayload(IContent entity) => entity;
32+
protected override object ConvertEntityToRequestPayload(IContent entity)
33+
=> new DefaultPayloadModel { Id = entity.Key };
3334
}

src/Umbraco.Core/Webhooks/Events/Content/ContentSavedWebhookEvent.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,5 @@ protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentSave
3939
notification.SavedEntities;
4040

4141
protected override object? ConvertEntityToRequestPayload(IContent entity)
42-
{
43-
// Get preview/saved version of content
44-
IPublishedContent? publishedContent = _contentCache.GetById(true, entity.Key);
45-
return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent);
46-
}
42+
=> new DefaultPayloadModel { Id = entity.Key };
4743
}

src/Umbraco.Core/Webhooks/Events/Content/ContentSortedWebhookEvent.cs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,11 @@ public ContentSortedWebhookEvent(
3636
public override string Alias => Constants.WebhookEvents.Aliases.ContentSorted;
3737

3838
public override object? ConvertNotificationToRequestPayload(ContentSortedNotification notification)
39-
{
40-
var sortedEntities = new List<object?>();
41-
foreach (var entity in notification.SortedEntities)
42-
{
43-
IPublishedContent? publishedContent = _contentCache.GetById(entity.Key);
44-
object? payload = publishedContent is null ? null : _apiContentBuilder.Build(publishedContent);
45-
sortedEntities.Add(payload);
46-
}
47-
return sortedEntities;
48-
}
39+
=> notification.SortedEntities
40+
.OrderBy(entity => entity.SortOrder)
41+
.Select(entity => new
42+
{
43+
Id = entity.Key,
44+
entity.SortOrder,
45+
});
4946
}

src/Umbraco.Core/Webhooks/Events/Content/ContentUnpublishedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ public ContentUnpublishedWebhookEvent(
2727

2828
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentUnpublishedNotification notification) => notification.UnpublishedEntities;
2929

30-
protected override object ConvertEntityToRequestPayload(IContent entity) => new DefaultPayloadModel { Id = entity.Key };
30+
protected override object ConvertEntityToRequestPayload(IContent entity)
31+
=> new DefaultPayloadModel { Id = entity.Key };
3132
}

src/Umbraco.Core/Webhooks/Events/ContentType/DocumentTypeChangedWebhookEvent.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ public DocumentTypeChangedWebhookEvent(
2121
public override string Alias => Constants.WebhookEvents.Aliases.DocumentTypeChanged;
2222

2323
public override object? ConvertNotificationToRequestPayload(ContentTypeChangedNotification notification)
24-
=> notification.Changes;
24+
=> notification.Changes.Select(contentTypeChange => new
25+
{
26+
Id = contentTypeChange.Item.Key,
27+
ContentTypeChange = contentTypeChange.ChangeTypes,
28+
});
2529
}

src/Umbraco.Core/Webhooks/Events/ContentType/DocumentTypeDeletedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -21,5 +22,5 @@ public DocumentTypeDeletedWebhookEvent(
2122
public override string Alias => Constants.WebhookEvents.Aliases.DocumentTypeDeleted;
2223

2324
public override object? ConvertNotificationToRequestPayload(ContentTypeDeletedNotification notification)
24-
=> notification.DeletedEntities;
25+
=> notification.DeletedEntities.Select(entity => new DefaultPayloadModel { Id = entity.Key });
2526
}

src/Umbraco.Core/Webhooks/Events/ContentType/DocumentTypeMovedWebhookEvent.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ public DocumentTypeMovedWebhookEvent(
2121
public override string Alias => Constants.WebhookEvents.Aliases.DocumentTypeMoved;
2222

2323
public override object? ConvertNotificationToRequestPayload(ContentTypeMovedNotification notification)
24-
=> notification.MoveInfoCollection;
24+
=> notification.MoveInfoCollection.Select(moveEvent => new
25+
{
26+
Id = moveEvent.Entity.Key,
27+
NewParentId = moveEvent.NewParentKey,
28+
});
2529
}

src/Umbraco.Core/Webhooks/Events/ContentType/DocumentTypeSavedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -21,5 +22,5 @@ public DocumentTypeSavedWebhookEvent(
2122
public override string Alias => Constants.WebhookEvents.Aliases.DocumentTypeSaved;
2223

2324
public override object? ConvertNotificationToRequestPayload(ContentTypeSavedNotification notification)
24-
=> notification.SavedEntities;
25+
=> notification.SavedEntities.Select(entity => new DefaultPayloadModel { Id = entity.Key });
2526
}

src/Umbraco.Core/Webhooks/Events/ContentType/MediaTypeChangedWebhookEvent.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ public MediaTypeChangedWebhookEvent(
2121
public override string Alias => Constants.WebhookEvents.Aliases.MediaTypeChanged;
2222

2323
public override object? ConvertNotificationToRequestPayload(MediaTypeChangedNotification notification)
24-
=> notification.Changes;
24+
=> notification.Changes.Select(contentTypeChange => new
25+
{
26+
Id = contentTypeChange.Item.Key,
27+
ContentTypeChange = contentTypeChange.ChangeTypes,
28+
});
2529
}

src/Umbraco.Core/Webhooks/Events/ContentType/MediaTypeDeletedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -21,5 +22,5 @@ public MediaTypeDeletedWebhookEvent(
2122
public override string Alias => Constants.WebhookEvents.Aliases.MediaTypeDeleted;
2223

2324
public override object? ConvertNotificationToRequestPayload(MediaTypeDeletedNotification notification)
24-
=> notification.DeletedEntities;
25+
=> notification.DeletedEntities.Select(entity => new DefaultPayloadModel { Id = entity.Key });
2526
}

src/Umbraco.Core/Webhooks/Events/ContentType/MediaTypeMovedWebhookEvent.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ public MediaTypeMovedWebhookEvent(
2121
public override string Alias => Constants.WebhookEvents.Aliases.MediaTypeMoved;
2222

2323
public override object? ConvertNotificationToRequestPayload(MediaTypeMovedNotification notification)
24-
=> notification.MoveInfoCollection;
24+
=> notification.MoveInfoCollection.Select(moveEvent => new
25+
{
26+
Id = moveEvent.Entity.Key,
27+
NewParentId = moveEvent.NewParentKey,
28+
});
2529
}

src/Umbraco.Core/Webhooks/Events/ContentType/MediaTypeSavedWebhookEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Options;
22
using Umbraco.Cms.Core.Configuration.Models;
3+
using Umbraco.Cms.Core.Models;
34
using Umbraco.Cms.Core.Notifications;
45
using Umbraco.Cms.Core.Services;
56
using Umbraco.Cms.Core.Sync;
@@ -21,5 +22,5 @@ public MediaTypeSavedWebhookEvent(
2122
public override string Alias => Constants.WebhookEvents.Aliases.MediaTypeSaved;
2223

2324
public override object? ConvertNotificationToRequestPayload(MediaTypeSavedNotification notification)
24-
=> notification.SavedEntities;
25+
=> notification.SavedEntities.Select(entity => new DefaultPayloadModel { Id = entity.Key });
2526
}

src/Umbraco.Core/Webhooks/Events/ContentType/MemberTypeChangedWebhookEvent.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ public MemberTypeChangedWebhookEvent(
2121
public override string Alias => Constants.WebhookEvents.Aliases.MemberTypeChanged;
2222

2323
public override object? ConvertNotificationToRequestPayload(MemberTypeChangedNotification notification)
24-
=> notification.Changes;
24+
=> notification.Changes.Select(contentTypeChange => new
25+
{
26+
Id = contentTypeChange.Item.Key,
27+
ContentTypeChange = contentTypeChange.ChangeTypes,
28+
});
2529
}

0 commit comments

Comments
 (0)