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.Cms.Api.Delivery/Services/RequestStartItemProvider.cs b/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs index 2ff748dcdc..dd72d930bd 100644 --- a/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs +++ b/src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs @@ -11,6 +11,7 @@ internal sealed class RequestStartItemProvider : RequestHeaderHandler, IRequestS { private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly IVariationContextAccessor _variationContextAccessor; + private readonly IRequestPreviewService _requestPreviewService; // this provider lifetime is Scope, so we can cache this as a field private IPublishedContent? _requestedStartContent; @@ -18,11 +19,13 @@ internal sealed class RequestStartItemProvider : RequestHeaderHandler, IRequestS public RequestStartItemProvider( IHttpContextAccessor httpContextAccessor, IPublishedSnapshotAccessor publishedSnapshotAccessor, - IVariationContextAccessor variationContextAccessor) + IVariationContextAccessor variationContextAccessor, + IRequestPreviewService requestPreviewService) : base(httpContextAccessor) { _publishedSnapshotAccessor = publishedSnapshotAccessor; _variationContextAccessor = variationContextAccessor; + _requestPreviewService = requestPreviewService; } /// @@ -45,7 +48,7 @@ internal sealed class RequestStartItemProvider : RequestHeaderHandler, IRequestS return null; } - IEnumerable rootContent = publishedSnapshot.Content.GetAtRoot(); + IEnumerable rootContent = publishedSnapshot.Content.GetAtRoot(_requestPreviewService.IsPreview()); _requestedStartContent = Guid.TryParse(headerValue, out Guid key) ? rootContent.FirstOrDefault(c => c.Key == key) diff --git a/src/Umbraco.Core/Media/EmbedProviders/Issuu.cs b/src/Umbraco.Core/Media/EmbedProviders/Issuu.cs index 1a53ad88d1..0fdb92e96f 100644 --- a/src/Umbraco.Core/Media/EmbedProviders/Issuu.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/Issuu.cs @@ -19,6 +19,9 @@ public class Issuu : OEmbedProviderBase public override Dictionary RequestParams => new() { + // ApiUrl/?iframe=true + { "iframe", "true" }, + // ApiUrl/?format=xml { "format", "xml" }, }; diff --git a/src/Umbraco.Core/Media/EmbedProviders/OEmbedProviderBase.cs b/src/Umbraco.Core/Media/EmbedProviders/OEmbedProviderBase.cs index b09baba0db..9385dcf6c9 100644 --- a/src/Umbraco.Core/Media/EmbedProviders/OEmbedProviderBase.cs +++ b/src/Umbraco.Core/Media/EmbedProviders/OEmbedProviderBase.cs @@ -55,11 +55,12 @@ public abstract class OEmbedProviderBase : IEmbedProvider if (_httpClient == null) { _httpClient = new HttpClient(); + _httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd("Umbraco-CMS"); } using (var request = new HttpRequestMessage(HttpMethod.Get, url)) { - HttpResponseMessage response = _httpClient.SendAsync(request).Result; + HttpResponseMessage response = _httpClient.SendAsync(request).GetAwaiter().GetResult(); return response.Content.ReadAsStringAsync().Result; } } diff --git a/src/Umbraco.Core/Models/DeliveryApi/ApiElement.cs b/src/Umbraco.Core/Models/DeliveryApi/ApiElement.cs index b7d10814fc..d5941a1ed1 100644 --- a/src/Umbraco.Core/Models/DeliveryApi/ApiElement.cs +++ b/src/Umbraco.Core/Models/DeliveryApi/ApiElement.cs @@ -1,3 +1,5 @@ +using System.Text.Json.Serialization; + namespace Umbraco.Cms.Core.Models.DeliveryApi; public class ApiElement : IApiElement @@ -11,6 +13,9 @@ public class ApiElement : IApiElement public Guid Id { get; } + // Ensure the ContentType property is serialized first + // This is needed so it can be used as a discriminator field by System.Text.Json + [JsonPropertyOrder(-100)] public string ContentType { get; } public IDictionary Properties { get; } diff --git a/src/Umbraco.Core/Models/DeliveryApi/IApiElement.cs b/src/Umbraco.Core/Models/DeliveryApi/IApiElement.cs index 7630225f64..e62525aa34 100644 --- a/src/Umbraco.Core/Models/DeliveryApi/IApiElement.cs +++ b/src/Umbraco.Core/Models/DeliveryApi/IApiElement.cs @@ -1,9 +1,14 @@ +using System.Text.Json.Serialization; + namespace Umbraco.Cms.Core.Models.DeliveryApi; public interface IApiElement { Guid Id { get; } + // Ensure the ContentType property is serialized first + // This is needed so it can be used as a discriminator field by System.Text.Json + [JsonPropertyOrder(-100)] string ContentType { get; } IDictionary Properties { get; } 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.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 64bfb7ad18..e70f323f1c 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1098,7 +1098,7 @@ public class ContentService : RepositoryService, IContentService new ContentTreeChangeNotification(contentsA, TreeChangeTypes.RefreshNode, eventMessages)); string contentIds = string.Join(", ", contentsA.Select(x => x.Id)); - Audit(AuditType.Save, userId, Constants.System.Root, $"Saved multiple content items ({contentIds})"); + Audit(AuditType.Save, userId, Constants.System.Root, $"Saved multiple content items (#{contentIds.Length})"); scope.Complete(); } @@ -1951,7 +1951,7 @@ public class ContentService : RepositoryService, IContentService cultures = new HashSet(); // empty means 'already published' } - if (edited) + if (isRoot || edited) { cultures.Add(c); // means 'republish this culture' } @@ -2106,11 +2106,13 @@ public class ContentService : RepositoryService, IContentService } // deal with the branch root - if it fails, abort - PublishResult? result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, eventMessages, userId, allLangs); - if (result != null) + var rootPublishNotificationState = new Dictionary(); + PublishResult? rootResult = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, + publishedDocuments, eventMessages, userId, allLangs, rootPublishNotificationState); + if (rootResult != null) { - results.Add(result); - if (!result.Success) + results.Add(rootResult); + if (!rootResult.Success) { return results; } @@ -2123,6 +2125,7 @@ public class ContentService : RepositoryService, IContentService int count; var page = 0; const int pageSize = 100; + PublishResult? result = null; do { count = 0; @@ -2141,7 +2144,8 @@ public class ContentService : RepositoryService, IContentService } // no need to check path here, parent has to be published here - result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs); + result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, + publishedDocuments, eventMessages, userId, allLangs,null); if (result != null) { results.Add(result); @@ -2165,7 +2169,12 @@ public class ContentService : RepositoryService, IContentService // (SaveAndPublishBranchOne does *not* do it) scope.Notifications.Publish( new ContentTreeChangeNotification(document, TreeChangeTypes.RefreshBranch, eventMessages)); - scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, eventMessages, true)); + if (rootResult?.Success is true) + { + scope.Notifications.Publish( + new ContentPublishedNotification(rootResult!.Content!.Yield(), eventMessages, true) + .WithState(rootPublishNotificationState)); + } scope.Complete(); } @@ -2176,6 +2185,9 @@ public class ContentService : RepositoryService, IContentService // shouldPublish: a function determining whether the document has changes that need to be published // note - 'force' is handled by 'editing' // publishValues: a function publishing values (using the appropriate PublishCulture calls) + /// Only set this when processing a the root of the branch + /// Published notification will not be send when this property is set + /// private PublishResult? SaveAndPublishBranchItem( ICoreScope scope, IContent document, @@ -2186,7 +2198,8 @@ public class ContentService : RepositoryService, IContentService ICollection publishedDocuments, EventMessages evtMsgs, int userId, - IReadOnlyCollection allLangs) + IReadOnlyCollection allLangs, + IDictionary? rootPublishingNotificationState) { HashSet? culturesToPublish = shouldPublish(document); @@ -2215,10 +2228,17 @@ public class ContentService : RepositoryService, IContentService return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, document); } - PublishResult result = CommitDocumentChangesInternal(scope, document, evtMsgs, allLangs, savingNotification.State, userId, true, isRoot); - if (result.Success) + var notificationState = rootPublishingNotificationState ?? new Dictionary(); + PublishResult result = CommitDocumentChangesInternal(scope, document, evtMsgs, allLangs, notificationState, userId, true, isRoot); + if (!result.Success) { - publishedDocuments.Add(document); + return result; + } + + publishedDocuments.Add(document); + if (rootPublishingNotificationState == null) + { + scope.Notifications.Publish(new ContentPublishedNotification(result.Content!, evtMsgs).WithState(notificationState)); } return result; 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/ModelsBuilder/PublishedModelUtility.cs b/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs index b59ddc4cef..dd99ddaf28 100644 --- a/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs +++ b/src/Umbraco.Infrastructure/ModelsBuilder/PublishedModelUtility.cs @@ -37,6 +37,7 @@ public static class PublishedModelUtility switch (itemType) { case PublishedItemType.Content: + case PublishedItemType.Element: return publishedSnapshot.Content?.GetContentType(alias); case PublishedItemType.Media: return publishedSnapshot.Media?.GetContentType(alias); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs index fb253cc325..99cefe1c29 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs @@ -121,7 +121,7 @@ public class BlockListPropertyValueConverter : BlockPropertyValueConverterBase public Type GetDeliveryApiPropertyValueType(IPublishedPropertyType propertyType) - => typeof(IEnumerable); + => typeof(ApiBlockListModel); /// public object? ConvertIntermediateToDeliveryApiObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object? inter, bool preview, bool expanding) 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.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs index 7f4fb54471..6cfa2f8169 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs @@ -90,7 +90,7 @@ public class ContentServicePublishBranchTests : UmbracoIntegrationTest AssertPublishResults( r, x => x.Result, - PublishResultType.SuccessPublishAlready, + PublishResultType.SuccessPublish, // During branch publishing, the change detection of the root branch runs AFTER the check to process the branchItem => root is always saved&Published as the intent requires it. PublishResultType.SuccessPublishAlready, PublishResultType.SuccessPublishAlready); @@ -137,7 +137,7 @@ public class ContentServicePublishBranchTests : UmbracoIntegrationTest AssertPublishResults( r, x => x.Result, - PublishResultType.SuccessPublishAlready, + PublishResultType.SuccessPublish, // During branch publishing, the change detection of the root branch runs AFTER the check to process the branchItem => root is always saved&Published as the intent requires it. PublishResultType.SuccessPublishAlready, PublishResultType.SuccessPublishAlready, PublishResultType.SuccessPublish, @@ -182,7 +182,7 @@ public class ContentServicePublishBranchTests : UmbracoIntegrationTest var r = ContentService.SaveAndPublishBranch(vRoot, false) .ToArray(); // no culture specified so "*" is used, so all cultures - Assert.AreEqual(PublishResultType.SuccessPublishAlready, r[0].Result); + Assert.AreEqual(PublishResultType.SuccessPublishCulture, r[0].Result); // During branch publishing, the change detection of the root branch runs AFTER the check to process the branchItem => root is always saved&Published as the intent requires it. Assert.AreEqual(PublishResultType.SuccessPublishCulture, r[1].Result); } @@ -218,7 +218,7 @@ public class ContentServicePublishBranchTests : UmbracoIntegrationTest var saveResult = ContentService.Save(iv1); var r = ContentService.SaveAndPublishBranch(vRoot, false, "de").ToArray(); - Assert.AreEqual(PublishResultType.SuccessPublishAlready, r[0].Result); + Assert.AreEqual(PublishResultType.SuccessPublishCulture, r[0].Result); // During branch publishing, the change detection of the root branch runs AFTER the check to process the branchItem => root is always saved&Published as the intent requires it. Assert.AreEqual(PublishResultType.SuccessPublishCulture, r[1].Result); } @@ -378,7 +378,7 @@ public class ContentServicePublishBranchTests : UmbracoIntegrationTest AssertPublishResults( r, x => x.Result, - PublishResultType.SuccessPublishAlready, + PublishResultType.SuccessPublish, // During branch publishing, the change detection of the root branch runs AFTER the check to process the branchItem => root is always saved&Published as the intent requires it. PublishResultType.SuccessPublish, PublishResultType.SuccessPublishCulture); @@ -404,7 +404,7 @@ public class ContentServicePublishBranchTests : UmbracoIntegrationTest AssertPublishResults( r, x => x.Result, - PublishResultType.SuccessPublishAlready, + PublishResultType.SuccessPublish, // During branch publishing, the change detection of the root branch runs AFTER the check to process the branchItem => root is always saved&Published as the intent requires it. PublishResultType.SuccessPublish, PublishResultType.SuccessPublishCulture); 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(() => new MediaPicker3Configuration @@ -361,7 +359,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes } private void ValidateMedia( - ApiMediaWithCrops actual, + IApiMediaWithCrops actual, string expectedName, string expectedUrl, string expectedExtension, @@ -378,7 +376,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes } - private void ValidateFocalPoint(ImageCropperValue.ImageCropperFocalPoint? actual, decimal expectedLeft, decimal expectedTop) + private void ValidateFocalPoint(ImageFocalPoint? actual, decimal expectedLeft, decimal expectedTop) { Assert.NotNull(actual); Assert.AreEqual(expectedLeft, actual.Left); @@ -386,7 +384,7 @@ public class MediaPickerWithCropsValueConverterTests : PropertyValueConverterTes } private void ValidateCrop( - ImageCropperValue.ImageCropperCrop actual, + ImageCrop actual, string expectedAlias, int expectedWidth, int expectedHeight,