From 2719e2c23123c094016ab4ba47d541b1007595dc Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 25 Feb 2016 15:19:42 +0000 Subject: [PATCH 01/10] WIP - ListView that grabs the current nodes permission from the editorState & use a neater object to return to the view rather than the lovely Magic String CHARs. Need help understanding that I don't get all the permissions to be expected --- .../listview/listview.controller.js | 35 +++++++++++++++++-- .../propertyeditors/listview/listview.html | 12 ++++--- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 85e43c02ec..b22978526e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -1,4 +1,4 @@ -function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper) { +function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService) { //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content // that isn't created yet, if we continue this will use the parent id in the route params which isn't what @@ -59,6 +59,36 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie items: [] }; + + $scope.currentNodePermissions = {} + + //Just ensure we do have an editorState + if(editorState.current){ + + //Get Current User to check if their usertype is an admin (overwrites all permissions!) + userService.getCurrentUser().then(function(data){ + + //Fetch current node allowed actions for the current user + //This is the current node & not each individual child node in the list + var currentUserPermissions = editorState.current.allowedActions; + + //Create a nicer model rather than the funky & hard to remember permissions strings + $scope.currentNodePermissions = { + "isAdminUser": data.userType.toLowerCase() === "admin", + "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O + "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D + "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M + "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U + "canUnpublish": _.contains(currentUserPermissions, 'Z'), //Magic Char = Z + "rawPermissions": currentUserPermissions + }; + + }); + } + + + + $scope.options = { displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1, pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10, @@ -166,9 +196,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie getListResultsCallback(id, $scope.options).then(function(data) { $scope.actionInProgress = false; - $scope.listViewResultSet = data; - + //update all values for display if ($scope.listViewResultSet.items) { _.each($scope.listViewResultSet.items, function(e, index) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 0f8014529e..ee5fa32581 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -82,7 +82,7 @@ + +
{{ currentNodePermissions | json }}
From 7d8791ec8618663afee0bdf7ec6813bbd603aef4 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 25 Feb 2016 17:05:44 +0100 Subject: [PATCH 02/10] Fix ActionButtonsResolver (need review) --- .../Models/Mapping/ContentModelMapper.cs | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 2c9a6410b4..1f36eb6c5b 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -292,35 +292,9 @@ namespace Umbraco.Web.Models.Mapping source.HasIdentity ? source.Id : source.ParentId) .FirstOrDefault(); - if (permissions == null) - { - return Enumerable.Empty(); - } - - var result = new List(); - - //can they publish ? - if (permissions.AssignedPermissions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture))) - { - result.Add(ActionPublish.Instance.Letter); - } - //can they send to publish ? - if (permissions.AssignedPermissions.Contains(ActionToPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture))) - { - result.Add(ActionToPublish.Instance.Letter); - } - //can they save ? - if (permissions.AssignedPermissions.Contains(ActionUpdate.Instance.Letter.ToString(CultureInfo.InvariantCulture))) - { - result.Add(ActionUpdate.Instance.Letter); - } - //can they create ? - if (permissions.AssignedPermissions.Contains(ActionNew.Instance.Letter.ToString(CultureInfo.InvariantCulture))) - { - result.Add(ActionNew.Instance.Letter); - } - - return result; + return permissions == null + ? Enumerable.Empty() + : permissions.AssignedPermissions.Where(x => x.Length == 1).Select(x => x.ToUpperInvariant()[0]); } } From 36246b96d49d70dbe9509a69a755d6295b195a41 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 25 Feb 2016 17:39:34 +0100 Subject: [PATCH 03/10] Fix bug with permissions cache refresh --- src/Umbraco.Web/Cache/UserCacheRefresher.cs | 2 +- src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index 2f8a370cd4..6f9cc7db80 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -49,7 +49,7 @@ namespace Umbraco.Web.Cache userCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); if (UserPermissionsCache) - UserPermissionsCache.Result.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + UserPermissionsCache.Result.ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs index 64744024ed..eed29ff764 100644 --- a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { if (UserPermissionsCache) - UserPermissionsCache.Result.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + UserPermissionsCache.Result.ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); base.Remove(id); } From c616354522d9566ddeadc8705c5e804aab8956bd Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 25 Feb 2016 20:49:56 +0000 Subject: [PATCH 04/10] After reading src code for contentEditorHelper.configureContentEditorButtons it makes the same assumption that if the publish action 'U' is present then the user can also unpublish aka 'Z' --- .../src/views/propertyeditors/listview/listview.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index b22978526e..b516aad062 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -79,7 +79,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U - "canUnpublish": _.contains(currentUserPermissions, 'Z'), //Magic Char = Z + "canUnpublish": _.contains(currentUserPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish) "rawPermissions": currentUserPermissions }; From 956425dfbf316f0ef9ba0f2b166ce049630bd8d4 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 25 Feb 2016 21:06:25 +0000 Subject: [PATCH 05/10] Now updated so the create button hides if we do not have the Create permission 'C' --- .../src/views/propertyeditors/listview/listview.controller.js | 1 + .../src/views/propertyeditors/listview/listview.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index b516aad062..665ff22cd3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -76,6 +76,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.currentNodePermissions = { "isAdminUser": data.userType.toLowerCase() === "admin", "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O + "canCreate": _.contains(currentUserPermissions, 'C'), //Magic Char = C "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index ee5fa32581..c2657459a0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -10,7 +10,7 @@ - +
Create From c7a3efadb12d51eb3f706593d02c2de310749c91 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 25 Feb 2016 21:09:12 +0000 Subject: [PATCH 06/10] Remove debug JSON in the view --- .../src/views/propertyeditors/listview/listview.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index c2657459a0..a7a94ff53a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -152,8 +152,6 @@ entity-type="{{entityType}}" on-get-content="reloadView"> - -
{{ currentNodePermissions | json }}
From 372a768dca24e2eb8e579b8f63b61f3736dc83ca Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 8 Mar 2016 15:53:22 +0100 Subject: [PATCH 07/10] U4-4700 List view doesn't respect user permissions - makes the buttons show/hide based on the selected items instead of the current item. --- .../src/common/resources/content.resource.js | 10 + .../common/services/listviewhelper.service.js | 493 ++++++++++-------- .../src/common/services/util.service.js | 2 +- .../listview/listview.controller.js | 72 ++- .../propertyeditors/listview/listview.html | 10 +- .../test/config/app.unit.js | 3 +- .../test/config/karma.conf.js | 2 +- .../common/services/list-view-helper.spec.js | 48 ++ src/Umbraco.Web/Editors/ContentController.cs | 16 +- 9 files changed, 387 insertions(+), 269 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/test/unit/common/services/list-view-helper.spec.js diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js index 5aa56a80af..2cf7127707 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js @@ -509,6 +509,16 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { 'Failed to check permission for item ' + id); }, + getPermissions: function (nodeIds) { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetPermissions"), + nodeIds), + 'Failed to get permissions'); + }, + /** * @ngdoc method * @name umbraco.resources.contentResource#save diff --git a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js index 428b9f4323..e211218ce1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js @@ -1,288 +1,319 @@ -(function() { - 'use strict'; +(function () { + 'use strict'; - function listViewHelper(localStorageService) { + function listViewHelper(localStorageService) { - var firstSelectedIndex = 0; - var localStorageKey = "umblistViewLayout"; + var firstSelectedIndex = 0; + var localStorageKey = "umblistViewLayout"; - function getLayout(nodeId, availableLayouts) { + function getLayout(nodeId, availableLayouts) { - var storedLayouts = []; + var storedLayouts = []; - if(localStorageService.get(localStorageKey)) { - storedLayouts = localStorageService.get(localStorageKey); - } - - if (storedLayouts && storedLayouts.length > 0) { - for (var i = 0; storedLayouts.length > i; i++) { - var layout = storedLayouts[i]; - if (layout.nodeId === nodeId) { - return setLayout(nodeId, layout, availableLayouts); - } - } - - } - - return getFirstAllowedLayout(availableLayouts); - - } - - function setLayout(nodeId, selectedLayout, availableLayouts) { - - var activeLayout = {}; - var layoutFound = false; - - for (var i = 0; availableLayouts.length > i; i++) { - var layout = availableLayouts[i]; - if (layout.path === selectedLayout.path) { - activeLayout = layout; - layout.active = true; - layoutFound = true; - } else { - layout.active = false; - } - } - - if(!layoutFound) { - activeLayout = getFirstAllowedLayout(availableLayouts); - } - - saveLayoutInLocalStorage(nodeId, activeLayout); - - return activeLayout; - - } - - function saveLayoutInLocalStorage(nodeId, selectedLayout) { - var layoutFound = false; - var storedLayouts = []; - - if(localStorageService.get(localStorageKey)) { - storedLayouts = localStorageService.get(localStorageKey); - } - - if(storedLayouts.length > 0) { - for(var i = 0; storedLayouts.length > i; i++) { - var layout = storedLayouts[i]; - if(layout.nodeId === nodeId) { - layout.path = selectedLayout.path; - layoutFound = true; - } - } - } - - if(!layoutFound) { - var storageObject = { - "nodeId": nodeId, - "path": selectedLayout.path - }; - storedLayouts.push(storageObject); - } - - localStorageService.set(localStorageKey, storedLayouts); - - } - - function getFirstAllowedLayout(layouts) { - - var firstAllowedLayout = {}; - - for (var i = 0; layouts.length > i; i++) { - var layout = layouts[i]; - if (layout.selected === true) { - firstAllowedLayout = layout; - break; + if (localStorageService.get(localStorageKey)) { + storedLayouts = localStorageService.get(localStorageKey); } - } - return firstAllowedLayout; - } + if (storedLayouts && storedLayouts.length > 0) { + for (var i = 0; storedLayouts.length > i; i++) { + var layout = storedLayouts[i]; + if (layout.nodeId === nodeId) { + return setLayout(nodeId, layout, availableLayouts); + } + } - function selectHandler(selectedItem, selectedIndex, items, selection, $event) { + } - var start = 0; - var end = 0; - var item = null; + return getFirstAllowedLayout(availableLayouts); - if ($event.shiftKey === true) { + } - if(selectedIndex > firstSelectedIndex) { + function setLayout(nodeId, selectedLayout, availableLayouts) { - start = firstSelectedIndex; - end = selectedIndex; + var activeLayout = {}; + var layoutFound = false; - for (; end >= start; start++) { - item = items[start]; - selectItem(item, selection); - } + for (var i = 0; availableLayouts.length > i; i++) { + var layout = availableLayouts[i]; + if (layout.path === selectedLayout.path) { + activeLayout = layout; + layout.active = true; + layoutFound = true; + } else { + layout.active = false; + } + } + + if (!layoutFound) { + activeLayout = getFirstAllowedLayout(availableLayouts); + } + + saveLayoutInLocalStorage(nodeId, activeLayout); + + return activeLayout; + + } + + function saveLayoutInLocalStorage(nodeId, selectedLayout) { + var layoutFound = false; + var storedLayouts = []; + + if (localStorageService.get(localStorageKey)) { + storedLayouts = localStorageService.get(localStorageKey); + } + + if (storedLayouts.length > 0) { + for (var i = 0; storedLayouts.length > i; i++) { + var layout = storedLayouts[i]; + if (layout.nodeId === nodeId) { + layout.path = selectedLayout.path; + layoutFound = true; + } + } + } + + if (!layoutFound) { + var storageObject = { + "nodeId": nodeId, + "path": selectedLayout.path + }; + storedLayouts.push(storageObject); + } + + localStorageService.set(localStorageKey, storedLayouts); + + } + + function getFirstAllowedLayout(layouts) { + + var firstAllowedLayout = {}; + + for (var i = 0; layouts.length > i; i++) { + var layout = layouts[i]; + if (layout.selected === true) { + firstAllowedLayout = layout; + break; + } + } + + return firstAllowedLayout; + } + + function selectHandler(selectedItem, selectedIndex, items, selection, $event) { + + var start = 0; + var end = 0; + var item = null; + + if ($event.shiftKey === true) { + + if (selectedIndex > firstSelectedIndex) { + + start = firstSelectedIndex; + end = selectedIndex; + + for (; end >= start; start++) { + item = items[start]; + selectItem(item, selection); + } + + } else { + + start = firstSelectedIndex; + end = selectedIndex; + + for (; end <= start; start--) { + item = items[start]; + selectItem(item, selection); + } + + } } else { - start = firstSelectedIndex; - end = selectedIndex; + if (selectedItem.selected) { + deselectItem(selectedItem, selection); + } else { + selectItem(selectedItem, selection); + } - for (; end <= start; start--) { - item = items[start]; - selectItem(item, selection); - } + firstSelectedIndex = selectedIndex; } - } else { + } - if(selectedItem.selected) { - deselectItem(selectedItem, selection); - } else { - selectItem(selectedItem, selection); + function selectItem(item, selection) { + var isSelected = false; + for (var i = 0; selection.length > i; i++) { + var selectedItem = selection[i]; + if (item.id === selectedItem.id) { + isSelected = true; + } + } + if (!isSelected) { + selection.push({ id: item.id }); + item.selected = true; + } + } + + function deselectItem(item, selection) { + for (var i = 0; selection.length > i; i++) { + var selectedItem = selection[i]; + if (item.id === selectedItem.id) { + selection.splice(i, 1); + item.selected = false; + } + } + } + + function clearSelection(items, folders, selection) { + + var i = 0; + + selection.length = 0; + + if (angular.isArray(items)) { + for (i = 0; items.length > i; i++) { + var item = items[i]; + item.selected = false; + } } - firstSelectedIndex = selectedIndex; - - } - - } - - function selectItem(item, selection) { - var isSelected = false; - for (var i = 0; selection.length > i; i++) { - var selectedItem = selection[i]; - if (item.id === selectedItem.id) { - isSelected = true; + if (angular.isArray(items)) { + for (i = 0; folders.length > i; i++) { + var folder = folders[i]; + folder.selected = false; + } } - } - if(!isSelected) { - selection.push({id: item.id}); - item.selected = true; - } - } + } - function deselectItem(item, selection) { - for (var i = 0; selection.length > i; i++) { - var selectedItem = selection[i]; - if (item.id === selectedItem.id) { - selection.splice(i, 1); - item.selected = false; + function selectAllItems(items, selection, $event) { + + var checkbox = $event.target; + var clearSelection = false; + + if (!angular.isArray(items)) { + return; } - } - } - function clearSelection(items, folders, selection) { + selection.length = 0; - var i = 0; + for (var i = 0; i < items.length; i++) { - selection.length = 0; + var item = items[i]; + + if (checkbox.checked) { + selection.push({ id: item.id }); + } else { + clearSelection = true; + } + + item.selected = checkbox.checked; - if(angular.isArray(items)) { - for(i = 0; items.length > i; i++) { - var item = items[i]; - item.selected = false; } - } - if(angular.isArray(items)) { - for(i = 0; folders.length > i; i++) { - var folder = folders[i]; - folder.selected = false; + if (clearSelection) { + selection.length = 0; } - } - } - function selectAllItems(items, selection, $event) { + } - var checkbox = $event.target; - var clearSelection = false; + function isSelectedAll(items, selection) { - if (!angular.isArray(items)) { - return; - } + var numberOfSelectedItem = 0; - selection.length = 0; + for (var itemIndex = 0; items.length > itemIndex; itemIndex++) { + var item = items[itemIndex]; - for (var i = 0; i < items.length; i++) { + for (var selectedIndex = 0; selection.length > selectedIndex; selectedIndex++) { + var selectedItem = selection[selectedIndex]; - var item = items[i]; + if (item.id === selectedItem.id) { + numberOfSelectedItem++; + } + } - if (checkbox.checked) { - selection.push({id: item.id}); - } else { - clearSelection = true; - } + } - item.selected = checkbox.checked; + if (numberOfSelectedItem === items.length) { + return true; + } - } + } - if (clearSelection) { - selection.length = 0; - } + function setSortingDirection(col, direction, options) { + return options.orderBy.toUpperCase() === col.toUpperCase() && options.orderDirection === direction; + } - } + function setSorting(field, allow, options) { + if (allow) { + options.orderBy = field; - function isSelectedAll(items, selection) { + if (options.orderDirection === "desc") { + options.orderDirection = "asc"; + } else { + options.orderDirection = "desc"; + } + } + } + + //This takes in a dictionary of Ids with Permissions and determines + // the intersect of all permissions to return an object representing the + // listview button permissions + function getButtonPermissions(unmergedPermissions, currentIdsWithPermissions) { + + if (currentIdsWithPermissions == null) { + currentIdsWithPermissions = {}; + } - var numberOfSelectedItem = 0; + //merge the newly retrieved permissions to the main dictionary + _.each(unmergedPermissions, function (value, key, list) { + currentIdsWithPermissions[key] = value; + }); - for(var itemIndex = 0; items.length > itemIndex; itemIndex++) { - var item = items[itemIndex]; + //get the intersect permissions + var arr = []; + _.each(currentIdsWithPermissions, function (value, key, list) { + arr.push(value); + }); - for(var selectedIndex = 0; selection.length > selectedIndex; selectedIndex++) { - var selectedItem = selection[selectedIndex]; + //we need to use 'apply' to call intersection with an array of arrays, + //see: http://stackoverflow.com/a/16229480/694494 + var intersectPermissions = _.intersection.apply(_, arr); - if(item.id === selectedItem.id) { - numberOfSelectedItem++; - } - } + return { + canCopy: _.contains(intersectPermissions, 'O'), //Magic Char = O + canCreate: _.contains(intersectPermissions, 'C'), //Magic Char = C + canDelete: _.contains(intersectPermissions, 'D'), //Magic Char = D + canMove: _.contains(intersectPermissions, 'M'), //Magic Char = M + canPublish: _.contains(intersectPermissions, 'U'), //Magic Char = U + canUnpublish: _.contains(intersectPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish) + }; + } - } + var service = { + getLayout: getLayout, + getFirstAllowedLayout: getFirstAllowedLayout, + setLayout: setLayout, + saveLayoutInLocalStorage: saveLayoutInLocalStorage, + selectHandler: selectHandler, + selectItem: selectItem, + deselectItem: deselectItem, + clearSelection: clearSelection, + selectAllItems: selectAllItems, + isSelectedAll: isSelectedAll, + setSortingDirection: setSortingDirection, + setSorting: setSorting, + getButtonPermissions: getButtonPermissions + }; - if(numberOfSelectedItem === items.length) { - return true; - } + return service; - } + } - function setSortingDirection(col, direction, options) { - return options.orderBy.toUpperCase() === col.toUpperCase() && options.orderDirection === direction; - } - - - function setSorting(field, allow, options) { - if (allow) { - options.orderBy = field; - - if (options.orderDirection === "desc") { - options.orderDirection = "asc"; - } else { - options.orderDirection = "desc"; - } - } - } - - - - var service = { - getLayout: getLayout, - getFirstAllowedLayout: getFirstAllowedLayout, - setLayout: setLayout, - saveLayoutInLocalStorage: saveLayoutInLocalStorage, - selectHandler: selectHandler, - selectItem: selectItem, - deselectItem: deselectItem, - clearSelection: clearSelection, - selectAllItems: selectAllItems, - isSelectedAll: isSelectedAll, - setSortingDirection: setSortingDirection, - setSorting: setSorting - }; - - return service; - - } - - - angular.module('umbraco.services').factory('listViewHelper', listViewHelper); + angular.module('umbraco.services').factory('listViewHelper', listViewHelper); })(); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js index 554790b6d0..9fbf2947af 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js @@ -21,6 +21,7 @@ function packageHelper(assetsService, treeService, eventsService, $templateCache } angular.module('umbraco.services').factory('packageHelper', packageHelper); +//TODO: I believe this is obsolete function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, mediaHelper, umbRequestHelper) { return { /** sets the image's url, thumbnail and if its a folder */ @@ -319,7 +320,6 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me } }; } - angular.module("umbraco.services").factory("umbPhotoFolderHelper", umbPhotoFolderHelper); /** diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 665ff22cd3..572969f753 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -58,37 +58,53 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie totalPages: 0, items: [] }; - - - $scope.currentNodePermissions = {} - //Just ensure we do have an editorState - if(editorState.current){ - - //Get Current User to check if their usertype is an admin (overwrites all permissions!) - userService.getCurrentUser().then(function(data){ - - //Fetch current node allowed actions for the current user - //This is the current node & not each individual child node in the list - var currentUserPermissions = editorState.current.allowedActions; - - //Create a nicer model rather than the funky & hard to remember permissions strings - $scope.currentNodePermissions = { - "isAdminUser": data.userType.toLowerCase() === "admin", - "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O - "canCreate": _.contains(currentUserPermissions, 'C'), //Magic Char = C - "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D - "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M - "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U - "canUnpublish": _.contains(currentUserPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish) - "rawPermissions": currentUserPermissions - }; - + //when this is null, we don't check permissions + $scope.buttonPermissions = null; + + //When we are dealing with 'content', we need to deal with permissions on child nodes. + // Currently there is no real good way to + if ($scope.entityType = "content") { + + var idsWithPermissions = null; + var intersectPermissions = null; + + $scope.buttonPermissions = { + canCopy: true, + canCreate: true, + canDelete: true, + canMove: true, + canPublish: true, + canUnpublish: true + }; + + $scope.$watch(function() { + return $scope.selection.length; + }, function(newVal, oldVal) { + + if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) { + + //go get the permissions for the selected items + var ids = _.map($scope.selection, function(i) { + return i.id; + }); + + //remove the dictionary items that don't have matching ids + var filtered = {}; + _.each(idsWithPermissions, function (value, key, list) { + if (_.contains(ids, Number(key))) { + filtered[key] = value; + } + }); + idsWithPermissions = filtered; + + contentResource.getPermissions(ids).then(function (p) { + $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions); + }); + } }); - } - - + } $scope.options = { displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1, diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index a7a94ff53a..904939b75f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -82,7 +82,7 @@ + /// Returns permissions for all nodes passed in for the current user + /// + /// + /// + [HttpPost] + public Dictionary GetPermissions(int[] nodeIds) + { + return Services.UserService + .GetPermissions(Security.CurrentUser, nodeIds) + .ToDictionary(x => x.EntityId, x => x.AssignedPermissions); + } + [HttpGet] public bool HasPermission(string permissionToCheck, int nodeId) { @@ -352,9 +366,7 @@ namespace Umbraco.Web.Editors return display; } - - /// /// Publishes a document with a given ID /// From 2a2f22c7d90e07015e6724c60591d9e12e00c49f Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 8 Mar 2016 15:53:45 +0100 Subject: [PATCH 08/10] fixes js null issue with boolean.controller --- .../src/views/propertyeditors/boolean/boolean.controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js index 59bc155bf5..aba7fddd1f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/boolean/boolean.controller.js @@ -4,8 +4,8 @@ function booleanEditorController($scope, $rootScope, assetsService) { $scope.renderModel = { value: false }; - - if($scope.model.config.default.toString() === "1" && $scope.model && !$scope.model.value) { + + if ($scope.model.config.default && $scope.model.config.default.toString() === "1" && $scope.model && !$scope.model.value) { $scope.renderModel.value = true; } From 402a5c9d5606b3ec2592a8e339f7688032c795a5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 8 Mar 2016 15:57:59 +0100 Subject: [PATCH 09/10] fixes bool check --- .../src/views/propertyeditors/listview/listview.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 572969f753..1b25fc5339 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -64,7 +64,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie //When we are dealing with 'content', we need to deal with permissions on child nodes. // Currently there is no real good way to - if ($scope.entityType = "content") { + if ($scope.entityType === "content") { var idsWithPermissions = null; var intersectPermissions = null; From a2564bd0c3fb435ef4e25e81957dd9964dd56e58 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 8 Mar 2016 16:18:33 +0100 Subject: [PATCH 10/10] ensures that requests are only made for ids that haven't already been queried. --- .../listview/listview.controller.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 1b25fc5339..5aade0cac0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -67,7 +67,6 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie if ($scope.entityType === "content") { var idsWithPermissions = null; - var intersectPermissions = null; $scope.buttonPermissions = { canCopy: true, @@ -83,24 +82,35 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie }, function(newVal, oldVal) { if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) { - - //go get the permissions for the selected items + + //get all of the selected ids var ids = _.map($scope.selection, function(i) { - return i.id; + return i.id.toString(); }); //remove the dictionary items that don't have matching ids var filtered = {}; _.each(idsWithPermissions, function (value, key, list) { - if (_.contains(ids, Number(key))) { + if (_.contains(ids, key)) { filtered[key] = value; - } + } }); idsWithPermissions = filtered; - contentResource.getPermissions(ids).then(function (p) { - $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions); + //find all ids that we haven't looked up permissions for + var existingIds = _.keys(idsWithPermissions); + var missingLookup = _.map(_.difference(ids, existingIds), function (i) { + return Number(i); }); + + if (missingLookup.length > 0) { + contentResource.getPermissions(missingLookup).then(function(p) { + $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions); + }); + } + else { + $scope.buttonPermissions = listViewHelper.getButtonPermissions({}, idsWithPermissions); + } } });