Move the built-in properties back to the delivery API media model + support property expansion for other media properties (#14224)
Co-authored-by: Elitsa <elm@umbraco.dk>
This commit is contained in:
@@ -22,14 +22,33 @@ internal sealed class RequestContextOutputExpansionStrategy : IOutputExpansionSt
|
||||
}
|
||||
|
||||
public IDictionary<string, object?> MapElementProperties(IPublishedElement element)
|
||||
=> MapProperties(element.Properties);
|
||||
|
||||
public IDictionary<string, object?> MapProperties(IEnumerable<IPublishedProperty> properties)
|
||||
=> properties.ToDictionary(
|
||||
=> element.Properties.ToDictionary(
|
||||
p => p.Alias,
|
||||
p => p.GetDeliveryApiValue(_state == ExpansionState.Expanding));
|
||||
|
||||
public 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 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?>();
|
||||
}
|
||||
|
||||
private IDictionary<string, object?> MapProperties(IEnumerable<IPublishedProperty> properties)
|
||||
{
|
||||
// in the initial state, content properties should always be rendered (expanded if the requests dictates it).
|
||||
// this corresponds to the root level of a content item, i.e. when the initial content rendering starts.
|
||||
@@ -37,7 +56,7 @@ internal sealed class RequestContextOutputExpansionStrategy : IOutputExpansionSt
|
||||
{
|
||||
// update state to pending so we don't end up here the next time around
|
||||
_state = ExpansionState.Pending;
|
||||
var rendered = content.Properties.ToDictionary(
|
||||
var rendered = properties.ToDictionary(
|
||||
property => property.Alias,
|
||||
property =>
|
||||
{
|
||||
@@ -63,7 +82,7 @@ internal sealed class RequestContextOutputExpansionStrategy : IOutputExpansionSt
|
||||
if (_state == ExpansionState.Expanding)
|
||||
{
|
||||
_state = ExpansionState.Expanded;
|
||||
var rendered = content.Properties.ToDictionary(
|
||||
var rendered = properties.ToDictionary(
|
||||
property => property.Alias,
|
||||
property => property.GetDeliveryApiValue(false));
|
||||
_state = ExpansionState.Expanding;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Umbraco.Cms.Core.Models.DeliveryApi;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.DeliveryApi;
|
||||
|
||||
@@ -7,15 +8,18 @@ public sealed class ApiMediaBuilder : IApiMediaBuilder
|
||||
{
|
||||
private readonly IApiContentNameProvider _apiContentNameProvider;
|
||||
private readonly IApiMediaUrlProvider _apiMediaUrlProvider;
|
||||
private readonly IPublishedValueFallback _publishedValueFallback;
|
||||
private readonly IOutputExpansionStrategyAccessor _outputExpansionStrategyAccessor;
|
||||
|
||||
public ApiMediaBuilder(
|
||||
IApiContentNameProvider apiContentNameProvider,
|
||||
IApiMediaUrlProvider apiMediaUrlProvider,
|
||||
IPublishedValueFallback publishedValueFallback,
|
||||
IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor)
|
||||
{
|
||||
_apiContentNameProvider = apiContentNameProvider;
|
||||
_apiMediaUrlProvider = apiMediaUrlProvider;
|
||||
_publishedValueFallback = publishedValueFallback;
|
||||
_outputExpansionStrategyAccessor = outputExpansionStrategyAccessor;
|
||||
}
|
||||
|
||||
@@ -25,11 +29,27 @@ public sealed class ApiMediaBuilder : IApiMediaBuilder
|
||||
_apiContentNameProvider.GetName(media),
|
||||
media.ContentType.Alias,
|
||||
_apiMediaUrlProvider.GetUrl(media),
|
||||
Extension(media),
|
||||
Width(media),
|
||||
Height(media),
|
||||
Bytes(media),
|
||||
Properties(media));
|
||||
|
||||
// map all media properties except the umbracoFile one, as we've already included the file URL etc. in the output
|
||||
private IDictionary<string, object?> Properties(IPublishedContent media) =>
|
||||
_outputExpansionStrategyAccessor.TryGetValue(out IOutputExpansionStrategy? outputExpansionStrategy)
|
||||
? outputExpansionStrategy.MapProperties(media.Properties.Where(p => p.Alias != Constants.Conventions.Media.File))
|
||||
private string? Extension(IPublishedContent media)
|
||||
=> media.Value<string>(_publishedValueFallback, Constants.Conventions.Media.Extension);
|
||||
|
||||
private int? Width(IPublishedContent media)
|
||||
=> media.Value<int?>(_publishedValueFallback, Constants.Conventions.Media.Width);
|
||||
|
||||
private int? Height(IPublishedContent media)
|
||||
=> media.Value<int?>(_publishedValueFallback, Constants.Conventions.Media.Height);
|
||||
|
||||
private int? Bytes(IPublishedContent media)
|
||||
=> media.Value<int?>(_publishedValueFallback, Constants.Conventions.Media.Bytes);
|
||||
|
||||
// map all media properties except the umbraco ones, as we've already included those in the output
|
||||
private IDictionary<string, object?> Properties(IPublishedContent media)
|
||||
=> _outputExpansionStrategyAccessor.TryGetValue(out IOutputExpansionStrategy? outputExpansionStrategy)
|
||||
? outputExpansionStrategy.MapMediaProperties(media)
|
||||
: new Dictionary<string, object?>();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ public interface IOutputExpansionStrategy
|
||||
{
|
||||
IDictionary<string, object?> MapElementProperties(IPublishedElement element);
|
||||
|
||||
IDictionary<string, object?> MapProperties(IEnumerable<IPublishedProperty> properties);
|
||||
|
||||
IDictionary<string, object?> MapContentProperties(IPublishedContent content);
|
||||
|
||||
IDictionary<string, object?> MapMediaProperties(IPublishedContent media, bool skipUmbracoProperties = true);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,12 @@ internal sealed class NoopOutputExpansionStrategy : IOutputExpansionStrategy
|
||||
public IDictionary<string, object?> MapElementProperties(IPublishedElement element)
|
||||
=> MapProperties(element.Properties);
|
||||
|
||||
public IDictionary<string, object?> MapProperties(IEnumerable<IPublishedProperty> properties)
|
||||
=> properties.ToDictionary(p => p.Alias, p => p.GetDeliveryApiValue(true));
|
||||
|
||||
public IDictionary<string, object?> MapContentProperties(IPublishedContent content)
|
||||
=> MapProperties(content.Properties);
|
||||
|
||||
public IDictionary<string, object?> MapMediaProperties(IPublishedContent media, bool skipUmbracoProperties = true)
|
||||
=> MapProperties(media.Properties.Where(p => skipUmbracoProperties is false || p.Alias.StartsWith("umbraco") is false));
|
||||
|
||||
private IDictionary<string, object?> MapProperties(IEnumerable<IPublishedProperty> properties)
|
||||
=> properties.ToDictionary(p => p.Alias, p => p.GetDeliveryApiValue(false));
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
public sealed class ApiMedia : IApiMedia
|
||||
{
|
||||
public ApiMedia(Guid id, string name, string mediaType, string url, IDictionary<string, object?> properties)
|
||||
public ApiMedia(Guid id, string name, string mediaType, string url, string? extension, int? width, int? height, int? bytes, IDictionary<string, object?> properties)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
MediaType = mediaType;
|
||||
Url = url;
|
||||
Extension = extension;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Bytes = bytes;
|
||||
Properties = properties;
|
||||
}
|
||||
|
||||
@@ -19,5 +23,13 @@ public sealed class ApiMedia : IApiMedia
|
||||
|
||||
public string Url { get; }
|
||||
|
||||
public string? Extension { get; }
|
||||
|
||||
public int? Width { get; }
|
||||
|
||||
public int? Height { get; }
|
||||
|
||||
public int? Bytes { get; }
|
||||
|
||||
public IDictionary<string, object?> Properties { get; }
|
||||
}
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
|
||||
public interface IApiMedia
|
||||
{
|
||||
public Guid Id { get; }
|
||||
Guid Id { get; }
|
||||
|
||||
public string Name { get; }
|
||||
string Name { get; }
|
||||
|
||||
public string MediaType { get; }
|
||||
string MediaType { get; }
|
||||
|
||||
public string Url { get; }
|
||||
string Url { get; }
|
||||
|
||||
public IDictionary<string, object?> Properties { get; }
|
||||
string? Extension { get; }
|
||||
|
||||
int? Width { get; }
|
||||
|
||||
int? Height { get; }
|
||||
|
||||
int? Bytes { get; }
|
||||
|
||||
IDictionary<string, object?> Properties { get; }
|
||||
}
|
||||
|
||||
@@ -24,6 +24,14 @@ internal sealed class ApiMediaWithCrops : IApiMedia
|
||||
|
||||
public string Url => _inner.Url;
|
||||
|
||||
public string? Extension => _inner.Extension;
|
||||
|
||||
public int? Width => _inner.Width;
|
||||
|
||||
public int? Height => _inner.Height;
|
||||
|
||||
public int? Bytes => _inner.Bytes;
|
||||
|
||||
public IDictionary<string, object?> Properties => _inner.Properties;
|
||||
|
||||
public ImageCropperValue.ImageCropperFocalPoint? FocalPoint { get; }
|
||||
|
||||
@@ -21,6 +21,7 @@ public class ContentBuilderTests : DeliveryApiTests
|
||||
|
||||
var contentType = new Mock<IPublishedContentType>();
|
||||
contentType.SetupGet(c => c.Alias).Returns("thePageType");
|
||||
contentType.SetupGet(c => c.ItemType).Returns(PublishedItemType.Content);
|
||||
|
||||
var key = Guid.NewGuid();
|
||||
var urlSegment = "url-segment";
|
||||
|
||||
@@ -56,11 +56,11 @@ public class DeliveryApiTests
|
||||
DefaultPropertyType = SetupPublishedPropertyType(defaultPropertyValueConverter.Object, "default", "Default.Editor");
|
||||
}
|
||||
|
||||
protected IPublishedPropertyType SetupPublishedPropertyType(IPropertyValueConverter valueConverter, string propertyTypeAlias, string editorAlias)
|
||||
protected IPublishedPropertyType SetupPublishedPropertyType(IPropertyValueConverter valueConverter, string propertyTypeAlias, string editorAlias, object? dataTypeConfiguration = null)
|
||||
{
|
||||
var mockPublishedContentTypeFactory = new Mock<IPublishedContentTypeFactory>();
|
||||
mockPublishedContentTypeFactory.Setup(x => x.GetDataType(It.IsAny<int>()))
|
||||
.Returns(new PublishedDataType(123, editorAlias, new Lazy<object>()));
|
||||
.Returns(new PublishedDataType(123, editorAlias, new Lazy<object>(() => dataTypeConfiguration)));
|
||||
|
||||
var publishedPropType = new PublishedPropertyType(
|
||||
propertyTypeAlias,
|
||||
@@ -100,7 +100,7 @@ public class DeliveryApiTests
|
||||
});
|
||||
content.SetupGet(c => c.ContentType).Returns(contentType);
|
||||
content.SetupGet(c => c.Properties).Returns(properties);
|
||||
content.SetupGet(c => c.ItemType).Returns(PublishedItemType.Content);
|
||||
content.SetupGet(c => c.ItemType).Returns(contentType.ItemType);
|
||||
}
|
||||
|
||||
protected string DefaultUrlSegment(string name, string? culture = null)
|
||||
|
||||
@@ -21,19 +21,21 @@ public class MediaBuilderTests : DeliveryApiTests
|
||||
{
|
||||
{ Constants.Conventions.Media.Width, 111 },
|
||||
{ Constants.Conventions.Media.Height, 222 },
|
||||
{ Constants.Conventions.Media.Extension, ".my-ext" }
|
||||
{ Constants.Conventions.Media.Extension, ".my-ext" },
|
||||
{ Constants.Conventions.Media.Bytes, 333 }
|
||||
});
|
||||
|
||||
var builder = new ApiMediaBuilder(new ApiContentNameProvider(), SetupMediaUrlProvider(), CreateOutputExpansionStrategyAccessor());
|
||||
var builder = new ApiMediaBuilder(new ApiContentNameProvider(), SetupMediaUrlProvider(), Mock.Of<IPublishedValueFallback>(), CreateOutputExpansionStrategyAccessor());
|
||||
var result = builder.Build(media);
|
||||
Assert.NotNull(result);
|
||||
Assert.AreEqual("The media", result.Name);
|
||||
Assert.AreEqual("theMediaType", result.MediaType);
|
||||
Assert.AreEqual("media-url:media-url-segment", result.Url);
|
||||
Assert.AreEqual(3, result.Properties.Count);
|
||||
Assert.AreEqual(111, result.Properties[Constants.Conventions.Media.Width]);
|
||||
Assert.AreEqual(222, result.Properties[Constants.Conventions.Media.Height]);
|
||||
Assert.AreEqual(".my-ext", result.Properties[Constants.Conventions.Media.Extension]);
|
||||
Assert.AreEqual(key, result.Id);
|
||||
Assert.AreEqual(111, result.Width);
|
||||
Assert.AreEqual(222, result.Height);
|
||||
Assert.AreEqual(".my-ext", result.Extension);
|
||||
Assert.AreEqual(333, result.Bytes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -46,7 +48,7 @@ public class MediaBuilderTests : DeliveryApiTests
|
||||
new Dictionary<string, object>()
|
||||
);
|
||||
|
||||
var builder = new ApiMediaBuilder(new ApiContentNameProvider(), SetupMediaUrlProvider(), CreateOutputExpansionStrategyAccessor());
|
||||
var builder = new ApiMediaBuilder(new ApiContentNameProvider(), SetupMediaUrlProvider(), Mock.Of<IPublishedValueFallback>(), CreateOutputExpansionStrategyAccessor());
|
||||
var result = builder.Build(media);
|
||||
Assert.NotNull(result);
|
||||
Assert.IsEmpty(result.Properties);
|
||||
@@ -61,7 +63,7 @@ public class MediaBuilderTests : DeliveryApiTests
|
||||
"media-url-segment",
|
||||
new Dictionary<string, object> { { "myProperty", 123 }, { "anotherProperty", "A value goes here" } });
|
||||
|
||||
var builder = new ApiMediaBuilder(new ApiContentNameProvider(), SetupMediaUrlProvider(), CreateOutputExpansionStrategyAccessor());
|
||||
var builder = new ApiMediaBuilder(new ApiContentNameProvider(), SetupMediaUrlProvider(), Mock.Of<IPublishedValueFallback>(), CreateOutputExpansionStrategyAccessor());
|
||||
var result = builder.Build(media);
|
||||
Assert.NotNull(result);
|
||||
Assert.AreEqual(2, result.Properties.Count);
|
||||
@@ -76,7 +78,7 @@ public class MediaBuilderTests : DeliveryApiTests
|
||||
var mediaType = new Mock<IPublishedContentType>();
|
||||
mediaType.SetupGet(c => c.Alias).Returns("theMediaType");
|
||||
|
||||
var mediaProperties = properties.Select(kvp => SetupProperty(kvp.Key, kvp.Value, media.Object)).ToArray();
|
||||
var mediaProperties = properties.Select(kvp => SetupProperty(kvp.Key, kvp.Value)).ToArray();
|
||||
|
||||
media.SetupGet(c => c.Properties).Returns(mediaProperties);
|
||||
media.SetupGet(c => c.UrlSegment).Returns(urlSegment);
|
||||
@@ -89,7 +91,7 @@ public class MediaBuilderTests : DeliveryApiTests
|
||||
return media.Object;
|
||||
}
|
||||
|
||||
private IPublishedProperty SetupProperty<T>(string alias, T value, IPublishedContent media)
|
||||
private IPublishedProperty SetupProperty<T>(string alias, T value)
|
||||
{
|
||||
var propertyMock = new Mock<IPublishedProperty>();
|
||||
propertyMock.SetupGet(p => p.Alias).Returns(alias);
|
||||
|
||||
@@ -98,5 +98,6 @@ public class MediaPickerValueConverterTests : PropertyValueConverterTests
|
||||
new ApiMediaBuilder(
|
||||
new ApiContentNameProvider(),
|
||||
new ApiMediaUrlProvider(PublishedUrlProvider),
|
||||
Mock.Of<IPublishedValueFallback>(),
|
||||
CreateOutputExpansionStrategyAccessor()));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
new ApiMediaBuilder(
|
||||
new ApiContentNameProvider(),
|
||||
apiUrlProvider,
|
||||
Mock.Of<IPublishedValueFallback>(),
|
||||
CreateOutputExpansionStrategyAccessor()));
|
||||
}
|
||||
|
||||
@@ -34,7 +35,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
public void MediaPickerWithCropsValueConverter_InSingleMode_ConvertsValueToCollectionOfApiMedia()
|
||||
{
|
||||
var publishedPropertyType = SetupMediaPropertyType(false);
|
||||
var mediaKey = SetupMedia("My media", ".jpg", 200, 400, "My alt text");
|
||||
var mediaKey = SetupMedia("My media", ".jpg", 200, 400, "My alt text", 800);
|
||||
|
||||
var serializer = new JsonNetSerializer();
|
||||
|
||||
@@ -64,7 +65,15 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
Assert.AreEqual(1, result.Count());
|
||||
Assert.AreEqual("My media", result.First().Name);
|
||||
Assert.AreEqual("my-media", result.First().Url);
|
||||
Assert.AreEqual(".jpg", result.First().Extension);
|
||||
Assert.AreEqual(200, result.First().Width);
|
||||
Assert.AreEqual(400, result.First().Height);
|
||||
Assert.AreEqual(800, result.First().Bytes);
|
||||
Assert.NotNull(result.First().FocalPoint);
|
||||
Assert.AreEqual(".jpg", result.First().Extension);
|
||||
Assert.AreEqual(200, result.First().Width);
|
||||
Assert.AreEqual(400, result.First().Height);
|
||||
Assert.AreEqual(800, result.First().Bytes);
|
||||
Assert.AreEqual(.2m, result.First().FocalPoint.Left);
|
||||
Assert.AreEqual(.4m, result.First().FocalPoint.Top);
|
||||
Assert.NotNull(result.First().Crops);
|
||||
@@ -78,19 +87,16 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
Assert.AreEqual(10m, result.First().Crops.First().Coordinates.Y1);
|
||||
Assert.AreEqual(20m, result.First().Crops.First().Coordinates.Y2);
|
||||
Assert.NotNull(result.First().Properties);
|
||||
Assert.AreEqual(4, result.First().Properties.Count);
|
||||
Assert.AreEqual(1, result.First().Properties.Count);
|
||||
Assert.AreEqual("My alt text", result.First().Properties["altText"]);
|
||||
Assert.AreEqual(".jpg", result.First().Properties[Constants.Conventions.Media.Extension]);
|
||||
Assert.AreEqual(200, result.First().Properties[Constants.Conventions.Media.Width]);
|
||||
Assert.AreEqual(400, result.First().Properties[Constants.Conventions.Media.Height]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MediaPickerWithCropsValueConverter_InMultiMode_ConvertsValueToMedias()
|
||||
{
|
||||
var publishedPropertyType = SetupMediaPropertyType(true);
|
||||
var mediaKey1 = SetupMedia("My media", ".jpg", 200, 400, "My alt text");
|
||||
var mediaKey2 = SetupMedia("My other media", ".png", 800, 600, "My other alt text");
|
||||
var mediaKey1 = SetupMedia("My media", ".jpg", 200, 400, "My alt text", 800);
|
||||
var mediaKey2 = SetupMedia("My other media", ".png", 800, 600, "My other alt text", 200);
|
||||
|
||||
var serializer = new JsonNetSerializer();
|
||||
|
||||
@@ -135,6 +141,10 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
|
||||
Assert.AreEqual("My media", result.First().Name);
|
||||
Assert.AreEqual("my-media", result.First().Url);
|
||||
Assert.AreEqual(".jpg", result.First().Extension);
|
||||
Assert.AreEqual(200, result.First().Width);
|
||||
Assert.AreEqual(400, result.First().Height);
|
||||
Assert.AreEqual(800, result.First().Bytes);
|
||||
Assert.NotNull(result.First().FocalPoint);
|
||||
Assert.AreEqual(.2m, result.First().FocalPoint.Left);
|
||||
Assert.AreEqual(.4m, result.First().FocalPoint.Top);
|
||||
@@ -149,14 +159,15 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
Assert.AreEqual(10m, result.First().Crops.First().Coordinates.Y1);
|
||||
Assert.AreEqual(20m, result.First().Crops.First().Coordinates.Y2);
|
||||
Assert.NotNull(result.First().Properties);
|
||||
Assert.AreEqual(4, result.First().Properties.Count);
|
||||
Assert.AreEqual(1, result.First().Properties.Count);
|
||||
Assert.AreEqual("My alt text", result.First().Properties["altText"]);
|
||||
Assert.AreEqual(".jpg", result.First().Properties[Constants.Conventions.Media.Extension]);
|
||||
Assert.AreEqual(200, result.First().Properties[Constants.Conventions.Media.Width]);
|
||||
Assert.AreEqual(400, result.First().Properties[Constants.Conventions.Media.Height]);
|
||||
|
||||
Assert.AreEqual("My other media", result.Last().Name);
|
||||
Assert.AreEqual("my-other-media", result.Last().Url);
|
||||
Assert.AreEqual(".png", result.Last().Extension);
|
||||
Assert.AreEqual(800, result.Last().Width);
|
||||
Assert.AreEqual(600, result.Last().Height);
|
||||
Assert.AreEqual(200, result.Last().Bytes);
|
||||
Assert.NotNull(result.Last().FocalPoint);
|
||||
Assert.AreEqual(.8m, result.Last().FocalPoint.Left);
|
||||
Assert.AreEqual(.6m, result.Last().FocalPoint.Top);
|
||||
@@ -171,11 +182,8 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
Assert.AreEqual(2m, result.Last().Crops.Last().Coordinates.Y1);
|
||||
Assert.AreEqual(1m, result.Last().Crops.Last().Coordinates.Y2);
|
||||
Assert.NotNull(result.Last().Properties);
|
||||
Assert.AreEqual(4, result.Last().Properties.Count);
|
||||
Assert.AreEqual(1, result.Last().Properties.Count);
|
||||
Assert.AreEqual("My other alt text", result.Last().Properties["altText"]);
|
||||
Assert.AreEqual(".png", result.Last().Properties[Constants.Conventions.Media.Extension]);
|
||||
Assert.AreEqual(800, result.Last().Properties[Constants.Conventions.Media.Width]);
|
||||
Assert.AreEqual(600, result.Last().Properties[Constants.Conventions.Media.Height]);
|
||||
}
|
||||
|
||||
[TestCase("")]
|
||||
@@ -233,7 +241,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
return publishedPropertyType.Object;
|
||||
}
|
||||
|
||||
private Guid SetupMedia(string name, string extension, int width, int height, string altText)
|
||||
private Guid SetupMedia(string name, string extension, int width, int height, string altText, int bytes)
|
||||
{
|
||||
var publishedMediaType = new Mock<IPublishedContentType>();
|
||||
publishedMediaType.SetupGet(c => c.ItemType).Returns(PublishedItemType.Media);
|
||||
@@ -257,6 +265,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
|
||||
AddProperty(Constants.Conventions.Media.Extension, extension);
|
||||
AddProperty(Constants.Conventions.Media.Width, width);
|
||||
AddProperty(Constants.Conventions.Media.Height, height);
|
||||
AddProperty(Constants.Conventions.Media.Bytes, bytes);
|
||||
AddProperty("altText", altText);
|
||||
|
||||
PublishedMediaCacheMock
|
||||
|
||||
@@ -27,7 +27,7 @@ public class MultiNodeTreePickerValueConverterTests : PropertyValueConverterTest
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
Mock.Of<IMemberService>(),
|
||||
new ApiContentBuilder(contentNameProvider, routeBuilder, expansionStrategyAccessor),
|
||||
new ApiMediaBuilder(contentNameProvider, apiUrProvider, expansionStrategyAccessor));
|
||||
new ApiMediaBuilder(contentNameProvider, apiUrProvider, Mock.Of<IPublishedValueFallback>(), expansionStrategyAccessor));
|
||||
}
|
||||
|
||||
private PublishedDataType MultiNodePickerPublishedDataType(bool multiSelect, string entityType) =>
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.PropertyEditors.DeliveryApi;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi;
|
||||
|
||||
@@ -19,6 +20,7 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
{
|
||||
private IPublishedContentType _contentType;
|
||||
private IPublishedContentType _elementType;
|
||||
private IPublishedContentType _mediaType;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
@@ -31,6 +33,10 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
elementType.SetupGet(c => c.Alias).Returns("theElementType");
|
||||
elementType.SetupGet(c => c.ItemType).Returns(PublishedItemType.Element);
|
||||
_elementType = elementType.Object;
|
||||
var mediaType = new Mock<IPublishedContentType>();
|
||||
mediaType.SetupGet(c => c.Alias).Returns("theMediaType");
|
||||
mediaType.SetupGet(c => c.ItemType).Returns(PublishedItemType.Media);
|
||||
_mediaType = mediaType.Object;
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -91,6 +97,47 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
Assert.AreEqual(78, contentPickerTwoOutput.Properties["numberTwo"]);
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void OutputExpansionStrategy_CanExpandSpecificMedia(bool mediaPicker3)
|
||||
{
|
||||
var accessor = CreateOutputExpansionStrategyAccessor(false, new[] { "mediaPickerTwo" });
|
||||
var apiMediaBuilder = new ApiMediaBuilder(
|
||||
new ApiContentNameProvider(),
|
||||
new ApiMediaUrlProvider(PublishedUrlProvider),
|
||||
Mock.Of<IPublishedValueFallback>(),
|
||||
accessor);
|
||||
|
||||
var media = new Mock<IPublishedContent>();
|
||||
|
||||
var mediaPickerOneContent = CreateSimplePickedMedia(12, 34);
|
||||
var mediaPickerOneProperty = mediaPicker3
|
||||
? CreateMediaPicker3Property(media.Object, mediaPickerOneContent.Key, "mediaPickerOne", apiMediaBuilder)
|
||||
: CreateMediaPickerProperty(media.Object, mediaPickerOneContent.Key, "mediaPickerOne", apiMediaBuilder);
|
||||
var mediaPickerTwoContent = CreateSimplePickedMedia(56, 78);
|
||||
var mediaPickerTwoProperty = mediaPicker3
|
||||
? CreateMediaPicker3Property(media.Object, mediaPickerTwoContent.Key, "mediaPickerTwo", apiMediaBuilder)
|
||||
: CreateMediaPickerProperty(media.Object, mediaPickerTwoContent.Key, "mediaPickerTwo", apiMediaBuilder);
|
||||
|
||||
SetupMediaMock(media, mediaPickerOneProperty, mediaPickerTwoProperty);
|
||||
|
||||
var result = apiMediaBuilder.Build(media.Object);
|
||||
|
||||
Assert.AreEqual(2, result.Properties.Count);
|
||||
|
||||
var mediaPickerOneOutput = (result.Properties["mediaPickerOne"] as IEnumerable<IApiMedia>)?.FirstOrDefault();
|
||||
Assert.IsNotNull(mediaPickerOneOutput);
|
||||
Assert.AreEqual(mediaPickerOneContent.Key, mediaPickerOneOutput.Id);
|
||||
Assert.IsEmpty(mediaPickerOneOutput.Properties);
|
||||
|
||||
var mediaPickerTwoOutput = (result.Properties["mediaPickerTwo"] as IEnumerable<IApiMedia>)?.FirstOrDefault();
|
||||
Assert.IsNotNull(mediaPickerTwoOutput);
|
||||
Assert.AreEqual(mediaPickerTwoContent.Key, mediaPickerTwoOutput.Id);
|
||||
Assert.AreEqual(2, mediaPickerTwoOutput.Properties.Count);
|
||||
Assert.AreEqual(56, mediaPickerTwoOutput.Properties["numberOne"]);
|
||||
Assert.AreEqual(78, mediaPickerTwoOutput.Properties["numberTwo"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OutputExpansionStrategy_CanExpandAllContent()
|
||||
{
|
||||
@@ -339,6 +386,30 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
Assert.AreEqual(0, nestedContentPickerOutput.Properties.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OutputExpansionStrategy_MappingContent_ThrowsOnInvalidItemType()
|
||||
{
|
||||
var accessor = CreateOutputExpansionStrategyAccessor();
|
||||
if (accessor.TryGetValue(out IOutputExpansionStrategy outputExpansionStrategy) is false)
|
||||
{
|
||||
Assert.Fail("Could not obtain the output expansion strategy");
|
||||
}
|
||||
|
||||
Assert.Throws<ArgumentException>(() => outputExpansionStrategy.MapContentProperties(PublishedMedia));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OutputExpansionStrategy_MappingMedia_ThrowsOnInvalidItemType()
|
||||
{
|
||||
var accessor = CreateOutputExpansionStrategyAccessor();
|
||||
if (accessor.TryGetValue(out IOutputExpansionStrategy outputExpansionStrategy) is false)
|
||||
{
|
||||
Assert.Fail("Could not obtain the output expansion strategy");
|
||||
}
|
||||
|
||||
Assert.Throws<ArgumentException>(() => outputExpansionStrategy.MapMediaProperties(PublishedContent));
|
||||
}
|
||||
|
||||
private IOutputExpansionStrategyAccessor CreateOutputExpansionStrategyAccessor(bool expandAll = false, string[]? expandPropertyAliases = null)
|
||||
{
|
||||
var httpContextMock = new Mock<HttpContext>();
|
||||
@@ -370,6 +441,16 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
RegisterContentWithProviders(content.Object);
|
||||
}
|
||||
|
||||
private void SetupMediaMock(Mock<IPublishedContent> media, params IPublishedProperty[] properties)
|
||||
{
|
||||
var key = Guid.NewGuid();
|
||||
var name = "The media";
|
||||
var urlSegment = "media-url-segment";
|
||||
ConfigurePublishedContentMock(media, key, name, urlSegment, _mediaType, properties);
|
||||
|
||||
RegisterMediaWithProviders(media.Object);
|
||||
}
|
||||
|
||||
private IPublishedContent CreateSimplePickedContent(int numberOneValue, int numberTwoValue)
|
||||
{
|
||||
var content = new Mock<IPublishedContent>();
|
||||
@@ -381,6 +462,17 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
return content.Object;
|
||||
}
|
||||
|
||||
private IPublishedContent CreateSimplePickedMedia(int numberOneValue, int numberTwoValue)
|
||||
{
|
||||
var media = new Mock<IPublishedContent>();
|
||||
SetupMediaMock(
|
||||
media,
|
||||
CreateNumberProperty(media.Object, numberOneValue, "numberOne"),
|
||||
CreateNumberProperty(media.Object, numberTwoValue, "numberTwo"));
|
||||
|
||||
return media.Object;
|
||||
}
|
||||
|
||||
private IPublishedContent CreateMultiLevelPickedContent(int numberValue, IPublishedContent nestedContentPickerValue, string nestedContentPickerPropertyTypeAlias, ApiContentBuilder apiContentBuilder)
|
||||
{
|
||||
var content = new Mock<IPublishedContent>();
|
||||
@@ -400,6 +492,31 @@ public class OutputExpansionStrategyTests : PropertyValueConverterTests
|
||||
return new PublishedElementPropertyBase(contentPickerPropertyType, parent, false, PropertyCacheLevel.None, new GuidUdi(Constants.UdiEntityType.Document, pickedContentKey).ToString());
|
||||
}
|
||||
|
||||
private PublishedElementPropertyBase CreateMediaPickerProperty(IPublishedElement parent, Guid pickedMediaKey, string propertyTypeAlias, IApiMediaBuilder mediaBuilder)
|
||||
{
|
||||
MediaPickerValueConverter mediaPickerValueConverter = new MediaPickerValueConverter(PublishedSnapshotAccessor, Mock.Of<IPublishedModelFactory>(), mediaBuilder);
|
||||
var mediaPickerPropertyType = SetupPublishedPropertyType(mediaPickerValueConverter, propertyTypeAlias, Constants.PropertyEditors.Aliases.MediaPicker, new MediaPickerConfiguration());
|
||||
|
||||
return new PublishedElementPropertyBase(mediaPickerPropertyType, parent, false, PropertyCacheLevel.None, new GuidUdi(Constants.UdiEntityType.Media, pickedMediaKey).ToString());
|
||||
}
|
||||
|
||||
private PublishedElementPropertyBase CreateMediaPicker3Property(IPublishedElement parent, Guid pickedMediaKey, string propertyTypeAlias, IApiMediaBuilder mediaBuilder)
|
||||
{
|
||||
var serializer = new JsonNetSerializer();
|
||||
var value = serializer.Serialize(new[]
|
||||
{
|
||||
new MediaPicker3PropertyEditor.MediaPicker3PropertyValueEditor.MediaWithCropsDto
|
||||
{
|
||||
MediaKey = pickedMediaKey
|
||||
}
|
||||
});
|
||||
|
||||
MediaPickerWithCropsValueConverter mediaPickerValueConverter = new MediaPickerWithCropsValueConverter(PublishedSnapshotAccessor, PublishedUrlProvider, Mock.Of<IPublishedValueFallback>(), new JsonNetSerializer(), mediaBuilder);
|
||||
var mediaPickerPropertyType = SetupPublishedPropertyType(mediaPickerValueConverter, propertyTypeAlias, Constants.PropertyEditors.Aliases.MediaPicker3, new MediaPicker3Configuration());
|
||||
|
||||
return new PublishedElementPropertyBase(mediaPickerPropertyType, parent, false, PropertyCacheLevel.None, value);
|
||||
}
|
||||
|
||||
private PublishedElementPropertyBase CreateNumberProperty(IPublishedElement parent, int propertyValue, string propertyTypeAlias)
|
||||
{
|
||||
var numberPropertyType = SetupPublishedPropertyType(new IntegerValueConverter(), propertyTypeAlias, Constants.PropertyEditors.Aliases.Label);
|
||||
|
||||
@@ -105,5 +105,8 @@ public class PropertyValueConverterTests : DeliveryApiTests
|
||||
PublishedMediaCacheMock
|
||||
.Setup(pcc => pcc.GetById(media.Key))
|
||||
.Returns(media);
|
||||
PublishedMediaCacheMock
|
||||
.Setup(pcc => pcc.GetById(It.IsAny<bool>(), media.Key))
|
||||
.Returns(media);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user