diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdContentApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByIdContentApiController.cs
similarity index 96%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ByIdContentApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByIdContentApiController.cs
index fc2e91e1ba..d16afc4d6d 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdContentApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByIdContentApiController.cs
@@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
public class ByIdContentApiController : ContentApiItemControllerBase
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdsContentApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByIdsContentApiController.cs
similarity index 96%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ByIdsContentApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByIdsContentApiController.cs
index ca2deb360d..5d415fffe6 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdsContentApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByIdsContentApiController.cs
@@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
public class ByIdsContentApiController : ContentApiItemControllerBase
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ByRouteContentApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs
similarity index 98%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ByRouteContentApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs
index 04900f52d2..2d22887637 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ByRouteContentApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ByRouteContentApiController.cs
@@ -1,4 +1,3 @@
-using System.Net;
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -9,7 +8,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
public class ByRouteContentApiController : ContentApiItemControllerBase
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ContentApiControllerBase.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ContentApiControllerBase.cs
similarity index 97%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ContentApiControllerBase.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Content/ContentApiControllerBase.cs
index 07439505e0..ebfa32c479 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ContentApiControllerBase.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ContentApiControllerBase.cs
@@ -5,7 +5,7 @@ using Umbraco.Cms.Api.Delivery.Routing;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Services.OperationStatus;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[DeliveryApiAccess]
[VersionedDeliveryApiRoute("content")]
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ContentApiItemControllerBase.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ContentApiItemControllerBase.cs
similarity index 94%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ContentApiItemControllerBase.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Content/ContentApiItemControllerBase.cs
index 8c8e2b5fd7..dad11de009 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ContentApiItemControllerBase.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/ContentApiItemControllerBase.cs
@@ -2,7 +2,7 @@
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
public abstract class ContentApiItemControllerBase : ContentApiControllerBase
{
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/QueryContentApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/QueryContentApiController.cs
similarity index 97%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/QueryContentApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Content/QueryContentApiController.cs
index e46204f85e..d4db82d9be 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/QueryContentApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Content/QueryContentApiController.cs
@@ -10,7 +10,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Content;
[ApiVersion("1.0")]
public class QueryContentApiController : ContentApiControllerBase
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs
similarity index 89%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ByIdMediaApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs
index 423d70fd5b..b0242bea5d 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdMediaApiController.cs
@@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.DeliveryApi;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
public class ByIdMediaApiController : MediaApiControllerBase
@@ -23,7 +23,7 @@ public class ByIdMediaApiController : MediaApiControllerBase
/// The media item or not found result.
[HttpGet("item/{id:guid}")]
[MapToApiVersion("1.0")]
- [ProducesResponseType(typeof(ApiMediaWithCropsResponse), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(IApiMediaWithCropsResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task ById(Guid id)
{
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdsMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs
similarity index 85%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ByIdsMediaApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs
index b8327e95c3..a9421eaa0c 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ByIdsMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByIdsMediaApiController.cs
@@ -7,7 +7,7 @@ using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.DeliveryApi;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
public class ByIdsMediaApiController : MediaApiControllerBase
@@ -24,7 +24,7 @@ public class ByIdsMediaApiController : MediaApiControllerBase
/// The media items.
[HttpGet("item")]
[MapToApiVersion("1.0")]
- [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
public async Task Item([FromQuery(Name = "id")] HashSet ids)
{
IPublishedContent[] mediaItems = ids
@@ -32,7 +32,7 @@ public class ByIdsMediaApiController : MediaApiControllerBase
.WhereNotNull()
.ToArray();
- ApiMediaWithCropsResponse[] apiMediaItems = mediaItems
+ IApiMediaWithCropsResponse[] apiMediaItems = mediaItems
.Select(BuildApiMediaWithCrops)
.ToArray();
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/ByPathMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs
similarity index 91%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/ByPathMediaApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs
index 947dd820a1..1d725ac5ab 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/ByPathMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/ByPathMediaApiController.cs
@@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.DeliveryApi;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
public class ByPathMediaApiController : MediaApiControllerBase
@@ -28,7 +28,7 @@ public class ByPathMediaApiController : MediaApiControllerBase
/// The media item or not found result.
[HttpGet("item/{*path}")]
[MapToApiVersion("1.0")]
- [ProducesResponseType(typeof(ApiMediaWithCropsResponse), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(IApiMediaWithCropsResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task ByPath(string path)
{
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/MediaApiControllerBase.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs
similarity index 94%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/MediaApiControllerBase.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs
index dc279cf703..73a385fd2e 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/MediaApiControllerBase.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/MediaApiControllerBase.cs
@@ -9,7 +9,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Infrastructure.DeliveryApi;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[DeliveryApiMediaAccess]
[VersionedDeliveryApiRoute("media")]
@@ -30,7 +30,7 @@ public abstract class MediaApiControllerBase : DeliveryApiControllerBase
??= _publishedSnapshotAccessor.GetRequiredPublishedSnapshot().Media
?? throw new InvalidOperationException("Could not obtain the published media cache");
- protected ApiMediaWithCropsResponse BuildApiMediaWithCrops(IPublishedContent media)
+ protected IApiMediaWithCropsResponse BuildApiMediaWithCrops(IPublishedContent media)
=> _apiMediaWithCropsResponseBuilder.Build(media);
protected IActionResult ApiMediaQueryOperationStatusResult(ApiMediaQueryOperationStatus status) =>
diff --git a/src/Umbraco.Cms.Api.Delivery/Controllers/QueryMediaApiController.cs b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs
similarity index 91%
rename from src/Umbraco.Cms.Api.Delivery/Controllers/QueryMediaApiController.cs
rename to src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs
index 98110e9589..5d962ea4bf 100644
--- a/src/Umbraco.Cms.Api.Delivery/Controllers/QueryMediaApiController.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Controllers/Media/QueryMediaApiController.cs
@@ -12,7 +12,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Infrastructure.DeliveryApi;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Api.Delivery.Controllers;
+namespace Umbraco.Cms.Api.Delivery.Controllers.Media;
[ApiVersion("1.0")]
public class QueryMediaApiController : MediaApiControllerBase
@@ -37,7 +37,7 @@ public class QueryMediaApiController : MediaApiControllerBase
/// The paged result of the media item(s).
[HttpGet]
[MapToApiVersion("1.0")]
- [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
public async Task Query(
string? fetch,
@@ -56,7 +56,7 @@ public class QueryMediaApiController : MediaApiControllerBase
PagedModel pagedResult = queryAttempt.Result;
IPublishedContent[] mediaItems = pagedResult.Items.Select(PublishedMediaCache.GetById).WhereNotNull().ToArray();
- var model = new PagedViewModel
+ var model = new PagedViewModel
{
Total = pagedResult.Total,
Items = mediaItems.Select(BuildApiMediaWithCrops)
diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs
index 8b3c946873..7c42a3d0aa 100644
--- a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerContentDocumentationFilter.cs
@@ -3,6 +3,7 @@ using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Umbraco.Cms.Api.Delivery.Configuration;
using Umbraco.Cms.Api.Delivery.Controllers;
+using Umbraco.Cms.Api.Delivery.Controllers.Content;
namespace Umbraco.Cms.Api.Delivery.Filters;
diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerMediaDocumentationFilter.cs b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerMediaDocumentationFilter.cs
index af22914f78..8529178888 100644
--- a/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerMediaDocumentationFilter.cs
+++ b/src/Umbraco.Cms.Api.Delivery/Filters/SwaggerMediaDocumentationFilter.cs
@@ -3,6 +3,7 @@ using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Umbraco.Cms.Api.Delivery.Configuration;
using Umbraco.Cms.Api.Delivery.Controllers;
+using Umbraco.Cms.Api.Delivery.Controllers.Media;
namespace Umbraco.Cms.Api.Delivery.Filters;
diff --git a/src/Umbraco.Core/Models/DeliveryApi/IApiMediaWithCrops.cs b/src/Umbraco.Core/Models/DeliveryApi/IApiMediaWithCrops.cs
new file mode 100644
index 0000000000..073ea89ca3
--- /dev/null
+++ b/src/Umbraco.Core/Models/DeliveryApi/IApiMediaWithCrops.cs
@@ -0,0 +1,8 @@
+namespace Umbraco.Cms.Core.Models.DeliveryApi;
+
+public interface IApiMediaWithCrops : IApiMedia
+{
+ public ImageFocalPoint? FocalPoint { get; }
+
+ public IEnumerable? Crops { get; }
+}
diff --git a/src/Umbraco.Core/Models/DeliveryApi/IApiMediaWithCropsResponse.cs b/src/Umbraco.Core/Models/DeliveryApi/IApiMediaWithCropsResponse.cs
new file mode 100644
index 0000000000..34912bbec7
--- /dev/null
+++ b/src/Umbraco.Core/Models/DeliveryApi/IApiMediaWithCropsResponse.cs
@@ -0,0 +1,10 @@
+namespace Umbraco.Cms.Core.Models.DeliveryApi;
+
+public interface IApiMediaWithCropsResponse : IApiMediaWithCrops
+{
+ public string Path { get; }
+
+ public DateTime CreateDate { get; }
+
+ public DateTime UpdateDate { get; }
+}
diff --git a/src/Umbraco.Core/Models/DeliveryApi/ImageCrop.cs b/src/Umbraco.Core/Models/DeliveryApi/ImageCrop.cs
new file mode 100644
index 0000000000..eda02d8fa7
--- /dev/null
+++ b/src/Umbraco.Core/Models/DeliveryApi/ImageCrop.cs
@@ -0,0 +1,20 @@
+namespace Umbraco.Cms.Core.Models.DeliveryApi;
+
+public class ImageCrop
+{
+ public ImageCrop(string? alias, int width, int height, ImageCropCoordinates? coordinates)
+ {
+ Alias = alias;
+ Width = width;
+ Height = height;
+ Coordinates = coordinates;
+ }
+
+ public string? Alias { get; }
+
+ public int Width { get; }
+
+ public int Height { get; }
+
+ public ImageCropCoordinates? Coordinates { get; }
+}
diff --git a/src/Umbraco.Core/Models/DeliveryApi/ImageCropCoordinates.cs b/src/Umbraco.Core/Models/DeliveryApi/ImageCropCoordinates.cs
new file mode 100644
index 0000000000..48ad0b6201
--- /dev/null
+++ b/src/Umbraco.Core/Models/DeliveryApi/ImageCropCoordinates.cs
@@ -0,0 +1,20 @@
+namespace Umbraco.Cms.Core.Models.DeliveryApi;
+
+public class ImageCropCoordinates
+{
+ public ImageCropCoordinates(decimal x1, decimal y1, decimal x2, decimal y2)
+ {
+ X1 = x1;
+ Y1 = y1;
+ X2 = x2;
+ Y2 = y2;
+ }
+
+ public decimal X1 { get; }
+
+ public decimal Y1 { get; }
+
+ public decimal X2 { get; }
+
+ public decimal Y2 { get; }
+}
diff --git a/src/Umbraco.Core/Models/DeliveryApi/ImageFocalPoint.cs b/src/Umbraco.Core/Models/DeliveryApi/ImageFocalPoint.cs
new file mode 100644
index 0000000000..d3ae5e65cd
--- /dev/null
+++ b/src/Umbraco.Core/Models/DeliveryApi/ImageFocalPoint.cs
@@ -0,0 +1,14 @@
+namespace Umbraco.Cms.Core.Models.DeliveryApi;
+
+public class ImageFocalPoint
+{
+ public ImageFocalPoint(decimal left, decimal top)
+ {
+ Left = left;
+ Top = top;
+ }
+
+ public decimal Left { get; }
+
+ public decimal Top { get; }
+}
diff --git a/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilder.cs b/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilder.cs
index ab9d7943b4..d3490dcb13 100644
--- a/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilder.cs
+++ b/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilder.cs
@@ -1,21 +1,20 @@
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
-using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Cms.Infrastructure.DeliveryApi;
-internal sealed class ApiMediaWithCropsBuilder : ApiMediaWithCropsBuilderBase, IApiMediaWithCropsBuilder
+internal sealed class ApiMediaWithCropsBuilder : ApiMediaWithCropsBuilderBase, IApiMediaWithCropsBuilder
{
public ApiMediaWithCropsBuilder(IApiMediaBuilder apiMediaBuilder, IPublishedValueFallback publishedValueFallback)
: base(apiMediaBuilder, publishedValueFallback)
{
}
- protected override ApiMediaWithCrops Create(
+ protected override IApiMediaWithCrops Create(
IPublishedContent media,
IApiMedia inner,
- ImageCropperValue.ImageCropperFocalPoint? focalPoint,
- IEnumerable? crops) =>
- new ApiMediaWithCrops(inner, focalPoint, crops);
+ ImageFocalPoint? focalPoint,
+ IEnumerable? crops)
+ => new ApiMediaWithCrops(inner, focalPoint, crops);
}
diff --git a/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilderBase.cs b/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilderBase.cs
index 8754eea976..d8ee9c9289 100644
--- a/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilderBase.cs
+++ b/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsBuilderBase.cs
@@ -9,7 +9,7 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.DeliveryApi;
internal abstract class ApiMediaWithCropsBuilderBase
- where T : IApiMedia
+ where T : IApiMediaWithCrops
{
private readonly IApiMediaBuilder _apiMediaBuilder;
private readonly IPublishedValueFallback _publishedValueFallback;
@@ -23,8 +23,8 @@ internal abstract class ApiMediaWithCropsBuilderBase
protected abstract T Create(
IPublishedContent media,
IApiMedia inner,
- ImageCropperValue.ImageCropperFocalPoint? focalPoint,
- IEnumerable? crops);
+ ImageFocalPoint? focalPoint,
+ IEnumerable? crops);
public T Build(MediaWithCrops media)
{
@@ -38,7 +38,7 @@ internal abstract class ApiMediaWithCropsBuilderBase
localCrops = localCrops.Merge(mediaCrops);
}
- return Create(media.Content, inner, localCrops.FocalPoint, localCrops.Crops);
+ return Create(media.Content, inner, localCrops.GetImageFocalPoint(), localCrops.GetImageCrops());
}
public T Build(IPublishedContent media)
diff --git a/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsResponseBuilder.cs b/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsResponseBuilder.cs
index 68c73304da..3fd3ca34ef 100644
--- a/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsResponseBuilder.cs
+++ b/src/Umbraco.Infrastructure/DeliveryApi/ApiMediaWithCropsResponseBuilder.cs
@@ -1,22 +1,21 @@
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.Models.PublishedContent;
-using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Cms.Infrastructure.DeliveryApi;
-internal sealed class ApiMediaWithCropsResponseBuilder : ApiMediaWithCropsBuilderBase, IApiMediaWithCropsResponseBuilder
+internal sealed class ApiMediaWithCropsResponseBuilder : ApiMediaWithCropsBuilderBase, IApiMediaWithCropsResponseBuilder
{
public ApiMediaWithCropsResponseBuilder(IApiMediaBuilder apiMediaBuilder, IPublishedValueFallback publishedValueFallback)
: base(apiMediaBuilder, publishedValueFallback)
{
}
- protected override ApiMediaWithCropsResponse Create(
+ protected override IApiMediaWithCropsResponse Create(
IPublishedContent media,
IApiMedia inner,
- ImageCropperValue.ImageCropperFocalPoint? focalPoint,
- IEnumerable? crops)
+ ImageFocalPoint? focalPoint,
+ IEnumerable? crops)
{
var path = $"/{string.Join("/", PathSegments(media).Reverse())}/";
return new ApiMediaWithCropsResponse(inner, focalPoint, crops, path, media.CreateDate, media.UpdateDate);
diff --git a/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsBuilder.cs b/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsBuilder.cs
index 63c2a0d218..5d56a7c6f1 100644
--- a/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsBuilder.cs
+++ b/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsBuilder.cs
@@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.DeliveryApi;
public interface IApiMediaWithCropsBuilder
{
- ApiMediaWithCrops Build(MediaWithCrops media);
+ IApiMediaWithCrops Build(MediaWithCrops media);
- ApiMediaWithCrops Build(IPublishedContent media);
+ IApiMediaWithCrops Build(IPublishedContent media);
}
diff --git a/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsResponseBuilder.cs b/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsResponseBuilder.cs
index 62e2cc7156..9c6377b4ea 100644
--- a/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsResponseBuilder.cs
+++ b/src/Umbraco.Infrastructure/DeliveryApi/IApiMediaWithCropsResponseBuilder.cs
@@ -5,5 +5,5 @@ namespace Umbraco.Cms.Infrastructure.DeliveryApi;
public interface IApiMediaWithCropsResponseBuilder
{
- ApiMediaWithCropsResponse Build(IPublishedContent media);
+ IApiMediaWithCropsResponse Build(IPublishedContent media);
}
diff --git a/src/Umbraco.Infrastructure/Extensions/DeliveryApiImageExtensions.cs b/src/Umbraco.Infrastructure/Extensions/DeliveryApiImageExtensions.cs
new file mode 100644
index 0000000000..ba23ed36de
--- /dev/null
+++ b/src/Umbraco.Infrastructure/Extensions/DeliveryApiImageExtensions.cs
@@ -0,0 +1,21 @@
+using Umbraco.Cms.Core.Models.DeliveryApi;
+using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
+
+namespace Umbraco.Extensions;
+
+public static class DeliveryApiImageExtensions
+{
+ public static ImageFocalPoint? GetImageFocalPoint(this ImageCropperValue imageCropperValue)
+ => imageCropperValue.FocalPoint is not null
+ ? new ImageFocalPoint(imageCropperValue.FocalPoint.Left, imageCropperValue.FocalPoint.Top)
+ : null;
+
+ public static IEnumerable? GetImageCrops(this ImageCropperValue imageCropperValue)
+ => imageCropperValue.Crops?.Select(crop => new ImageCrop(
+ crop.Alias,
+ crop.Width,
+ crop.Height,
+ crop.Coordinates is not null
+ ? new ImageCropCoordinates(crop.Coordinates.X1, crop.Coordinates.Y1, crop.Coordinates.X2, crop.Coordinates.Y2)
+ : null));
+}
diff --git a/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiImageCropperValue.cs b/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiImageCropperValue.cs
index 5cb6ee535e..275c88c619 100644
--- a/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiImageCropperValue.cs
+++ b/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiImageCropperValue.cs
@@ -1,10 +1,8 @@
-using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
-
namespace Umbraco.Cms.Core.Models.DeliveryApi;
internal sealed class ApiImageCropperValue
{
- public ApiImageCropperValue(string url, ImageCropperValue.ImageCropperFocalPoint? focalPoint, IEnumerable? crops)
+ public ApiImageCropperValue(string url, ImageFocalPoint? focalPoint, IEnumerable? crops)
{
Url = url;
FocalPoint = focalPoint;
@@ -13,7 +11,7 @@ internal sealed class ApiImageCropperValue
public string Url { get; }
- public ImageCropperValue.ImageCropperFocalPoint? FocalPoint { get; }
+ public ImageFocalPoint? FocalPoint { get; }
- public IEnumerable? Crops { get; }
+ public IEnumerable? Crops { get; }
}
diff --git a/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCrops.cs b/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCrops.cs
index d51a34e27d..9b7f60d2ba 100644
--- a/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCrops.cs
+++ b/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCrops.cs
@@ -1,15 +1,13 @@
-using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
-
namespace Umbraco.Cms.Core.Models.DeliveryApi;
-public class ApiMediaWithCrops : IApiMedia
+internal class ApiMediaWithCrops : IApiMediaWithCrops
{
private readonly IApiMedia _inner;
public ApiMediaWithCrops(
IApiMedia inner,
- ImageCropperValue.ImageCropperFocalPoint? focalPoint,
- IEnumerable? crops)
+ ImageFocalPoint? focalPoint,
+ IEnumerable? crops)
{
_inner = inner;
FocalPoint = focalPoint;
@@ -34,7 +32,7 @@ public class ApiMediaWithCrops : IApiMedia
public IDictionary Properties => _inner.Properties;
- public ImageCropperValue.ImageCropperFocalPoint? FocalPoint { get; }
+ public ImageFocalPoint? FocalPoint { get; }
- public IEnumerable? Crops { get; }
+ public IEnumerable? Crops { get; }
}
diff --git a/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCropsResponse.cs b/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCropsResponse.cs
index e1c1f09344..b7c056a395 100644
--- a/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCropsResponse.cs
+++ b/src/Umbraco.Infrastructure/Models/DeliveryApi/ApiMediaWithCropsResponse.cs
@@ -1,13 +1,11 @@
-using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
+namespace Umbraco.Cms.Core.Models.DeliveryApi;
-namespace Umbraco.Cms.Core.Models.DeliveryApi;
-
-public sealed class ApiMediaWithCropsResponse : ApiMediaWithCrops
+internal sealed class ApiMediaWithCropsResponse : ApiMediaWithCrops, IApiMediaWithCropsResponse
{
public ApiMediaWithCropsResponse(
IApiMedia inner,
- ImageCropperValue.ImageCropperFocalPoint? focalPoint,
- IEnumerable? crops,
+ ImageFocalPoint? focalPoint,
+ IEnumerable? crops,
string path,
DateTime createDate,
DateTime updateDate)
diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs
index 37a4b406fc..1f6dfc9578 100644
--- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs
+++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs
@@ -73,7 +73,10 @@ public class ImageCropperValueConverter : PropertyValueConverterBase, IDeliveryA
public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType) => typeof(ApiImageCropperValue);
public object? ConvertIntermediateToDeliveryApiObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview, bool expanding)
- => inter is ImageCropperValue {Src: { }} imageCropperValue
- ? new ApiImageCropperValue(imageCropperValue.Src, imageCropperValue.FocalPoint, imageCropperValue.Crops)
+ => inter is ImageCropperValue { Src: { } } imageCropperValue
+ ? new ApiImageCropperValue(
+ imageCropperValue.Src,
+ imageCropperValue.GetImageFocalPoint(),
+ imageCropperValue.GetImageCrops())
: null;
}
diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs
index 7e0829a399..817d48687a 100644
--- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs
+++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs
@@ -151,13 +151,13 @@ public class MediaPickerWithCropsValueConverter : PropertyValueConverterBase, ID
public PropertyCacheLevel GetDeliveryApiPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Elements;
- public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType) => typeof(IEnumerable);
+ public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType) => typeof(IEnumerable);
public object? ConvertIntermediateToDeliveryApiObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview, bool expanding)
{
var isMultiple = IsMultipleDataType(propertyType.DataType);
- ApiMediaWithCrops ToApiMedia(MediaWithCrops media) => _apiMediaWithCropsBuilder.Build(media);
+ IApiMediaWithCrops ToApiMedia(MediaWithCrops media) => _apiMediaWithCropsBuilder.Build(media);
// NOTE: eventually we might implement this explicitly instead of piggybacking on the default object conversion. however, this only happens once per cache rebuild,
// and the performance gain from an explicit implementation is negligible, so... at least for the time being this will do just fine.
@@ -171,7 +171,7 @@ public class MediaPickerWithCropsValueConverter : PropertyValueConverterBase, ID
return new [] { ToApiMedia(mediaWithCrops) };
}
- return Array.Empty();
+ return Array.Empty();
}
private bool IsMultipleDataType(PublishedDataType dataType) =>
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MediaPickerWithCropsValueConverterTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MediaPickerWithCropsValueConverterTests.cs
index 9e0284ffa8..365e48a325 100644
--- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MediaPickerWithCropsValueConverterTests.cs
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/MediaPickerWithCropsValueConverterTests.cs
@@ -43,7 +43,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
var serializer = new JsonNetSerializer();
var valueConverter = MediaPickerWithCropsValueConverter();
- Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
+ Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
var inter = serializer.Serialize(new[]
{
@@ -63,7 +63,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
}
});
- var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
+ var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
Assert.NotNull(result);
Assert.AreEqual(1, result.Count());
var first = result.Single();
@@ -87,7 +87,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
var serializer = new JsonNetSerializer();
var valueConverter = MediaPickerWithCropsValueConverter();
- Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
+ Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
var inter = serializer.Serialize(new[]
{
@@ -121,7 +121,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
}
});
- var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
+ var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
Assert.NotNull(result);
Assert.AreEqual(2, result.Count());
var first = result.First();
@@ -169,7 +169,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
var serializer = new JsonNetSerializer();
var valueConverter = MediaPickerWithCropsValueConverter();
- Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
+ Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
var inter = serializer.Serialize(new[]
{
@@ -188,7 +188,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
}
});
- var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
+ var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
Assert.NotNull(result);
Assert.AreEqual(1, result.Count());
var mediaWithCrops = result.Single();
@@ -206,7 +206,6 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
ValidateCrop(mediaWithCrops.Crops.Last(), "mediaOne", 111, 222, 2m, 4m, 20m, 40m);
}
-
[Test]
public void MediaPickerWithCropsValueConverter_LocalCropsAndFocalPointTakesPrecedenceOverMediaCropsAndFocalPoint()
{
@@ -230,7 +229,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
var serializer = new JsonNetSerializer();
var valueConverter = MediaPickerWithCropsValueConverter();
- Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
+ Assert.AreEqual(typeof(IEnumerable), valueConverter.GetDeliveryApiPropertyValueType(publishedPropertyType));
var inter = serializer.Serialize(new[]
{
@@ -250,7 +249,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
}
});
- var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
+ var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
Assert.NotNull(result);
Assert.AreEqual(1, result.Count());
var mediaWithCrops = result.Single();
@@ -277,7 +276,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
var valueConverter = MediaPickerWithCropsValueConverter();
- var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
+ var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
Assert.NotNull(result);
Assert.IsEmpty(result);
}
@@ -292,12 +291,11 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes
var valueConverter = MediaPickerWithCropsValueConverter();
- var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
+ var result = valueConverter.ConvertIntermediateToDeliveryApiObject(Mock.Of(), publishedPropertyType, PropertyCacheLevel.Element, inter, false, false) as IEnumerable;
Assert.NotNull(result);
Assert.IsEmpty(result);
}
-
private IPublishedPropertyType SetupMediaPropertyType(bool multiSelect)
{
var publishedDataType = new PublishedDataType(123, "test", new Lazy