' +
'
' +
'
' +
@@ -310,6 +310,25 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
}
+ /** Returns the css classses assigned to the node (div element) */
+ scope.getNodeCssClass = function (node) {
+ if (!node) {
+ return '';
+ }
+
+ //TODO: This is called constantly because as a method in a template it's re-evaluated pretty much all the time
+ // it would be better if we could cache the processing. The problem is that some of these things are dynamic.
+
+ var css = [];
+ if (node.cssClasses) {
+ _.each(node.cssClasses, function (c) {
+ css.push(c);
+ });
+ }
+
+ return css.join(" ");
+ };
+
scope.selectEnabledNodeClass = function (node) {
return node ?
node.selected ?
@@ -383,6 +402,12 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
defined on the tree
*/
scope.select = function (n, ev) {
+
+ if (n.metaData && n.metaData.noAccess === true) {
+ ev.preventDefault();
+ return;
+ }
+
//on tree select we need to remove the current node -
// whoever handles this will need to make sure the correct node is selected
//reset current node selection
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js
index b32942791c..25c1becc87 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js
@@ -41,7 +41,7 @@ angular.module("umbraco.directives")
//'
' +
'
' +
'
' +
- '
' +
+ '
' +
//NOTE: These are the 'option' elipses
'
' +
'
' +
@@ -112,6 +112,10 @@ angular.module("umbraco.directives")
if (!node) {
return '';
}
+
+ //TODO: This is called constantly because as a method in a template it's re-evaluated pretty much all the time
+ // it would be better if we could cache the processing. The problem is that some of these things are dynamic.
+
var css = [];
if (node.cssClasses) {
_.each(node.cssClasses, function(c) {
@@ -121,6 +125,7 @@ angular.module("umbraco.directives")
if (node.selected) {
css.push("umb-tree-node-checked");
}
+
return css.join(" ");
};
@@ -158,6 +163,11 @@ angular.module("umbraco.directives")
return;
}
+ if (n.metaData && n.metaData.noAccess === true) {
+ ev.preventDefault();
+ return;
+ }
+
emitEvent("treeNodeSelect", { element: element, tree: scope.tree, node: n, event: ev });
ev.preventDefault();
};
@@ -229,6 +239,12 @@ angular.module("umbraco.directives")
setupNodeDom(scope.node, scope.tree);
+ // load the children if the current user don't have access to the node
+ // it is used to auto expand the tree to the start nodes the user has access to
+ if(scope.node.hasChildren && scope.node.metaData.noAccess) {
+ scope.loadChildren(scope.node);
+ }
+
var template = '
';
var newElement = angular.element(template);
$compile(newElement)(scope);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
index c692fda7ba..8738c1011e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
@@ -44,7 +44,7 @@ angular.module('umbraco.services')
return entityResource.search(args.term, "Member", args.searchFrom).then(function (data) {
_.each(data, function (item) {
- configureMemberResult(item);
+ searchResultFormatter.configureMemberResult(item);
});
return data;
});
@@ -69,7 +69,7 @@ angular.module('umbraco.services')
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler).then(function (data) {
_.each(data, function (item) {
- configureContentResult(item);
+ searchResultFormatter.configureContentResult(item);
});
return data;
});
@@ -94,7 +94,7 @@ angular.module('umbraco.services')
return entityResource.search(args.term, "Media", args.searchFrom).then(function (data) {
_.each(data, function (item) {
- configureMediaResult(item);
+ searchResultFormatter.configureMediaResult(item);
});
return data;
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
index 5469c12c30..888a067a66 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
@@ -44,52 +44,69 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
if (!parentNode.section) {
parentNode.section = section;
}
+
+ if (parentNode.metaData && parentNode.metaData.noAccess === true) {
+ if (!parentNode.cssClasses) {
+ parentNode.cssClasses = [];
+ }
+ parentNode.cssClasses.push("no-access");
+ }
+
//create a method outside of the loop to return the parent - otherwise jshint blows up
var funcParent = function() {
return parentNode;
};
for (var i = 0; i < treeNodes.length; i++) {
- treeNodes[i].level = childLevel;
+ var treeNode = treeNodes[i];
+
+ treeNode.level = childLevel;
//create a function to get the parent node, we could assign the parent node but
// then we cannot serialize this entity because we have a cyclical reference.
// Instead we just make a function to return the parentNode.
- treeNodes[i].parent = funcParent;
+ treeNode.parent = funcParent;
//set the section for each tree node - this allows us to reference this easily when accessing tree nodes
- treeNodes[i].section = section;
+ treeNode.section = section;
//if there is not route path specified, then set it automatically,
//if this is a tree root node then we want to route to the section's dashboard
- if (!treeNodes[i].routePath) {
+ if (!treeNode.routePath) {
- if (treeNodes[i].metaData && treeNodes[i].metaData["treeAlias"]) {
+ if (treeNode.metaData && treeNode.metaData["treeAlias"]) {
//this is a root node
- treeNodes[i].routePath = section;
+ treeNode.routePath = section;
}
else {
- var treeAlias = this.getTreeAlias(treeNodes[i]);
- treeNodes[i].routePath = section + "/" + treeAlias + "/edit/" + treeNodes[i].id;
+ var treeAlias = this.getTreeAlias(treeNode);
+ treeNode.routePath = section + "/" + treeAlias + "/edit/" + treeNode.id;
}
}
-
+
//now, format the icon data
- if (treeNodes[i].iconIsClass === undefined || treeNodes[i].iconIsClass) {
- var converted = iconHelper.convertFromLegacyTreeNodeIcon(treeNodes[i]);
- treeNodes[i].cssClass = standardCssClass + " " + converted;
+ if (treeNode.iconIsClass === undefined || treeNode.iconIsClass) {
+ var converted = iconHelper.convertFromLegacyTreeNodeIcon(treeNode);
+ treeNode.cssClass = standardCssClass + " " + converted;
if (converted.startsWith('.')) {
//its legacy so add some width/height
- treeNodes[i].style = "height:16px;width:16px;";
+ treeNode.style = "height:16px;width:16px;";
}
else {
- treeNodes[i].style = "";
+ treeNode.style = "";
}
}
else {
- treeNodes[i].style = "background-image: url('" + treeNodes[i].iconFilePath + "');";
+ treeNode.style = "background-image: url('" + treeNode.iconFilePath + "');";
//we need an 'icon-' class in there for certain styles to work so if it is image based we'll add this
- treeNodes[i].cssClass = standardCssClass + " legacy-custom-file";
+ treeNode.cssClass = standardCssClass + " legacy-custom-file";
+ }
+
+ if (treeNode.metaData && treeNode.metaData.noAccess === true) {
+ if (!treeNode.cssClasses) {
+ treeNode.cssClasses = [];
+ }
+ treeNode.cssClasses.push("no-access");
}
}
},
@@ -375,9 +392,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
}
for (var i = 0; i < treeNode.children.length; i++) {
- if (treeNode.children[i].children && angular.isArray(treeNode.children[i].children) && treeNode.children[i].children.length > 0) {
+ var child = treeNode.children[i];
+ if (child.children && angular.isArray(child.children) && child.children.length > 0) {
//recurse
- found = this.getDescendantNode(treeNode.children[i], id);
+ found = this.getDescendantNode(child, id);
if (found) {
return found;
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less
index 5de27de9f3..c859fae991 100644
--- a/src/Umbraco.Web.UI.Client/src/less/tree.less
+++ b/src/Umbraco.Web.UI.Client/src/less/tree.less
@@ -377,6 +377,13 @@ div.locked:before{
bottom: 0;
}
+.umb-tree li div.no-access .umb-tree-icon,
+.umb-tree li div.no-access .root-link,
+.umb-tree li div.no-access .umb-tree-item__label {
+ color: @gray-7;
+ cursor: not-allowed;
+}
+
// Tree context menu
// -------------------------
.umb-actions {
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js
index 6820e81f31..b18aa96588 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js
@@ -169,10 +169,10 @@ angular.module("umbraco")
$scope.showPasswordFields = !$scope.showPasswordFields;
}
- function clearPasswordFields() {
+ function clearPasswordFields() {
$scope.changePasswordModel.value.oldPassword = "";
$scope.changePasswordModel.value.newPassword = "";
$scope.changePasswordModel.value.confirm = "";
}
-
+
});
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js
index 9940aebe64..fa2d831eac 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/content.copy.controller.js
@@ -1,5 +1,5 @@
angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
- function ($scope, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
+ function ($scope, userService, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
var dialogOptions = $scope.dialogOptions;
var searchText = "Search...";
@@ -18,6 +18,12 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
results: [],
selectedSearchResults: []
}
+ $scope.treeModel = {
+ hideHeader: false
+ }
+ userService.getCurrentUser().then(function (userData) {
+ $scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
+ });
var node = dialogOptions.currentNode;
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js
index ce81a60a38..984c147ee4 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/content.move.controller.js
@@ -1,5 +1,5 @@
angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
- function ($scope, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
+ function ($scope, userService, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
var dialogOptions = $scope.dialogOptions;
var searchText = "Search...";
@@ -15,7 +15,13 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
showSearch: false,
results: [],
selectedSearchResults: []
- }
+ }
+ $scope.treeModel = {
+ hideHeader: false
+ }
+ userService.getCurrentUser().then(function (userData) {
+ $scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
+ });
var node = dialogOptions.currentNode;
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/copy.html b/src/Umbraco.Web.UI.Client/src/views/content/copy.html
index c19ec72dbd..ca7714c284 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/copy.html
+++ b/src/Umbraco.Web.UI.Client/src/views/content/copy.html
@@ -48,7 +48,7 @@
-
0 && userData.startMediaIds.indexOf(-1) == -1;
+ });
+
function nodeSelectHandler(ev, args) {
if(args && args.event) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/media/move.html b/src/Umbraco.Web.UI.Client/src/views/media/move.html
index 52be1832f0..d04d66f706 100644
--- a/src/Umbraco.Web.UI.Client/src/views/media/move.html
+++ b/src/Umbraco.Web.UI.Client/src/views/media/move.html
@@ -27,7 +27,7 @@
(user);
+ var result = Mapper.Map(user);
+ return result;
}
///
diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
index 356a09a556..6c40643766 100644
--- a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
@@ -249,7 +249,7 @@ namespace Umbraco.Web.Models.Mapping
user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService),
applicationContext.Services.TextService,
applicationContext.Services.EntityService,
- UmbracoObjectTypes.Document,
+ UmbracoObjectTypes.Media,
"media/mediaRoot")))
.ForMember(
detail => detail.StartContentIds,
diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs
index 9b3a6e82f8..ea644f5dc8 100644
--- a/src/Umbraco.Web/Trees/ContentTreeController.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeController.cs
@@ -41,22 +41,8 @@ namespace Umbraco.Web.Trees
[SearchableTree("searchResultFormatter", "configureContentResult")]
public class ContentTreeController : ContentTreeControllerBase, ISearchableTree
{
-
private readonly UmbracoTreeSearcher _treeSearcher = new UmbracoTreeSearcher();
-
- protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
- {
- var node = base.CreateRootNode(queryStrings);
-
- // if the user's start node is not default, then ensure the root doesn't have a menu
- if (UserStartNodes.Contains(Constants.System.Root) == false)
- {
- node.MenuUrl = "";
- }
- node.Name = ui.Text("sections", Constants.Trees.Content);
- return node;
- }
-
+
protected override int RecycleBinId
{
get { return Constants.System.RecycleBinContent; }
@@ -123,14 +109,17 @@ namespace Umbraco.Web.Trees
}
protected override MenuItemCollection PerformGetMenuForNode(string id, FormDataCollection queryStrings)
- {
+ {
if (id == Constants.System.Root.ToInvariantString())
{
var menu = new MenuItemCollection();
- // if the user's start node is not the root then ensure the root menu is empty/doesn't exist
+ // if the user's start node is not the root then the only menu item to display is refresh
if (UserStartNodes.Contains(Constants.System.Root) == false)
{
+ menu.Items.Add(
+ Services.TextService.Localize(string.Concat("actions/", ActionRefresh.Instance.Alias)),
+ true);
return menu;
}
@@ -174,6 +163,16 @@ namespace Umbraco.Web.Trees
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
+
+ //if the user has no path access for this node, all they can do is refresh
+ if (Security.CurrentUser.HasPathAccess(item, Services.EntityService, RecycleBinId) == false)
+ {
+ var menu = new MenuItemCollection();
+ menu.Items.Add(
+ Services.TextService.Localize(string.Concat("actions/", ActionRefresh.Instance.Alias)),
+ true);
+ return menu;
+ }
var nodeMenu = GetAllNodeMenuItems(item);
var allowedMenuItems = GetAllowedUserMenuItemsForNode(item);
@@ -210,17 +209,7 @@ namespace Umbraco.Web.Trees
protected override bool HasPathAccess(string id, FormDataCollection queryStrings)
{
var entity = GetEntityFromId(id);
- if (entity == null)
- {
- return false;
- }
-
- var content = Services.ContentService.GetById(entity.Id);
- if (content == null)
- {
- return false;
- }
- return Security.CurrentUser.HasPathAccess(content, Services.EntityService);
+ return HasPathAccess(entity, queryStrings);
}
///
diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
index fa18e703bd..8fabc1677e 100644
--- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
+++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -52,8 +54,48 @@ namespace Umbraco.Web.Trees
}
#endregion
+
+ ///
+ /// Ensure the noAccess metadata is applied for the root node if in dialog mode and the user doesn't have path access to it
+ ///
+ ///
+ ///
+ protected override TreeNode CreateRootNode(FormDataCollection queryStrings)
+ {
+ var node = base.CreateRootNode(queryStrings);
+
+ if (IsDialog(queryStrings) && UserStartNodes.Contains(Constants.System.Root) == false)
+ {
+ node.AdditionalData["noAccess"] = true;
+ }
+
+ return node;
+ }
protected abstract TreeNode GetSingleTreeNode(IUmbracoEntity e, string parentId, FormDataCollection queryStrings);
+
+ ///
+ /// Returns a for the and
+ /// attaches some meta data to the node if the user doesn't have start node access to it when in dialog mode
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal TreeNode GetSingleTreeNodeWithAccessCheck(IUmbracoEntity e, string parentId, FormDataCollection queryStrings)
+ {
+ bool hasPathAccess;
+ var entityIsAncestorOfStartNodes = Security.CurrentUser.IsInBranchOfStartNode(e, Services.EntityService, RecycleBinId, out hasPathAccess);
+ if (entityIsAncestorOfStartNodes == false)
+ return null;
+
+ var treeNode = GetSingleTreeNode(e, parentId, queryStrings);
+ if (hasPathAccess == false)
+ {
+ treeNode.AdditionalData["noAccess"] = true;
+ }
+ return treeNode;
+ }
///
/// Returns the
@@ -69,13 +111,7 @@ namespace Umbraco.Web.Trees
/// Returns the user's start node for this tree
///
protected abstract int[] UserStartNodes { get; }
-
- ///
- /// Gets the tree nodes for the given id
- ///
- ///
- ///
- ///
+
protected virtual TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
{
var nodes = new TreeNodeCollection();
@@ -83,9 +119,10 @@ namespace Umbraco.Web.Trees
var altStartId = string.Empty;
if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
altStartId = queryStrings.GetValue(TreeQueryStringParameters.StartNodeId);
+ var rootIdString = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
//check if a request has been made to render from a specific start node
- if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
+ if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != rootIdString)
{
id = altStartId;
@@ -111,10 +148,42 @@ namespace Umbraco.Web.Trees
}
}
- var entities = GetChildEntities(id);
- nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null));
+ var entities = GetChildEntities(id).ToList();
+
+ //If we are looking up the root and there is more than one node ...
+ //then we want to lookup those nodes' 'site' nodes and render those so that the
+ //user has some context of where they are in the tree, this is generally for pickers in a dialog.
+ //for any node they don't have access too, we need to add some metadata
+ if (id == rootIdString && entities.Count > 1)
+ {
+ var siteNodeIds = new List();
+ //put into array since we might modify the list
+ foreach (var e in entities.ToArray())
+ {
+ var pathParts = e.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
+ if (pathParts.Length < 2)
+ continue; // this should never happen but better to check
+
+ int siteNodeId;
+ if (int.TryParse(pathParts[1], out siteNodeId) == false)
+ continue;
+
+ //we'll look up this
+ siteNodeIds.Add(siteNodeId);
+ }
+ var siteNodes = Services.EntityService.GetAll(UmbracoObjectType, siteNodeIds.ToArray())
+ .DistinctBy(e => e.Id)
+ .ToArray();
+
+ //add site nodes
+ nodes.AddRange(siteNodes.Select(e => GetSingleTreeNodeWithAccessCheck(e, id, queryStrings)).Where(node => node != null));
+
+ return nodes;
+ }
+
+ nodes.AddRange(entities.Select(e => GetSingleTreeNodeWithAccessCheck(e, id, queryStrings)).Where(node => node != null));
return nodes;
- }
+ }
protected abstract MenuItemCollection PerformGetMenuForNode(string id, FormDataCollection queryStrings);
@@ -154,8 +223,21 @@ namespace Umbraco.Web.Trees
///
///
///
+ //we should remove this in v8, it's now here for backwards compat only
protected abstract bool HasPathAccess(string id, FormDataCollection queryStrings);
+ ///
+ /// Returns true or false if the current user has access to the node based on the user's allowed start node (path) access
+ ///
+ ///
+ ///
+ ///
+ protected bool HasPathAccess(IUmbracoEntity entity, FormDataCollection queryStrings)
+ {
+ if (entity == null) return false;
+ return Security.CurrentUser.HasPathAccess(entity, Services.EntityService, RecycleBinId);
+ }
+
///
/// Ensures the recycle bin is appended when required (i.e. user has access to the root and it's not in dialog mode)
///
@@ -214,7 +296,7 @@ namespace Umbraco.Web.Trees
///
private TreeNodeCollection GetTreeNodesInternal(string id, FormDataCollection queryStrings)
{
- IUmbracoEntity current = GetEntityFromId(id);
+ var current = GetEntityFromId(id);
//before we get the children we need to see if this is a container node
@@ -242,7 +324,8 @@ namespace Umbraco.Web.Trees
menu.Items.Add(ui.Text("actions", "emptyTrashcan"));
menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true);
return menu;
- }
+ }
+
return PerformGetMenuForNode(id, queryStrings);
}
@@ -271,10 +354,11 @@ namespace Umbraco.Web.Trees
internal IEnumerable
[Obsolete("This class has been superceded by Umbraco.Web.UI.Pages.UmbracoEnsuredPage")]
public class UmbracoEnsuredPage : BasePage
- {
+ {
+ ///
+ /// Performs an authorization check for the user against the requested entity/path and permission set, this is only relevant to content and media
+ ///
+ ///
+ ///
+ ///
+ protected void CheckPathAndPermissions(int entityId, UmbracoObjectTypes objectType, IAction actionToCheck)
+ {
+ if (objectType == UmbracoObjectTypes.Document || objectType == UmbracoObjectTypes.Media)
+ {
+ //check path access
+
+ var entity = entityId == Constants.System.Root
+ ? UmbracoEntity.Root
+ : Services.EntityService.Get(
+ entityId,
+ objectType);
+ var hasAccess = CurrentUser.UserEntity.HasPathAccess(
+ entity,
+ Services.EntityService,
+ objectType == UmbracoObjectTypes.Document ? Constants.System.RecycleBinContent : Constants.System.RecycleBinMedia);
+ if (hasAccess == false)
+ throw new UserAuthorizationException(string.Format("The current user doesn't have access to the path '{0}'", entity.Path));
+
+ //only documents have action permissions
+ if (objectType == UmbracoObjectTypes.Document)
+ {
+ var allowedActions = ActionsResolver.Current.FromActionSymbols(CurrentUser.UserEntity.GetPermissions(entity.Path, Services.UserService)).ToArray();
+ if (allowedActions.Contains(actionToCheck) == false)
+ throw new UserAuthorizationException(string.Format("The current user doesn't have permission to {0} on the path '{1}'", actionToCheck.Alias, entity.Path));
+ }
+ }
+ }
+
///
/// Checks if the page exists outside of the /umbraco route, in which case the request will not have been authenticated for the back office
/// so we'll force authentication.
diff --git a/src/umbraco.cms/Actions/Action.cs b/src/umbraco.cms/Actions/Action.cs
index 81c78ade1b..c7a9a6242b 100644
--- a/src/umbraco.cms/Actions/Action.cs
+++ b/src/umbraco.cms/Actions/Action.cs
@@ -128,30 +128,20 @@ namespace umbraco.BusinessLogic.Actions
///
///
/// returns a list of actions that have an associated letter found in the action string list
+ [Obsolete("Use ActionsResolver.Current.FromActionSymbols instead")]
public static List FromString(string actions)
{
- List list = new List();
- foreach (char c in actions.ToCharArray())
- {
- IAction action = ActionsResolver.Current.Actions.ToList().Find(
- delegate(IAction a)
- {
- return a.Letter == c;
- }
- );
- if (action != null)
- list.Add(action);
- }
- return list;
+ return ActionsResolver.Current.FromActionSymbols(actions.ToCharArray().Select(x => x.ToString())).ToList();
}
///
/// Returns the string representation of the actions that make up the actions collection
///
///
+ [Obsolete("Use ActionsResolver.Current.ToActionSymbols instead")]
public static string ToString(List actions)
{
- string[] strMenu = Array.ConvertAll(actions.ToArray(), delegate(IAction a) { return (a.Letter.ToString(CultureInfo.InvariantCulture)); });
+ string[] strMenu = Array.ConvertAll(actions.ToArray(), a => (a.Letter.ToString(CultureInfo.InvariantCulture)));
return string.Join("", strMenu);
}
@@ -161,12 +151,7 @@ namespace umbraco.BusinessLogic.Actions
///
public static List GetPermissionAssignable()
{
- return ActionsResolver.Current.Actions.ToList().FindAll(
- delegate(IAction a)
- {
- return (a.CanBePermissionAssigned);
- }
- );
+ return ActionsResolver.Current.Actions.ToList().FindAll(a => (a.CanBePermissionAssigned));
}
///