-
Couldn't load subscription status.
- Fork 2.8k
Webhooks: Register OutputExpansionStrategy for webhooks if Delivery API is not enabled (closes #20272) #20559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| using Microsoft.AspNetCore.Http; | ||
| using Umbraco.Cms.Core.DeliveryApi; | ||
|
|
||
| namespace Umbraco.Cms.Api.Common.Accessors; | ||
|
|
||
| public sealed class RequestContextOutputExpansionStrategyAccessor : RequestContextServiceAccessorBase<IOutputExpansionStrategy>, IOutputExpansionStrategyAccessor | ||
| { | ||
| public RequestContextOutputExpansionStrategyAccessor(IHttpContextAccessor httpContextAccessor) | ||
| : base(httpContextAccessor) | ||
| { | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using Microsoft.AspNetCore.Http; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Umbraco.Cms.Api.Common.Accessors; | ||
|
|
||
| public abstract class RequestContextServiceAccessorBase<T> | ||
| where T : class | ||
| { | ||
| private readonly IHttpContextAccessor _httpContextAccessor; | ||
|
|
||
| protected RequestContextServiceAccessorBase(IHttpContextAccessor httpContextAccessor) | ||
| => _httpContextAccessor = httpContextAccessor; | ||
|
|
||
| public bool TryGetValue([NotNullWhen(true)] out T? requestStartNodeService) | ||
| { | ||
| requestStartNodeService = _httpContextAccessor.HttpContext?.RequestServices.GetService<T>(); | ||
| return requestStartNodeService is not null; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| using Umbraco.Cms.Core.DeliveryApi; | ||
| using Umbraco.Cms.Core.Models.PublishedContent; | ||
| using Umbraco.Extensions; | ||
|
|
||
| namespace Umbraco.Cms.Api.Common.Rendering; | ||
|
|
||
| public class ElementOnlyOutputExpansionStrategy : IOutputExpansionStrategy | ||
| { | ||
| protected const string All = "$all"; | ||
| protected const string None = ""; | ||
| protected const string ExpandParameterName = "expand"; | ||
| protected const string FieldsParameterName = "fields"; | ||
|
|
||
| private readonly IApiPropertyRenderer _propertyRenderer; | ||
|
|
||
| protected readonly Stack<Node?> ExpandProperties; | ||
| protected readonly Stack<Node?> IncludeProperties; | ||
|
|
||
| public ElementOnlyOutputExpansionStrategy( | ||
| IApiPropertyRenderer propertyRenderer) | ||
| { | ||
| _propertyRenderer = propertyRenderer; | ||
| ExpandProperties = new Stack<Node?>(); | ||
| IncludeProperties = new Stack<Node?>(); | ||
| } | ||
|
|
||
| public virtual IDictionary<string, object?> MapContentProperties(IPublishedContent content) | ||
| => content.ItemType == PublishedItemType.Content | ||
| ? MapProperties(content.Properties) | ||
| : throw new ArgumentException($"Invalid item type. This method can only be used with item type {nameof(PublishedItemType.Content)}, got: {content.ItemType}"); | ||
|
|
||
| public virtual IDictionary<string, object?> MapMediaProperties(IPublishedContent media, bool skipUmbracoProperties = true) | ||
| { | ||
| if (media.ItemType != PublishedItemType.Media) | ||
| { | ||
| throw new ArgumentException($"Invalid item type. This method can only be used with item type {PublishedItemType.Media}, got: {media.ItemType}"); | ||
| } | ||
|
|
||
| IPublishedProperty[] properties = media | ||
| .Properties | ||
| .Where(p => skipUmbracoProperties is false || p.Alias.StartsWith("umbraco") is false) | ||
| .ToArray(); | ||
|
|
||
| return properties.Any() | ||
| ? MapProperties(properties) | ||
| : new Dictionary<string, object?>(); | ||
| } | ||
|
|
||
| public virtual IDictionary<string, object?> MapElementProperties(IPublishedElement element) | ||
| => MapProperties(element.Properties, true); | ||
|
|
||
| protected IDictionary<string, object?> MapProperties(IEnumerable<IPublishedProperty> properties, bool forceExpandProperties = false) | ||
Migaroez marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| Node? currentExpandProperties = ExpandProperties.Count > 0 ? ExpandProperties.Peek() : null; | ||
| if (ExpandProperties.Count > 1 && currentExpandProperties is null && forceExpandProperties is false) | ||
| { | ||
| return new Dictionary<string, object?>(); | ||
| } | ||
|
|
||
| Node? currentIncludeProperties = IncludeProperties.Count > 0 ? IncludeProperties.Peek() : null; | ||
| var result = new Dictionary<string, object?>(); | ||
| foreach (IPublishedProperty property in properties) | ||
| { | ||
| Node? nextIncludeProperties = GetNextProperties(currentIncludeProperties, property.Alias); | ||
| if (currentIncludeProperties is not null && currentIncludeProperties.Items.Any() && nextIncludeProperties is null) | ||
|
Check warning on line 65 in src/Umbraco.Cms.Api.Common/Rendering/ElementOnlyOutputExpansionStrategy.cs
|
||
| { | ||
| continue; | ||
| } | ||
|
|
||
| Node? nextExpandProperties = GetNextProperties(currentExpandProperties, property.Alias); | ||
|
|
||
| IncludeProperties.Push(nextIncludeProperties); | ||
| ExpandProperties.Push(nextExpandProperties); | ||
|
|
||
| result[property.Alias] = GetPropertyValue(property); | ||
|
|
||
| ExpandProperties.Pop(); | ||
| IncludeProperties.Pop(); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
Check warning on line 82 in src/Umbraco.Cms.Api.Common/Rendering/ElementOnlyOutputExpansionStrategy.cs
|
||
|
|
||
| private Node? GetNextProperties(Node? currentProperties, string propertyAlias) | ||
| => currentProperties?.Items.FirstOrDefault(i => i.Key == All) | ||
| ?? currentProperties?.Items.FirstOrDefault(i => i.Key == "properties")?.Items.FirstOrDefault(i => i.Key == All || i.Key == propertyAlias); | ||
|
|
||
| private object? GetPropertyValue(IPublishedProperty property) | ||
| => _propertyRenderer.GetPropertyValue(property, ExpandProperties.Peek() is not null); | ||
|
|
||
| protected sealed class Node | ||
| { | ||
| public string Key { get; private set; } = string.Empty; | ||
|
|
||
| public List<Node> Items { get; } = new(); | ||
|
|
||
| public static Node Parse(string value) | ||
| { | ||
| // verify that there are as many start brackets as there are end brackets | ||
| if (value.CountOccurrences("[") != value.CountOccurrences("]")) | ||
| { | ||
| throw new ArgumentException("Value did not contain an equal number of start and end brackets"); | ||
| } | ||
|
|
||
| // verify that the value does not start with a start bracket | ||
| if (value.StartsWith("[")) | ||
| { | ||
| throw new ArgumentException("Value cannot start with a bracket"); | ||
| } | ||
|
|
||
| // verify that there are no empty brackets | ||
| if (value.Contains("[]")) | ||
| { | ||
| throw new ArgumentException("Value cannot contain empty brackets"); | ||
| } | ||
|
|
||
| var stack = new Stack<Node>(); | ||
| var root = new Node { Key = "root" }; | ||
| stack.Push(root); | ||
|
|
||
| var currentNode = new Node(); | ||
| root.Items.Add(currentNode); | ||
|
|
||
| foreach (char c in value) | ||
| { | ||
| switch (c) | ||
| { | ||
| case '[': // Start a new node, child of the current node | ||
| stack.Push(currentNode); | ||
| currentNode = new Node(); | ||
| stack.Peek().Items.Add(currentNode); | ||
| break; | ||
| case ',': // Start a new node, but at the same level of the current node | ||
| currentNode = new Node(); | ||
| stack.Peek().Items.Add(currentNode); | ||
| break; | ||
| case ']': // Back to parent of the current node | ||
| currentNode = stack.Pop(); | ||
| break; | ||
| default: // Add char to current node key | ||
| currentNode.Key += c; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| return root; | ||
| } | ||
|
Check warning on line 147 in src/Umbraco.Cms.Api.Common/Rendering/ElementOnlyOutputExpansionStrategy.cs
|
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.