From 26382ab8d567d009a50df4ae5ad372d4bc602c09 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Mon, 27 Sep 2021 14:36:17 +0100 Subject: [PATCH 1/3] Add EntityController GetUrlsByUdis Enables loading multiple URLs in a single request for Media & Documents --- src/Umbraco.Web/Editors/EntityController.cs | 49 +++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index b6bef3fd9651..66173634185b 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -235,6 +235,55 @@ public HttpResponseMessage GetUrl(Udi udi, string culture = "*") return GetUrl(intId.Result, entityType, culture); } + /// + /// Get entity URLs by UDIs + /// + /// + /// A list of UDIs to lookup items by + /// + /// The culture to fetch the URL for + /// Dictionary mapping Udi -> Url + /// + /// We allow for POST because there could be quite a lot of Ids. + /// + [HttpGet] + [HttpPost] + public IDictionary GetUrlsByUdis([FromJsonPath] Udi[] ids, string culture = null) + { + if (ids == null) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + if (ids.Length == 0) + { + return new Dictionary(); + } + + // TODO: PMJ 2021-09-27 - Should GetUrl(Udi) exist as an extension method on UrlProvider/IUrlProvider (in v9) + string MediaOrDocumentUrl(Udi udi) + { + if (udi is not GuidUdi guidUdi) + { + return null; + } + + return guidUdi.EntityType switch + { + Constants.UdiEntityType.Document => UmbracoContext.UrlProvider.GetUrl(guidUdi.Guid, culture: culture ?? ClientCulture()), + // NOTE: If culture is passed here we get an empty string rather than a media item URL WAT + Constants.UdiEntityType.Media => UmbracoContext.UrlProvider.GetMediaUrl(guidUdi.Guid, culture: null), + _ => null + }; + } + + return ids + .Select(udi => new { + Udi = udi, + Url = MediaOrDocumentUrl(udi) + }).ToDictionary(x => x.Udi, x => x.Url); + } + /// /// Gets the URL of an entity /// From 4eb75799e7458ddebec05958b53e80b2030ad8d7 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Mon, 27 Sep 2021 14:39:04 +0100 Subject: [PATCH 2/3] Update content picker to use GetUrlsByUdis --- .../common/mocks/resources/entity.mocks.js | 13 +++++++ .../src/common/resources/entity.resource.js | 15 ++++++++ .../contentpicker/contentpicker.controller.js | 36 +++++++------------ 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js index 2c2007dd91b0..05594115e1d2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js @@ -34,6 +34,15 @@ angular.module('umbraco.mocks'). return [200, nodes, null]; } + function returnUrlsbyUdis(status, data, headers) { + + if (!mocksUtils.checkAuth()) { + return [401, null, null]; + } + + return [200, {}, null]; + } + function returnEntitybyIdsPost(method, url, data, headers) { if (!mocksUtils.checkAuth()) { @@ -73,6 +82,10 @@ angular.module('umbraco.mocks'). .whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetByIds')) .respond(returnEntitybyIdsPost); + $httpBackend + .whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetUrlsByUdis')) + .respond(returnUrlsbyUdis); + $httpBackend .whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetAncestors')) .respond(returnEntitybyIds); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js index 0b060da34bed..1c29a69c2dda 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js @@ -127,6 +127,21 @@ function entityResource($q, $http, umbRequestHelper) { 'Failed to retrieve url for id:' + id); }, + getUrlsByUdis: function(ids, culture) { + var query = "culture=" + (culture || ""); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "entityApiBaseUrl", + "GetUrlsByUdis", + query), + { + ids: ids + }), + 'Failed to retrieve url map for ids ' + ids); + }, + getUrlByUdi: function (udi, culture) { if (!udi) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index d8c7b3e76a62..7c8c1e64fbd7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -413,8 +413,13 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso var missingIds = _.difference(valueIds, renderModelIds); if (missingIds.length > 0) { - return entityResource.getByIds(missingIds, entityType).then(function (data) { + var requests = [ + entityResource.getByIds(missingIds, entityType), + entityResource.getUrlsByUdis(missingIds) + ]; + + return $q.all(requests).then(function ([data, urlMap]) { _.each(valueIds, function (id, i) { var entity = _.find(data, function (d) { @@ -422,7 +427,12 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso }); if (entity) { - addSelectedItem(entity); + + entity.url = entity.trashed + ? vm.labels.general_recycleBin + : urlMap[id]; + + addSelectedItem(entity); } }); @@ -469,26 +479,6 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso } - function setEntityUrl(entity) { - - // get url for content and media items - if (entityType !== "Member") { - entityResource.getUrl(entity.id, entityType).then(function (data) { - // update url - $scope.renderModel.forEach(function (item) { - if (item.id === entity.id) { - if (entity.trashed) { - item.url = vm.labels.general_recycleBin; - } else { - item.url = data; - } - } - }); - }); - } - - } - function addSelectedItem(item) { // set icon @@ -523,8 +513,6 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso "published": (item.metaData && item.metaData.IsPublished === false && entityType === "Document") ? false : true // only content supports published/unpublished content so we set everything else to published so the UI looks correct }); - - setEntityUrl(item); } function setSortingState(items) { From 106f6dce25fbf5be2c7fb6de27e47c645b683253 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Tue, 5 Oct 2021 13:45:43 +0100 Subject: [PATCH 3/3] Rename parameter for clarity --- .../src/common/resources/entity.resource.js | 6 +++--- src/Umbraco.Web/Editors/EntityController.cs | 13 ++++--------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js index 1c29a69c2dda..44be85b8fdd9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js @@ -127,7 +127,7 @@ function entityResource($q, $http, umbRequestHelper) { 'Failed to retrieve url for id:' + id); }, - getUrlsByUdis: function(ids, culture) { + getUrlsByUdis: function(udis, culture) { var query = "culture=" + (culture || ""); return umbRequestHelper.resourcePromise( @@ -137,9 +137,9 @@ function entityResource($q, $http, umbRequestHelper) { "GetUrlsByUdis", query), { - ids: ids + udis: udis }), - 'Failed to retrieve url map for ids ' + ids); + 'Failed to retrieve url map for udis ' + udis); }, getUrlByUdi: function (udi, culture) { diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 66173634185b..0b6273e79da8 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -238,7 +238,7 @@ public HttpResponseMessage GetUrl(Udi udi, string culture = "*") /// /// Get entity URLs by UDIs /// - /// + /// /// A list of UDIs to lookup items by /// /// The culture to fetch the URL for @@ -248,14 +248,9 @@ public HttpResponseMessage GetUrl(Udi udi, string culture = "*") /// [HttpGet] [HttpPost] - public IDictionary GetUrlsByUdis([FromJsonPath] Udi[] ids, string culture = null) + public IDictionary GetUrlsByUdis([FromJsonPath] Udi[] udis, string culture = null) { - if (ids == null) - { - throw new HttpResponseException(HttpStatusCode.NotFound); - } - - if (ids.Length == 0) + if (udis == null || udis.Length == 0) { return new Dictionary(); } @@ -277,7 +272,7 @@ string MediaOrDocumentUrl(Udi udi) }; } - return ids + return udis .Select(udi => new { Udi = udi, Url = MediaOrDocumentUrl(udi)