Skip to content

Commit

Permalink
V15: Fix webhook RTE serialization (#17656)
Browse files Browse the repository at this point in the history
* Make base type resolver class

* Add new webhook serializer

* fix comment

* Update src/Umbraco.Infrastructure/Serialization/ContentJsonTypeResolverBase.cs

Co-authored-by: Elitsa Marinovska <[email protected]>

* Update src/Umbraco.Core/Services/WebhookRequestService.cs

---------

Co-authored-by: Elitsa <[email protected]>
Co-authored-by: Elitsa Marinovska <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent 49330b4 commit 6f08178
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 59 deletions.
55 changes: 3 additions & 52 deletions src/Umbraco.Cms.Api.Delivery/Json/DeliveryApiJsonTypeResolver.cs
Original file line number Diff line number Diff line change
@@ -1,56 +1,7 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Infrastructure.Serialization;

namespace Umbraco.Cms.Api.Delivery.Json;

// see https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism?pivots=dotnet-7-0
public class DeliveryApiJsonTypeResolver : DefaultJsonTypeInfoResolver
{
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);

Type[] derivedTypes = GetDerivedTypes(jsonTypeInfo);
if (derivedTypes.Length > 0)
{
ConfigureJsonPolymorphismOptions(jsonTypeInfo, derivedTypes);
}

return jsonTypeInfo;
}

protected virtual Type[] GetDerivedTypes(JsonTypeInfo jsonTypeInfo)
{
if (jsonTypeInfo.Type == typeof(IApiContent))
{
return new[] { typeof(ApiContent) };
}

if (jsonTypeInfo.Type == typeof(IApiContentResponse))
{
return new[] { typeof(ApiContentResponse) };
}

if (jsonTypeInfo.Type == typeof(IRichTextElement))
{
return new[] { typeof(RichTextRootElement), typeof(RichTextGenericElement), typeof(RichTextTextElement) };
}

return Array.Empty<Type>();
}

protected void ConfigureJsonPolymorphismOptions(JsonTypeInfo jsonTypeInfo, params Type[] derivedTypes)
{
jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
{
UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
};

foreach (Type derivedType in derivedTypes)
{
jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(new JsonDerivedType(derivedType));
}
}
}
public class DeliveryApiJsonTypeResolver : ContentJsonTypeResolverBase
{ }
8 changes: 5 additions & 3 deletions src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
using Umbraco.Cms.Core.Packaging;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.PublishedCache.Internal;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Runtime;
using Umbraco.Cms.Core.Scoping;
Expand All @@ -37,6 +35,7 @@
using Umbraco.Cms.Core.DynamicRoot;
using Umbraco.Cms.Core.Preview;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services.FileSystem;
using Umbraco.Cms.Core.Services.ImportExport;
using Umbraco.Cms.Core.Services.Navigation;
Expand Down Expand Up @@ -403,7 +402,10 @@ private void AddCoreServices()
Services.AddUnique<IWebhookService, WebhookService>();
Services.AddUnique<IWebhookLogService, WebhookLogService>();
Services.AddUnique<IWebhookLogFactory, WebhookLogFactory>();
Services.AddUnique<IWebhookRequestService, WebhookRequestService>();
Services.AddUnique<IWebhookRequestService>(factory => new WebhookRequestService(
factory.GetRequiredService<ICoreScopeProvider>(),
factory.GetRequiredService<IWebhookRequestRepository>(),
factory.GetRequiredService<IWebhookJsonSerializer>()));

// Data type configuration cache
Services.AddUnique<IDataTypeConfigurationCache, DataTypeConfigurationCache>();
Expand Down
4 changes: 4 additions & 0 deletions src/Umbraco.Core/Serialization/IWebhookJsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace Umbraco.Cms.Core.Serialization;

public interface IWebhookJsonSerializer : IJsonSerializer
{ }
16 changes: 12 additions & 4 deletions src/Umbraco.Core/Services/WebhookRequestService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Umbraco.Cms.Core.Models;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Serialization;
Expand All @@ -9,13 +11,19 @@ public class WebhookRequestService : IWebhookRequestService
{
private readonly ICoreScopeProvider _coreScopeProvider;
private readonly IWebhookRequestRepository _webhookRequestRepository;
private readonly IJsonSerializer _jsonSerializer;
private readonly IWebhookJsonSerializer _webhookJsonSerializer;

[Obsolete("This constructor is obsolete and will be removed in future versions. Scheduled for removal in V17")]
public WebhookRequestService(ICoreScopeProvider coreScopeProvider, IWebhookRequestRepository webhookRequestRepository, IJsonSerializer jsonSerializer)
: this (coreScopeProvider, webhookRequestRepository, StaticServiceProvider.Instance.GetRequiredService<IWebhookJsonSerializer>())
{
}

public WebhookRequestService(ICoreScopeProvider coreScopeProvider, IWebhookRequestRepository webhookRequestRepository, IWebhookJsonSerializer webhookJsonSerializer)
{
_coreScopeProvider = coreScopeProvider;
_webhookRequestRepository = webhookRequestRepository;
_jsonSerializer = jsonSerializer;
_webhookJsonSerializer = webhookJsonSerializer;
}

public async Task<WebhookRequest> CreateAsync(Guid webhookKey, string eventAlias, object? payload)
Expand All @@ -26,7 +34,7 @@ public async Task<WebhookRequest> CreateAsync(Guid webhookKey, string eventAlias
{
WebhookKey = webhookKey,
EventAlias = eventAlias,
RequestObject = _jsonSerializer.Serialize(payload),
RequestObject = _webhookJsonSerializer.Serialize(payload),
RetryCount = 0,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builde

builder.Services.AddSingleton<IJsonSerializer, SystemTextJsonSerializer>();
builder.Services.AddSingleton<IConfigurationEditorJsonSerializer, SystemTextConfigurationEditorJsonSerializer>();
builder.Services.AddUnique<IWebhookJsonSerializer, SystemTextWebhookJsonSerializer>();

// register database builder
// *not* a singleton, don't want to keep it around
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Umbraco.Cms.Core.Models.DeliveryApi;

namespace Umbraco.Cms.Infrastructure.Serialization;

public abstract class ContentJsonTypeResolverBase : DefaultJsonTypeInfoResolver
{
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);

Type[] derivedTypes = GetDerivedTypes(jsonTypeInfo);
if (derivedTypes.Length > 0)
{
ConfigureJsonPolymorphismOptions(jsonTypeInfo, derivedTypes);
}

return jsonTypeInfo;
}

public virtual Type[] GetDerivedTypes(JsonTypeInfo jsonTypeInfo)
{
if (jsonTypeInfo.Type == typeof(IApiContent))
{
return new[] { typeof(ApiContent) };
}

if (jsonTypeInfo.Type == typeof(IApiContentResponse))
{
return new[] { typeof(ApiContentResponse) };
}

if (jsonTypeInfo.Type == typeof(IRichTextElement))
{
return new[] { typeof(RichTextRootElement), typeof(RichTextGenericElement), typeof(RichTextTextElement) };
}

return Array.Empty<Type>();
}

public void ConfigureJsonPolymorphismOptions(JsonTypeInfo jsonTypeInfo, params Type[] derivedTypes)
{
jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
{
UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization,
};

foreach (Type derivedType in derivedTypes)
{
jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(new JsonDerivedType(derivedType));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Umbraco.Cms.Core.Serialization;

namespace Umbraco.Cms.Infrastructure.Serialization;

/// <inheritdoc />
public sealed class SystemTextWebhookJsonSerializer : SystemTextJsonSerializerBase, IWebhookJsonSerializer
{
private readonly JsonSerializerOptions _jsonSerializerOptions;

/// <summary>
/// Initializes a new instance of the <see cref="SystemTextWebhookJsonSerializer" /> class.
/// </summary>
public SystemTextWebhookJsonSerializer()
=> _jsonSerializerOptions = new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters =
{
new JsonStringEnumConverter(),
new JsonUdiConverter(),
new JsonUdiRangeConverter(),
new JsonObjectConverter(), // Required for block editor values
new JsonBlockValueConverter()
},
TypeInfoResolver = new WebhookJsonTypeResolver(),
};

protected override JsonSerializerOptions JsonSerializerOptions => _jsonSerializerOptions;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace Umbraco.Cms.Infrastructure.Serialization;

public class WebhookJsonTypeResolver : ContentJsonTypeResolverBase
{ }

0 comments on commit 6f08178

Please sign in to comment.