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:
Kenn Jacobsen
2023-05-10 14:04:42 +02:00
committed by GitHub
parent 9187d92a2c
commit b0f42a2c86
15 changed files with 254 additions and 51 deletions

View File

@@ -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;

View File

@@ -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?>();
}

View File

@@ -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);
}

View File

@@ -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));
}

View File

@@ -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; }
}

View File

@@ -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; }
}

View File

@@ -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; }

View File

@@ -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";

View File

@@ -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)

View File

@@ -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);

View File

@@ -98,5 +98,6 @@ public class MediaPickerValueConverterTests : PropertyValueConverterTests
new ApiMediaBuilder(
new ApiContentNameProvider(),
new ApiMediaUrlProvider(PublishedUrlProvider),
Mock.Of<IPublishedValueFallback>(),
CreateOutputExpansionStrategyAccessor()));
}

View File

@@ -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

View File

@@ -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) =>

View File

@@ -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);

View File

@@ -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);
}
}