From 1a9f336a59bf8d34064d224de3d4b4c026be5bcb Mon Sep 17 00:00:00 2001 From: Niels Hartvig Date: Mon, 9 Jan 2017 14:45:40 +0100 Subject: [PATCH] Add support for GUIDs in media and content pickers --- .../mediaPicker/mediapicker.controller.js | 7 +- .../Editors/BackOfficeController.cs | 2 +- src/Umbraco.Web/Editors/MediaController.cs | 64 +++++++++++++++++-- .../Editors/MediaTypeController.cs | 19 +++++- .../Trees/ContentTreeController.cs | 6 +- .../Trees/ContentTreeControllerBase.cs | 60 ++++++++++++++--- 6 files changed, 137 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js index 43c65d99ee..3b6c39e84a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js @@ -1,7 +1,7 @@ //used for the media picker dialog angular.module("umbraco") .controller("Umbraco.Overlays.MediaPickerController", - function($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, $cookieStore, localizationService) { + function ($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, localStorageService, localizationService) { if (!$scope.model.title) { $scope.model.title = localizationService.localize("defaultdialogs_selectMedia"); @@ -15,7 +15,7 @@ angular.module("umbraco") $scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false; $scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1; $scope.cropSize = dialogOptions.cropSize; - $scope.lastOpenedNode = $cookieStore.get("umbLastOpenedMediaNodeId"); + $scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId"); if ($scope.onlyImages) { $scope.acceptedFileTypes = mediaHelper .formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes); @@ -133,8 +133,7 @@ angular.module("umbraco") }); $scope.currentFolder = folder; - // for some reason i cannot set cookies with cookieStore - document.cookie = "umbLastOpenedMediaNodeId=" + folder.id; + localStorageService.set("umbLastOpenedMediaNodeId", folder.id); }; diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 199ffd9bed..74e616e756 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -262,7 +262,7 @@ namespace Umbraco.Web.Editors }, { "mediaTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( - controller => controller.GetAllowedChildren(0)) + controller => controller.GetAllowedChildren("0")) }, { "macroApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 7a7e349a3c..1f95034c34 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -36,6 +36,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Persistence.FaultHandling; using Umbraco.Web.UI; using Notification = Umbraco.Web.Models.ContentEditing.Notification; +using Umbraco.Core.Persistence; namespace Umbraco.Web.Editors { @@ -175,7 +176,37 @@ namespace Umbraco.Web.Editors /// Returns the child media objects /// [FilterAllowedOutgoingMedia(typeof(IEnumerable>), "Items")] - public PagedResult> GetChildren(int id, + public PagedResult> GetChildren(string id, + int pageNumber = 0, + int pageSize = 0, + string orderBy = "SortOrder", + Direction orderDirection = Direction.Ascending, + bool orderBySystemField = true, + string filter = "") + { + int idInt; Guid idGuid; + + if (Guid.TryParse(id, out idGuid)) + { + var entity = Services.EntityService.GetByKey(idGuid); + if (entity != null) + { + return getChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter); + } + else + { + throw new EntityNotFoundException(id, "The passed id doesn't exist"); + } + } + else if (int.TryParse(id, out idInt)) + { + return getChildren(idInt, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter); + } + + throw new InvalidCastException("Id must be either an integer or a Guid"); + } + + private PagedResult> getChildren(int id, int pageNumber = 0, int pageSize = 0, string orderBy = "SortOrder", @@ -448,12 +479,37 @@ namespace Umbraco.Web.Editors } //get the string json from the request - int parentId; - if (int.TryParse(result.FormData["currentFolder"], out parentId) == false) + int parentId; bool entityFound; + string currentFolderId = result.FormData["currentFolder"]; + if (int.TryParse(currentFolderId, out parentId) == false) { - return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer"); + // if a guid then try to look up the entity + Guid idGuid; + if (Guid.TryParse(currentFolderId, out idGuid)) + { + var entity = Services.EntityService.GetByKey(idGuid); + if (entity != null) + { + entityFound = true; + parentId = entity.Id; + } + else + { + throw new EntityNotFoundException(currentFolderId, "The passed id doesn't exist"); + } + } + else + { + return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer or Guid"); + } + + if (entityFound == false) + { + return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer or Guid"); + } } + //ensure the user has access to this folder by parent id! if (CheckPermissions( new Dictionary(), diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index 0f83ad6d03..a40b83c9ea 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -11,6 +11,8 @@ using System.Net; using System.Net.Http; using Umbraco.Web.WebApi; using Umbraco.Core.Services; +using Umbraco.Core.Models.EntityBase; +using System; namespace Umbraco.Web.Editors { @@ -174,7 +176,22 @@ namespace Umbraco.Web.Editors /// /// [UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)] - public IEnumerable GetAllowedChildren(int contentId) + public IEnumerable GetAllowedChildren(string contentId) + { + Guid idGuid = Guid.Empty; + int idInt; + if (Guid.TryParse(contentId, out idGuid)) { + var entity = ApplicationContext.Services.EntityService.GetByKey(idGuid); + return getAllowedChildren(entity.Id); + } else if (int.TryParse(contentId, out idInt)) + { + return getAllowedChildren(idInt); + } + + throw new InvalidCastException("Id must be either an integer or a Guid"); + } + + private IEnumerable getAllowedChildren(int contentId) { if (contentId == Constants.System.RecycleBinContent) return Enumerable.Empty(); diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 9f33a44ea9..9a5f90ff89 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -202,11 +202,13 @@ namespace Umbraco.Web.Trees /// protected override bool HasPathAccess(string id, FormDataCollection queryStrings) { - var content = Services.ContentService.GetById(int.Parse(id)); - if (content == null) + var entity = GetEntityFromId(id); + if (entity == null) { return false; } + + IContent content = Services.ContentService.GetById(entity.Id); return Security.CurrentUser.HasPathAccess(content); } diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 3708c6fd4f..99ec60be75 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -96,7 +96,7 @@ namespace Umbraco.Web.Trees LogHelper.Warn("The user " + Security.CurrentUser.Username + " does not have access to the tree node " + id); return new TreeNodeCollection(); } - + // So there's an alt id specified, it's not the root node and the user has access to it, great! But there's one thing we // need to consider: // If the tree is being rendered in a dialog view we want to render only the children of the specified id, but @@ -110,7 +110,7 @@ namespace Umbraco.Web.Trees id = Constants.System.Root.ToString(CultureInfo.InvariantCulture); } } - + var entities = GetChildEntities(id); nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null)); return nodes; @@ -122,11 +122,24 @@ namespace Umbraco.Web.Trees protected IEnumerable GetChildEntities(string id) { + // use helper method to ensure we support both integer and guid lookups int iid; - if (int.TryParse(id, out iid) == false) + + // if it's the root node, we won't use the look up + if (id != "-1") { - throw new InvalidCastException("The id for the media tree must be an integer"); + var idEntity = GetEntityFromId(id); + if (idEntity == null) + { + throw new EntityNotFoundException(id, "The passed id doesn't exist"); + } + iid = idEntity.Id; } + else + { + iid = int.Parse(id); + } + //if a request is made for the root node data but the user's start node is not the default, then // we need to return their start node data @@ -134,11 +147,12 @@ namespace Umbraco.Web.Trees { //just return their single start node, it will show up under the 'Content' label var startNode = Services.EntityService.Get(UserStartNode, UmbracoObjectType); - if (startNode == null) + if (startNode != null) + return new[] { startNode }; + else { throw new EntityNotFoundException(UserStartNode, "User's start content node could not be found"); } - return new[] { startNode }; } return Services.EntityService.GetChildren(iid, UmbracoObjectType).ToArray(); @@ -176,9 +190,9 @@ namespace Umbraco.Web.Trees { id = altStartId; } - + var nodes = GetTreeNodesInternal(id, queryStrings); - + //only render the recycle bin if we are not in dialog and the start id id still the root if (IsDialog(queryStrings) == false && id == Constants.System.Root.ToInvariantString()) { @@ -210,8 +224,9 @@ namespace Umbraco.Web.Trees /// private TreeNodeCollection GetTreeNodesInternal(string id, FormDataCollection queryStrings) { + IUmbracoEntity current = GetEntityFromId(id); + //before we get the children we need to see if this is a container node - var current = Services.EntityService.Get(int.Parse(id), UmbracoObjectType); //test if the parent is a listview / container if (current != null && current.IsContainer()) @@ -286,5 +301,32 @@ namespace Umbraco.Web.Trees { return allowedUserOptions.Select(x => x.Action).OfType().Any(); } + + /// + /// Get an entity via an id that can be either an integer or a Guid + /// + /// + /// + internal IUmbracoEntity GetEntityFromId(string id) + { + IUmbracoEntity entity; + Guid idGuid = Guid.Empty; + int idInt; + if (Guid.TryParse(id, out idGuid)) + { + entity = Services.EntityService.GetByKey(idGuid, UmbracoObjectType); + + } + else if (int.TryParse(id, out idInt)) + { + entity = Services.EntityService.Get(idInt, UmbracoObjectType); + } + else + { + throw new InvalidCastException("Id must be either an integer or a Guid"); + } + + return entity; + } } } \ No newline at end of file