diff --git a/src/Umbraco.Core/Models/Membership/ContentPermissionSet.cs b/src/Umbraco.Core/Models/Membership/ContentPermissionSet.cs
new file mode 100644
index 0000000000..1345be2c8c
--- /dev/null
+++ b/src/Umbraco.Core/Models/Membership/ContentPermissionSet.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Models.Membership
+{
+ ///
+ /// Represents an -> user group & permission key value pair collection
+ ///
+ ///
+ /// This implements purely so it can be used with the repository layer which is why it's explicitly implemented.
+ ///
+ public class ContentPermissionSet : EntityPermissionSet, IAggregateRoot
+ {
+ private readonly IContent _content;
+
+ public ContentPermissionSet(IContent content, IEnumerable permissionsSet)
+ : base(content.Id, permissionsSet)
+ {
+ _content = content;
+ }
+
+ public override int EntityId
+ {
+ get { return _content.Id; }
+ }
+
+ #region Explicit implementation of IAggregateRoot
+ int IEntity.Id
+ {
+ get { return EntityId; }
+ set { throw new NotImplementedException(); }
+ }
+
+ bool IEntity.HasIdentity
+ {
+ get { return EntityId > 0; }
+ }
+
+ Guid IEntity.Key { get; set; }
+
+ DateTime IEntity.CreateDate { get; set; }
+
+ DateTime IEntity.UpdateDate { get; set; }
+
+ DateTime? IDeletableEntity.DeletedDate { get; set; }
+
+ object IDeepCloneable.DeepClone()
+ {
+ throw new NotImplementedException();
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Membership/EntityPermission.cs b/src/Umbraco.Core/Models/Membership/EntityPermission.cs
index a1fa57d274..c6d9e8350d 100644
--- a/src/Umbraco.Core/Models/Membership/EntityPermission.cs
+++ b/src/Umbraco.Core/Models/Membership/EntityPermission.cs
@@ -7,21 +7,24 @@ namespace Umbraco.Core.Models.Membership
///
public class EntityPermission
{
- public EntityPermission(int entityId, string[] assignedPermissions)
+ public EntityPermission(int groupId, int entityId, string[] assignedPermissions)
{
+ UserGroupId = groupId;
EntityId = entityId;
AssignedPermissions = assignedPermissions;
IsDefaultPermissions = false;
}
- public EntityPermission(int entityId, string[] assignedPermissions, bool isDefaultPermissions)
+ public EntityPermission(int groupId, int entityId, string[] assignedPermissions, bool isDefaultPermissions)
{
+ UserGroupId = groupId;
EntityId = entityId;
AssignedPermissions = assignedPermissions;
IsDefaultPermissions = isDefaultPermissions;
}
public int EntityId { get; private set; }
+ public int UserGroupId { get; private set; }
///
/// The assigned permissions for the user/entity combo
@@ -50,7 +53,9 @@ namespace Umbraco.Core.Models.Membership
AssignedPermissions = newPermissions
.Distinct()
.ToArray();
- }
+ }
+
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs b/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs
index d91cd3a352..dd9190ae85 100644
--- a/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs
+++ b/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs
@@ -1,60 +1,56 @@
using System.Collections.Generic;
+using System.Linq;
namespace Umbraco.Core.Models.Membership
{
///
/// Represents an entity -> user group & permission key value pair collection
- ///
+ ///
public class EntityPermissionSet
{
///
- /// The entity id with permissions assigned
+ /// Returns an empty permission set
///
- public int EntityId { get; private set; }
+ ///
+ public static EntityPermissionSet Empty()
+ {
+ return new EntityPermissionSet(-1, new EntityPermission[0]);
+ }
- ///
- /// The key/value pairs of user group id & single permission
- ///
- public IEnumerable PermissionsSet { get; private set; }
-
- public EntityPermissionSet(int entityId, IEnumerable permissionsSet)
+ public EntityPermissionSet(int entityId, IEnumerable permissionsSet)
{
EntityId = entityId;
PermissionsSet = permissionsSet;
}
- public class UserGroupPermission
+ ///
+ /// The entity id with permissions assigned
+ ///
+ public virtual int EntityId { get; private set; }
+
+ ///
+ /// The key/value pairs of user group id & single permission
+ ///
+ public IEnumerable PermissionsSet { get; private set; }
+
+ ///
+ /// Returns the aggregte permissions in the permission set
+ ///
+ ///
+ ///
+ /// This value is only calculated once
+ ///
+ public IEnumerable GetAllPermissions()
{
- public UserGroupPermission(int groupId, string permission)
- {
- UserGroupId = groupId;
- Permission = permission;
- }
-
- public int UserGroupId { get; private set; }
-
- public string Permission { get; private set; }
-
- protected bool Equals(UserGroupPermission other)
- {
- return UserGroupId == other.UserGroupId && string.Equals(Permission, other.Permission);
- }
-
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != this.GetType()) return false;
- return Equals((UserGroupPermission) obj);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- return (UserGroupId * 397) ^ Permission.GetHashCode();
- }
- }
+ return _calculatedPermissions ?? (_calculatedPermissions =
+ PermissionsSet.SelectMany(x => x.AssignedPermissions).Distinct().ToArray());
}
+
+ private string[] _calculatedPermissions;
+
+
+
+
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Membership/UserGroupEntityPermission.cs b/src/Umbraco.Core/Models/Membership/UserGroupEntityPermission.cs
deleted file mode 100644
index 619223f01a..0000000000
--- a/src/Umbraco.Core/Models/Membership/UserGroupEntityPermission.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Umbraco.Core.Models.Membership
-{
- ///
- /// Represents a user group -> entity permission
- ///
- public class UserGroupEntityPermission : EntityPermission
- {
- public UserGroupEntityPermission(int groupId, int entityId, string[] assignedPermissions)
- : base(entityId, assignedPermissions)
- {
- UserGroupId = groupId;
- }
-
- public int UserGroupId { get; private set; }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentBlueprintRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentBlueprintRepository.cs
new file mode 100644
index 0000000000..4c9021d20a
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentBlueprintRepository.cs
@@ -0,0 +1,31 @@
+using System;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence.SqlSyntax;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Persistence.Repositories
+{
+ ///
+ /// Override the base content repository so we can change the node object type
+ ///
+ ///
+ /// It would be nicer if we could separate most of this down into a smaller version of the ContentRepository class, however to do that
+ /// requires quite a lot of work since we'd need to re-organize the interhitance quite a lot or create a helper class to perform a lot of the underlying logic.
+ ///
+ /// TODO: Create a helper method to contain most of the underlying logic for the ContentRepository
+ ///
+ internal class ContentBlueprintRepository : ContentRepository
+ {
+ public ContentBlueprintRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider syntaxProvider, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, IContentSection contentSection)
+ : base(work, cacheHelper, logger, syntaxProvider, contentTypeRepository, templateRepository, tagRepository, contentSection)
+ {
+ }
+
+ protected override Guid NodeObjectTypeId
+ {
+ get { return Constants.ObjectTypes.DocumentBlueprintGuid; }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index f07e9c8385..2c3f126c6e 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -20,28 +20,6 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
- ///
- /// Override the base content repository so we can change the node object type
- ///
- ///
- /// It would be nicer if we could separate most of this down into a smaller version of the ContentRepository class, however to do that
- /// requires quite a lot of work since we'd need to re-organize the interhitance quite a lot or create a helper class to perform a lot of the underlying logic.
- ///
- /// TODO: Create a helper method to conain most of the underlying logic for the ContentRepository
- ///
- internal class ContentBlueprintRepository : ContentRepository
- {
- public ContentBlueprintRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider syntaxProvider, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, IContentSection contentSection) : base(work, cacheHelper, logger, syntaxProvider, contentTypeRepository, templateRepository, tagRepository, contentSection)
- {
- }
-
- protected override Guid NodeObjectTypeId
- {
- get { return Constants.ObjectTypes.DocumentBlueprintGuid; }
- }
-
- }
-
///
/// Represents a repository for doing CRUD operations for
///
@@ -50,9 +28,9 @@ namespace Umbraco.Core.Persistence.Repositories
private readonly IContentTypeRepository _contentTypeRepository;
private readonly ITemplateRepository _templateRepository;
private readonly ITagRepository _tagRepository;
- private readonly CacheHelper _cacheHelper;
private readonly ContentPreviewRepository _contentPreviewRepository;
private readonly ContentXmlRepository _contentXmlRepository;
+ private readonly PermissionRepository _permissionRepository;
public ContentRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider syntaxProvider, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, IContentSection contentSection)
: base(work, cacheHelper, logger, syntaxProvider, contentSection)
@@ -63,10 +41,10 @@ namespace Umbraco.Core.Persistence.Repositories
_contentTypeRepository = contentTypeRepository;
_templateRepository = templateRepository;
_tagRepository = tagRepository;
- _cacheHelper = cacheHelper;
_contentPreviewRepository = new ContentPreviewRepository(work, CacheHelper.NoCache, logger, syntaxProvider);
_contentXmlRepository = new ContentXmlRepository(work, CacheHelper.NoCache, logger, syntaxProvider);
-
+ _permissionRepository = new PermissionRepository(UnitOfWork, cacheHelper, Logger, SqlSyntax);
+
EnsureUniqueNaming = true;
}
@@ -468,26 +446,7 @@ namespace Umbraco.Core.Persistence.Repositories
entity.Id = nodeDto.NodeId; //Set Id on entity to ensure an Id is set
entity.Path = nodeDto.Path;
entity.SortOrder = sortOrder;
- entity.Level = level;
-
- ////Assign the same permissions to it as the parent node
- //// http://issues.umbraco.org/issue/U4-2161
- //var permissionsRepo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- //var parentPermissions = permissionsRepo.GetPermissionsForEntity(entity.ParentId).ToArray();
- ////if there are parent permissions then assign them, otherwise leave null and permissions will become the
- //// user's default permissions.
- //if (parentPermissions.Length > 0)
- //{
- // var userGroupPermissions = (
- // from perm in parentPermissions
- // from p in perm.AssignedPermissions
- // select new EntityPermissionSet.UserGroupPermission(perm.UserGroupId, p)).ToList();
-
- // permissionsRepo.ReplaceEntityPermissions(new EntityPermissionSet(entity.Id, userGroupPermissions));
- // //flag the entity's permissions changed flag so we can track those changes.
- // //Currently only used for the cache refreshers to detect if we should refresh all user permissions cache.
- // ((Content)entity).PermissionsChanged = true;
- //}
+ entity.Level = level;
//Create the Content specific data - cmsContent
var contentDto = dto.ContentVersionDto.ContentDto;
@@ -863,8 +822,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
public void ReplaceContentPermissions(EntityPermissionSet permissionSet)
{
- var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- repo.ReplaceEntityPermissions(permissionSet);
+ _permissionRepository.ReplaceEntityPermissions(permissionSet);
}
public void ClearPublished(IContent content)
@@ -880,21 +838,19 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
///
///
public void AssignEntityPermission(IContent entity, char permission, IEnumerable groupIds)
- {
- var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- repo.AssignEntityPermission(entity, permission, groupIds);
+ {
+ _permissionRepository.AssignEntityPermission(entity, permission, groupIds);
}
///
- /// Returns permissions directly assigned to the content item for all user groups
+ /// Gets the explicit list of permissions for the content item
///
///
///
- public IEnumerable GetPermissionsForEntity(int entityId)
+ public IEnumerable GetPermissionsForEntity(int entityId)
{
- var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- return repo.GetPermissionsForEntity(entityId);
- }
+ return _permissionRepository.GetPermissionsForEntity(entityId);
+ }
///
/// Adds/updates content/published xml
@@ -906,6 +862,15 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity(content, xml));
}
+ ///
+ /// Used to add/update a permission for a content item
+ ///
+ ///
+ public void AddOrUpdatePermissions(ContentPermissionSet permission)
+ {
+ _permissionRepository.AddOrUpdate(permission);
+ }
+
///
/// Used to remove the content xml for a content item
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
index 41889de1c4..6f643b3e0b 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
@@ -57,11 +57,18 @@ namespace Umbraco.Core.Persistence.Repositories
void AssignEntityPermission(IContent entity, char permission, IEnumerable groupIds);
///
- /// Gets the list of permissions for the content item
+ /// Gets the explicit list of permissions for the content item
///
///
///
- IEnumerable GetPermissionsForEntity(int entityId);
+ IEnumerable GetPermissionsForEntity(int entityId);
+
+ /////
+ ///// Gets the implicit/inherited list of permissions for the content item
+ /////
+ /////
+ /////
+ //IEnumerable GetPermissionsForPath(string path);
///
/// Used to add/update published xml for the content item
@@ -70,6 +77,12 @@ namespace Umbraco.Core.Persistence.Repositories
///
void AddOrUpdateContentXml(IContent content, Func xml);
+ ///
+ /// Used to add/update a permission for a content item
+ ///
+ ///
+ void AddOrUpdatePermissions(ContentPermissionSet permission);
+
///
/// Used to remove the content xml for a content item
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs
index 3ccfa89885..b018bd3c08 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs
@@ -32,6 +32,14 @@ namespace Umbraco.Core.Persistence.Repositories
/// Array of entity Ids, if empty will return permissions for the group for all entities
IEnumerable GetPermissionsForEntities(int groupId, params int[] entityIds);
+ ///
+ /// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
+ ///
+ /// The group
+ /// If true will include the group's default permissions if no permissions are explicitly assigned
+ /// Array of entity Ids, if empty will return permissions for the group for all entities
+ IEnumerable GetPermissionsForEntities(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds);
+
///
/// Replaces the same permission set for a single group to any number of entities
///
@@ -47,6 +55,6 @@ namespace Umbraco.Core.Persistence.Repositories
/// Permissions as enumerable list of
/// Specify the nodes to replace permissions for
void AssignGroupPermission(int groupId, char permission, params int[] entityIds);
-
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs
index 5ae4efad45..4cad3be7e7 100644
--- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs
@@ -12,6 +12,9 @@ using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using CacheKeys = Umbraco.Core.Cache.CacheKeys;
using Umbraco.Core.Cache;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -19,19 +22,18 @@ namespace Umbraco.Core.Persistence.Repositories
/// A repository that exposes functionality to modify assigned permissions to a node
///
///
- internal class PermissionRepository
+ ///
+ /// This repo implements the base class so that permissions can be queued to be persisted
+ /// like the normal repository pattern but the standard repository Get commands don't apply and will throw
+ ///
+ internal class PermissionRepository : PetaPocoRepositoryBase
where TEntity : class, IAggregateRoot
{
- private readonly IScopeUnitOfWork _unitOfWork;
- private readonly IRuntimeCacheProvider _runtimeCache;
- private readonly ISqlSyntaxProvider _sqlSyntax;
- internal PermissionRepository(IScopeUnitOfWork unitOfWork, CacheHelper cache, ISqlSyntaxProvider sqlSyntax)
+ public PermissionRepository(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
+ : base(work, cache, logger, sqlSyntax)
{
- _unitOfWork = unitOfWork;
- //Make this repository use an isolated cache
- _runtimeCache = cache.IsolatedRuntimeCache.GetOrCreateCache();
- _sqlSyntax = sqlSyntax;
+
}
///
@@ -41,7 +43,6 @@ namespace Umbraco.Core.Persistence.Repositories
///
///
public IEnumerable GetPermissionsForEntities(int groupId, params int[] entityIds)
- {
//var whereCriteria = GetPermissionsForEntitiesCriteria(groupId, entityIds);
var result = new List();
//iterate in groups of 2000 since we don't want to exceed the max SQL param count
@@ -51,9 +52,9 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql();
sql.Select("*")
- .From(_sqlSyntax)
- .Where(dto => dto.UserGroupId == groupId && ids.Contains(dto.NodeId), _sqlSyntax);
- var permissions = _unitOfWork.Database.Fetch(sql);
+ .From(SqlSyntax)
+ .Where(dto => dto.UserGroupId == groupId && ids.Contains(dto.NodeId), SqlSyntax);
+ var permissions = UnitOfWork.Database.Fetch(sql);
result.AddRange(ConvertToPermissionList(permissions));
}
return result;
@@ -73,62 +74,62 @@ namespace Umbraco.Core.Persistence.Repositories
// sql.Select("*")
// .From()
// .Where(whereCriteria);
- // var result = _unitOfWork.Database.Fetch(sql);
+ // var result = UnitOfWork.Database.Fetch(sql);
// return ConvertToPermissionList(result);
// },
// GetCacheTimeout(),
// priority: GetCachePriority());
- }
-
- //private static string GetEntityIdKey(int[] entityIds)
- //{
- // return string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture)));
- //}
-
- //private static TimeSpan GetCacheTimeout()
- //{
- // //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will only have this exist in cache for 20 minutes,
- // // then it will refresh from the database.
- // return new TimeSpan(0, 20, 0);
- //}
-
- //private static CacheItemPriority GetCachePriority()
- //{
- // //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will make this priority below average
- // return CacheItemPriority.BelowNormal;
- //}
-
- private static IEnumerable ConvertToPermissionList(IEnumerable result)
+ }
+
+ //private static string GetEntityIdKey(int[] entityIds)
+ //{
+ // return string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture)));
+ //}
+
+ //private static TimeSpan GetCacheTimeout()
+ //{
+ // //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will only have this exist in cache for 20 minutes,
+ // // then it will refresh from the database.
+ // return new TimeSpan(0, 20, 0);
+ //}
+
+ //private static CacheItemPriority GetCachePriority()
+ //{
+ // //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will make this priority below average
+ // return CacheItemPriority.BelowNormal;
+ //}
+
+ ///
+ /// Returns permissions directly assigned to the content items for all user groups
+ ///
+ ///
+ ///
+ public IEnumerable GetPermissionsForEntities(int[] entityIds)
{
- var permissions = new List();
- var nodePermissions = result.GroupBy(x => x.NodeId);
- foreach (var np in nodePermissions)
- {
- var userGroupPermissions = np.GroupBy(x => x.UserGroupId);
- foreach (var permission in userGroupPermissions)
- {
- var perms = permission.Select(x => x.Permission).ToArray();
- permissions.Add(new UserGroupEntityPermission(permission.Key, permission.First().NodeId, perms));
- }
- }
+ var sql = new Sql();
+ sql.Select("*")
+ .From(SqlSyntax)
+ .Where(dto => entityIds.Contains(dto.NodeId), SqlSyntax)
+ .OrderBy(dto => dto.NodeId, SqlSyntax);
- return permissions;
- }
+ var result = UnitOfWork.Database.Fetch(sql);
+ return ConvertToPermissionList(result);
+ }
///
/// Returns permissions directly assigned to the content item for all user groups
///
///
///
- public IEnumerable GetPermissionsForEntity(int entityId)
+ public IEnumerable GetPermissionsForEntity(int entityId)
{
var sql = new Sql();
sql.Select("*")
- .From()
- .Where(dto => dto.NodeId == entityId)
- .OrderBy(dto => dto.NodeId);
+ .From(SqlSyntax)
+ .Where(dto => dto.NodeId == entityId, SqlSyntax)
+ .OrderBy(dto => dto.NodeId, SqlSyntax);
- var result = _unitOfWork.Database.Fetch(sql);
+ var result = UnitOfWork.Database.Fetch(sql);
return ConvertToPermissionList(result);
}
@@ -143,7 +144,7 @@ namespace Umbraco.Core.Persistence.Repositories
///
public void ReplacePermissions(int groupId, IEnumerable permissions, params int[] entityIds)
{
- var db = _unitOfWork.Database;
+ var db = UnitOfWork.Database;
//we need to batch these in groups of 2000 so we don't exceed the max 2100 limit
var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE userGroupId = @groupId AND nodeId in (@nodeIds)";
@@ -166,10 +167,10 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
- _unitOfWork.Database.BulkInsertRecords(toInsert, _sqlSyntax);
+ UnitOfWork.Database.BulkInsertRecords(toInsert, SqlSyntax);
//Raise the event
- _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(toInsert), false));
+ UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(toInsert), false));
}
@@ -181,7 +182,7 @@ namespace Umbraco.Core.Persistence.Repositories
///
public void AssignPermission(int groupId, char permission, params int[] entityIds)
{
- var db = _unitOfWork.Database;
+ var db = UnitOfWork.Database;
var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE userGroupId = @groupId AND permission=@permission AND nodeId in (@entityIds)";
db.Execute(sql,
new
@@ -198,10 +199,10 @@ namespace Umbraco.Core.Persistence.Repositories
UserGroupId = groupId
}).ToArray();
- _unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
+ UnitOfWork.Database.BulkInsertRecords(actions, SqlSyntax);
//Raise the event
- _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false));
+ UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false));
}
@@ -213,7 +214,7 @@ namespace Umbraco.Core.Persistence.Repositories
///
public void AssignEntityPermission(TEntity entity, char permission, IEnumerable groupIds)
{
- var db = _unitOfWork.Database;
+ var db = UnitOfWork.Database;
var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @nodeId AND permission = @permission AND userGroupId in (@groupIds)";
db.Execute(sql,
new
@@ -230,15 +231,15 @@ namespace Umbraco.Core.Persistence.Repositories
UserGroupId = id
}).ToArray();
- _unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
+ UnitOfWork.Database.BulkInsertRecords(actions, SqlSyntax);
//Raise the event
- _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false));
+ UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false));
}
///
- /// Assigns permissions to an entity for multiple users/permission entries
+ /// Assigns permissions to an entity for multiple group/permission entries
///
///
///
@@ -247,25 +248,118 @@ namespace Umbraco.Core.Persistence.Repositories
///
public void ReplaceEntityPermissions(EntityPermissionSet permissionSet)
{
- var db = _unitOfWork.Database;
- var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @nodeId";
- db.Execute(sql, new { nodeId = permissionSet.EntityId });
-
- var actions = permissionSet.PermissionsSet.Select(p => new UserGroup2NodePermissionDto
- {
- NodeId = permissionSet.EntityId,
- Permission = p.Permission,
- UserGroupId = p.UserGroupId
- }).ToArray();
+ var db = UnitOfWork.Database;
+ var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @nodeId";
+ db.Execute(sql, new { nodeId = permissionSet.EntityId });
+
+ var toInsert = new List();
+ foreach (var entityPermission in permissionSet.PermissionsSet)
+ {
+ foreach (var permission in entityPermission.AssignedPermissions)
+ {
+ toInsert.Add(new UserGroup2NodePermissionDto
+ {
+ NodeId = permissionSet.EntityId,
+ Permission = permission,
+ UserGroupId = entityPermission.UserGroupId
+ });
+ }
+ }
+
+ UnitOfWork.Database.BulkInsertRecords(toInsert, SqlSyntax);
+
+ //Raise the event
+ UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(permissionSet.PermissionsSet, false));
+
- _unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
-
- //Raise the event
- _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false));
-
-
}
- public static event TypedEventHandler, SaveEventArgs> AssignedPermissions;
+
+ #region Not implemented (don't need to for the purposes of this repo)
+ protected override ContentPermissionSet PerformGet(int id)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override IEnumerable PerformGetAll(params int[] ids)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override IEnumerable PerformGetByQuery(IQuery query)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override Sql GetBaseQuery(bool isCount)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override string GetBaseWhereClause()
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override IEnumerable GetDeleteClauses()
+ {
+ return new List();
+ }
+
+ protected override Guid NodeObjectTypeId
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ protected override void PersistDeletedItem(ContentPermissionSet entity)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+
+ ///
+ /// Used to add or update entity permissions during a content item being updated
+ ///
+ ///
+ protected override void PersistNewItem(ContentPermissionSet entity)
+ {
+ //does the same thing as update
+ PersistUpdatedItem(entity);
+ }
+
+ ///
+ /// Used to add or update entity permissions during a content item being updated
+ ///
+ ///
+ protected override void PersistUpdatedItem(ContentPermissionSet entity)
+ {
+ var asAggregateRoot = (IAggregateRoot)entity;
+ if (asAggregateRoot.HasIdentity == false)
+ {
+ throw new InvalidOperationException("Cannot create permissions for an entity without an Id");
+ }
+
+ ReplaceEntityPermissions(entity);
+ }
+
+ private static IEnumerable ConvertToPermissionList(IEnumerable result)
+ {
+ var permissions = new List();
+ var nodePermissions = result.GroupBy(x => x.NodeId);
+ foreach (var np in nodePermissions)
+ {
+ var userGroupPermissions = np.GroupBy(x => x.UserGroupId);
+ foreach (var permission in userGroupPermissions)
+ {
+ var perms = permission.Select(x => x.Permission).ToArray();
+ permissions.Add(new EntityPermission(permission.Key, np.Key, perms));
+ }
+ }
+
+ return permissions;
+ }
+
+ public static event TypedEventHandler, SaveEventArgs> AssignedPermissions;
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/SimpleGetRepository.cs b/src/Umbraco.Core/Persistence/Repositories/SimpleGetRepository.cs
index 67c9149422..28e676743f 100644
--- a/src/Umbraco.Core/Persistence/Repositories/SimpleGetRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/SimpleGetRepository.cs
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Persistence.Repositories
return Database.Fetch(sql).Select(ConvertToEntity);
}
- protected override sealed IEnumerable PerformGetByQuery(IQuery query)
+ protected sealed override IEnumerable PerformGetByQuery(IQuery query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator(sqlClause, query);
@@ -76,22 +76,22 @@ namespace Umbraco.Core.Persistence.Repositories
#region Not implemented and not required
- protected override sealed IEnumerable GetDeleteClauses()
+ protected sealed override IEnumerable GetDeleteClauses()
{
throw new NotImplementedException();
}
- protected override sealed Guid NodeObjectTypeId
+ protected sealed override Guid NodeObjectTypeId
{
get { throw new NotImplementedException(); }
}
- protected override sealed void PersistNewItem(TEntity entity)
+ protected sealed override void PersistNewItem(TEntity entity)
{
throw new NotImplementedException();
}
- protected override sealed void PersistUpdatedItem(TEntity entity)
+ protected sealed override void PersistUpdatedItem(TEntity entity)
{
throw new NotImplementedException();
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs
index e0717deda4..bd2b8390cd 100644
--- a/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs
@@ -22,12 +22,14 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly CacheHelper _cacheHelper;
private readonly UserGroupWithUsersRepository _userGroupWithUsersRepository;
+ private readonly PermissionRepository _permissionRepository;
public UserGroupRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cacheHelper, logger, sqlSyntax)
{
_cacheHelper = cacheHelper;
_userGroupWithUsersRepository = new UserGroupWithUsersRepository(this, work, cacheHelper, logger, sqlSyntax);
+ _permissionRepository = new PermissionRepository(work, _cacheHelper, logger, sqlSyntax);
}
public const string GetByAliasCacheKeyPrefix = "UserGroupRepository_GetByAlias_";
@@ -97,8 +99,33 @@ namespace Umbraco.Core.Persistence.Repositories
/// Array of entity Ids, if empty will return permissions for the group for all entities
public IEnumerable GetPermissionsForEntities(int groupId, params int[] entityIds)
{
- var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- return repo.GetPermissionsForEntities(groupId, entityIds);
+ return _permissionRepository.GetPermissionsForEntities(groupId, entityIds);
+ }
+
+ ///
+ /// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
+ ///
+ /// The group
+ /// If true will include the group's default permissions if no permissions are explicitly assigned
+ /// Array of entity Ids, if empty will return permissions for the group for all entities
+ public IEnumerable GetPermissionsForEntities(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds)
+ {
+ if (group == null) throw new ArgumentNullException("group");
+
+ var explicitPermissions = GetPermissionsForEntities(group.Id, nodeIds);
+ var result = new List(explicitPermissions);
+
+ // If requested, and no permissions are assigned to a particular node, then we will fill in those permissions with the group's defaults
+ if (fallbackToDefaultPermissions)
+ {
+ var missingIds = nodeIds.Except(result.Select(x => x.EntityId)).ToArray();
+ if (missingIds.Length > 0)
+ {
+ result.AddRange(missingIds
+ .Select(i => new EntityPermission(group.Id, i, group.Permissions.ToArray(), isDefaultPermissions: true)));
+ }
+ }
+ return result;
}
///
@@ -109,8 +136,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// Specify the nodes to replace permissions for. If nothing is specified all permissions are removed.
public void ReplaceGroupPermissions(int groupId, IEnumerable permissions, params int[] entityIds)
{
- var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- repo.ReplacePermissions(groupId, permissions, entityIds);
+ _permissionRepository.ReplacePermissions(groupId, permissions, entityIds);
}
///
@@ -121,9 +147,8 @@ namespace Umbraco.Core.Persistence.Repositories
/// Specify the nodes to replace permissions for
public void AssignGroupPermission(int groupId, char permission, params int[] entityIds)
{
- var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax);
- repo.AssignPermission(groupId, permission, entityIds);
- }
+ _permissionRepository.AssignPermission(groupId, permission, entityIds);
+ }
#region Overrides of RepositoryBase
diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 6e09d5f845..b7649ea382 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -130,11 +130,11 @@ namespace Umbraco.Core.Services
}
///
- /// Returns permissions directly assigned to the content item for all user groups
+ /// Returns implicit/inherited permissions assigned to the content item for all user groups
///
///
///
- public IEnumerable GetPermissionsForEntity(IContent content)
+ public IEnumerable GetPermissionsForEntity(IContent content)
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
@@ -1671,9 +1671,21 @@ namespace Umbraco.Core.Services
// Update the create author and last edit author
copy.CreatorId = userId;
copy.WriterId = userId;
+
+ //get the current permissions, if there are any explicit ones they need to be copied
+ var currentPermissions = GetPermissionsForEntity(content)
+ .Where(x => x.IsDefaultPermissions == false).ToArray();
repository.AddOrUpdate(copy);
- repository.AddOrUpdatePreviewXml(copy, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
+ repository.AddOrUpdatePreviewXml(copy, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
+
+ //add permissions
+ if (currentPermissions.Length > 0)
+ {
+ var permissionSet = new ContentPermissionSet(copy, currentPermissions);
+ repository.AddOrUpdatePermissions(permissionSet);
+ }
+
uow.Commit(); // todo - this should flush, not commit
//Special case for the associated tags
diff --git a/src/Umbraco.Core/Services/ContentServiceExtensions.cs b/src/Umbraco.Core/Services/ContentServiceExtensions.cs
index 95fe79f9ac..c6dc0274b6 100644
--- a/src/Umbraco.Core/Services/ContentServiceExtensions.cs
+++ b/src/Umbraco.Core/Services/ContentServiceExtensions.cs
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Services
///
public static void RemoveContentPermissions(this IContentService contentService, int contentId)
{
- contentService.ReplaceContentPermissions(new EntityPermissionSet(contentId, Enumerable.Empty()));
+ contentService.ReplaceContentPermissions(new EntityPermissionSet(contentId, Enumerable.Empty()));
}
///
diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs
index 289af7324b..251bf169ad 100644
--- a/src/Umbraco.Core/Services/IContentService.cs
+++ b/src/Umbraco.Core/Services/IContentService.cs
@@ -151,11 +151,11 @@ namespace Umbraco.Core.Services
void AssignContentPermission(IContent entity, char permission, IEnumerable groupIds);
///
- /// Returns permissions directly assigned to the content item for all user groups
+ /// Returns implicit/inherited permissions assigned to the content item for all user groups
///
///
///
- IEnumerable GetPermissionsForEntity(IContent content);
+ IEnumerable GetPermissionsForEntity(IContent content);
bool SendToPublication(IContent content, int userId = 0);
diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs
index de228412da..c5b282cd66 100644
--- a/src/Umbraco.Core/Services/IUserService.cs
+++ b/src/Umbraco.Core/Services/IUserService.cs
@@ -102,8 +102,7 @@ namespace Umbraco.Core.Services
///
/// Group to retrieve permissions for
///
- /// Flag indicating if we want to get just the permissions directly assigned for the group and path,
- /// or fall back to the group's default permissions when nothing is directly assigned
+ /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
///
/// Specifiying nothing will return all permissions for all nodes
/// An enumerable list of
@@ -114,16 +113,15 @@ namespace Umbraco.Core.Services
///
/// User to check permissions for
/// Path to check permissions for
- EntityPermissionSet GetPermissionsForPath(IUser user, string path);
-
+ EntityPermissionSet GetPermissionsForPath(IUser user, string path);
+
///
/// Gets the permissions for the provided group and path
///
/// Group to check permissions for
/// Path to check permissions for
///
- /// Flag indicating if we want to get just the permissions directly assigned for the group and path,
- /// or fall back to the group's default permissions when nothing is directly assigned
+ /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
///
EntityPermission GetPermissionsForPath(IUserGroup group, string path, bool fallbackToDefaultPermissions = false);
diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs
index 841a51456e..52e3e82106 100644
--- a/src/Umbraco.Core/Services/UserService.cs
+++ b/src/Umbraco.Core/Services/UserService.cs
@@ -865,21 +865,18 @@ namespace Umbraco.Core.Services
///
/// Group to retrieve permissions for
///
- /// Flag indicating if we want to get just the permissions directly assigned for the group and path,
- /// or fall back to the group's default permissions when nothing is directly assigned
+ /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
///
/// Specifiying nothing will return all permissions for all nodes
/// An enumerable list of
private IEnumerable GetPermissions(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
- if (group == null) throw new ArgumentNullException("group");
- if (nodeIds.Length == 0)
- return Enumerable.Empty();
-
+ if (group == null) throw new ArgumentNullException("group");
+
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
- return GetPermissionsInternal(repository, group, fallbackToDefaultPermissions, nodeIds);
+ return repository.GetPermissionsForEntities(group, fallbackToDefaultPermissions, nodeIds);
}
}
@@ -888,8 +885,7 @@ namespace Umbraco.Core.Services
///
/// Group to retrieve permissions for
///
- /// Flag indicating if we want to get just the permissions directly assigned for the group and path,
- /// or fall back to the group's default permissions when nothing is directly assigned
+ /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
///
/// Specifiying nothing will return all permissions for all nodes
/// An enumerable list of
@@ -899,28 +895,8 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
- return GetPermissionsInternal(repository, group.ToReadOnlyGroup(), fallbackToDefaultPermissions, nodeIds);
+ return repository.GetPermissionsForEntities(group.ToReadOnlyGroup(), fallbackToDefaultPermissions, nodeIds);
}
- }
-
- private static IEnumerable GetPermissionsInternal(IUserGroupRepository repository, IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds)
- {
- if (group == null) throw new ArgumentNullException("group");
-
- var explicitPermissions = repository.GetPermissionsForEntities(group.Id, nodeIds);
- var result = new List(explicitPermissions);
-
- // If requested, and no permissions are assigned to a particular node, then we will fill in those permissions with the group's defaults
- if (fallbackToDefaultPermissions)
- {
- var missingIds = nodeIds.Except(result.Select(x => x.EntityId)).ToArray();
- if (missingIds.Length > 0)
- {
- result.AddRange(missingIds
- .Select(i => new EntityPermission(i, group.Permissions.ToArray(), isDefaultPermissions: true)));
- }
- }
- return result;
}
///
@@ -952,49 +928,18 @@ namespace Umbraco.Core.Services
/// Path to check permissions for
public EntityPermissionSet GetPermissionsForPath(IUser user, string path)
{
- var nodeIds = GetIdsFromPath(path);
+ var nodeIds = path.GetIdsFromPathReversed();
if (nodeIds.Length == 0)
return EntityPermissionSet.Empty();
- var permissionsByGroup = GetPermissionsForGroupsAndPath(user.Groups, nodeIds);
-
- // not sure this will ever happen, it shouldn't since this should return defaults, but maybe those are empty?
- if (permissionsByGroup.Count == 0)
- return EntityPermissionSet.Empty();
-
- var entityId = nodeIds[0];
-
- var groupPermissions = new List();
- foreach (var entityPermission in permissionsByGroup)
- {
- var groupId = entityPermission.Key;
- foreach (var assignedPermission in entityPermission.Value.AssignedPermissions)
- {
- groupPermissions.Add(new EntityPermissionSet.UserGroupPermission(groupId, assignedPermission));
- }
- }
-
- var permissionSet = new EntityPermissionSet(entityId, groupPermissions);
- return permissionSet;
- }
-
- ///
- /// Retrieves the permissions assigned to each group for a given path
- ///
- /// List of groups associated with the user
- /// Path to check permissions for
- /// A dictionary of group ids and their associated node permissions
- private IDictionary GetPermissionsForGroupsAndPath(IEnumerable groups, int[] pathIds)
- {
- return groups
- .Select(g => new
- {
- group = g.Id,
- permissions = GetPermissionsForPath(g, pathIds, fallbackToDefaultPermissions: true)
- })
- .ToDictionary(x => x.group, x => x.permissions);
- }
+ //collect all permissions structures for all nodes for all groups belonging to the user
+ var groupPermissions = user.Groups
+ .Select(g => GetPermissionsForPath(g, nodeIds, fallbackToDefaultPermissions: true))
+ .ToArray();
+
+ return CalculatePermissionsForPathForUser(groupPermissions, nodeIds);
+ }
///
/// Gets the permissions for the provided group and path
@@ -1002,13 +947,12 @@ namespace Umbraco.Core.Services
/// Group to check permissions for
/// Path to check permissions for
///
- /// Flag indicating if we want to get just the permissions directly assigned for the group and path,
- /// or fall back to the group's default permissions when nothing is directly assigned
+ /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
///
/// String indicating permissions for provided user and path
public EntityPermission GetPermissionsForPath(IUserGroup group, string path, bool fallbackToDefaultPermissions = false)
{
- var nodeIds = GetIdsFromPath(path);
+ var nodeIds = path.GetIdsFromPathReversed();
return GetPermissionsForPath(group.ToReadOnlyGroup(), nodeIds, fallbackToDefaultPermissions);
}
@@ -1016,17 +960,91 @@ namespace Umbraco.Core.Services
{
//get permissions for all nodes in the path
var permissions = GetPermissions(group, fallbackToDefaultPermissions, pathIds);
- return GetPermissionsForPath(permissions, pathIds, fallbackToDefaultPermissions);
- }
-
+ return GetPermissionsForPathForGroup(permissions, pathIds, fallbackToDefaultPermissions);
+ }
+
///
- /// Returns the permissions for the path ids
+ /// This performs the calculations for inherited nodes based on this http://issues.umbraco.org/issue/U4-10075#comment=67-40085
///
- ///
- /// Must be ordered deepest to shallowest (right to left)
- ///
+ ///
+ ///
///
- private static EntityPermission GetPermissionsForPath(
+ internal static EntityPermissionSet CalculatePermissionsForPathForUser(
+ EntityPermission[] groupPermissions,
+ int[] pathIds)
+ {
+ // not sure this will ever happen, it shouldn't since this should return defaults, but maybe those are empty?
+ if (groupPermissions.Length == 0 || pathIds.Length == 0)
+ return EntityPermissionSet.Empty();
+
+ //The actual entity id being looked at (deepest part of the path)
+ var entityId = pathIds[0];
+
+ var resultPermissions = new List();
+
+ //create a grouped by dictionary of another grouped by dictionary
+ var permissionsByGroup = groupPermissions
+ .GroupBy(x => x.UserGroupId)
+ .ToDictionary(
+ x => x.Key,
+ x => x.GroupBy(a => a.EntityId).ToDictionary(a => a.Key, a => a.ToArray()));
+
+ //iterate through each group
+ foreach (var byGroup in permissionsByGroup)
+ {
+ var added = false;
+
+ //iterate deepest to shallowest
+ foreach (var pathId in pathIds)
+ {
+ EntityPermission[] permissionsForNodeAndGroup;
+ if (byGroup.Value.TryGetValue(pathId, out permissionsForNodeAndGroup) == false)
+ continue;
+
+ //In theory there will only be one EntityPermission in this group
+ // but there's nothing stopping the logic of this method
+ // from having more so we deal with it here
+ foreach (var entityPermission in permissionsForNodeAndGroup)
+ {
+ if (entityPermission.IsDefaultPermissions == false)
+ {
+ //explicit permision found so we'll append it and move on, of course if there was two explicit permissions
+ //found for this group the ones after this one wouldn't matter but considering there should only be one per
+ //group anyways, that is fine.
+ resultPermissions.Add(entityPermission);
+ added = true;
+ break;
+ }
+ }
+
+ //if the permission has been added for this group and this branch then we can exit this loop
+ if (added)
+ break;
+ }
+
+ if (added == false && byGroup.Value.Count > 0)
+ {
+ //if there was no explicit permissions assigned in this branch for this group, then we will
+ //add the group's default permissions
+ resultPermissions.Add(byGroup.Value[entityId][0]);
+ }
+
+ }
+
+ var permissionSet = new EntityPermissionSet(entityId, resultPermissions);
+ return permissionSet;
+ }
+
+ ///
+ /// Returns the resulting permission set for a group for the path based on all permissions provided for the branch
+ ///
+ /// The collective set of permissions provided to calculate the resulting permissions set for the path
+ /// Must be ordered deepest to shallowest (right to left)
+ ///
+ /// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
+ ///
+ ///
+ internal static EntityPermission GetPermissionsForPathForGroup(
IEnumerable pathPermissions,
int[] pathIds,
bool fallbackToDefaultPermissions = false)
@@ -1051,24 +1069,8 @@ namespace Umbraco.Core.Services
return null;
return permissionsByEntityId[pathIds[0]];
- }
-
- ///
- /// Convert a path to node ids in the order from right to left (deepest to shallowest)
- ///
- ///
- ///
- private int[] GetIdsFromPath(string path)
- {
- var nodeIds = path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
- .Select(x => x.TryConvertTo())
- .Where(x => x.Success)
- .Select(x => x.Result)
- .Reverse()
- .ToArray();
- return nodeIds;
}
-
+
///
/// Checks in a set of permissions associated with a user for those related to a given nodeId
///
diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs
index dba7f2cfee..0780fe799c 100644
--- a/src/Umbraco.Core/StringExtensions.cs
+++ b/src/Umbraco.Core/StringExtensions.cs
@@ -41,6 +41,22 @@ namespace Umbraco.Core
ToCSharpEscapeChars[escape[0]] = escape[1];
}
+ ///
+ /// Convert a path to node ids in the order from right to left (deepest to shallowest)
+ ///
+ ///
+ ///
+ internal static int[] GetIdsFromPathReversed(this string path)
+ {
+ var nodeIds = path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(x => x.TryConvertTo())
+ .Where(x => x.Success)
+ .Select(x => x.Result)
+ .Reverse()
+ .ToArray();
+ return nodeIds;
+ }
+
///
/// Removes new lines and tabs
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 8a635b966c..7269dcd9f6 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -345,6 +345,7 @@
+
@@ -456,7 +457,6 @@
-
@@ -588,6 +588,7 @@
+
diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
index 2b9e0b1ed3..f969488055 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
@@ -533,48 +533,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual(dateValue, persistedTextpage.GetValue(dateTimePropertyAlias));
Assert.AreEqual(persistedTextpage.GetValue(dateTimePropertyAlias), textpage.GetValue(dateTimePropertyAlias));
}
- }
-
- [Test]
- public void Ensures_Permissions_Are_Set_If_Parent_Entity_Permissions_Exist()
- {
- // Arrange
- var provider = new PetaPocoUnitOfWorkProvider(Logger);
- var unitOfWork = provider.GetUnitOfWork();
-
- using (var repository = CreateUserGroupRepository(unitOfWork))
- {
- var userGroup = MockedUserGroup.CreateUserGroup("1");
- repository.AddOrUpdate(userGroup);
- unitOfWork.Commit();
- }
-
- ContentTypeRepository contentTypeRepository;
- using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
- {
- var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
- contentType.AllowedContentTypes = new List
- {
- new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias)
- };
- var parentPage = MockedContent.CreateSimpleContent(contentType);
- contentTypeRepository.AddOrUpdate(contentType);
- repository.AddOrUpdate(parentPage);
- unitOfWork.Commit();
-
- // Act
- repository.AssignEntityPermission(parentPage, 'A', new[] { 1 });
- var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage);
- repository.AddOrUpdate(childPage);
- unitOfWork.Commit();
-
- // Assert
- var permissions = repository.GetPermissionsForEntity(childPage.Id);
- Assert.AreEqual(1, permissions.Count());
- Assert.AreEqual("A", permissions.Single().AssignedPermissions.First());
- }
-
- }
+ }
[Test]
public void Can_Perform_Add_On_ContentRepository()
diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs
index 93202af102..43f049adf4 100644
--- a/src/Umbraco.Tests/Services/ContentServiceTests.cs
+++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs
@@ -1459,7 +1459,7 @@ namespace Umbraco.Tests.Services
}
[Test]
- public void Ensures_Permissions_Are_Set_On_Copied_Entity_To_Parent_Without_Permissions()
+ public void Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explicit_Permissions()
{
// Arrange
var userGroup = MockedUserGroup.CreateUserGroup("1");
@@ -1472,27 +1472,28 @@ namespace Umbraco.Tests.Services
};
ServiceContext.ContentTypeService.Save(contentType);
- var parentPage = MockedContent.CreateSimpleContent(contentType);
- ServiceContext.ContentService.Save(parentPage);
- ServiceContext.ContentService.AssignContentPermission(parentPage, 'A', new[] { 1 });
+ var parentPage = MockedContent.CreateSimpleContent(contentType);
+ ServiceContext.ContentService.Save(parentPage);
var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage);
- ServiceContext.ContentService.Save(childPage);
-
- //Ok, now copy, what should happen is the childPage will not have any permissions assigned since it's new parent
- //doesn't have any assigned
+ ServiceContext.ContentService.Save(childPage);
+ //assign explicit permissions to the child
+ ServiceContext.ContentService.AssignContentPermission(childPage, 'A', new[] { userGroup.Id });
+
+ //Ok, now copy, what should happen is the childPage will retain it's own permissions
var parentPage2 = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(parentPage2);
var copy = ServiceContext.ContentService.Copy(childPage, parentPage2.Id, false, true);
- //Re-get the permissions, since there was none assigned to the new parent, the child shouldn't have any directly assigned
- var copyPermissions = ServiceContext.ContentService.GetPermissionsForEntity(copy);
- Assert.AreEqual(0, copyPermissions.Count());
+ //get the permissions and verify
+ var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, copy.Path, fallbackToDefaultPermissions: true);
+ Assert.AreEqual(1, permissions.AssignedPermissions.Length);
+ Assert.AreEqual("A", permissions.AssignedPermissions[0]);
}
[Test]
- public void Ensures_Permissions_Are_Set_On_Copied_Entity_To_Parent_With_Permissions()
+ public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants()
{
// Arrange
var userGroup = MockedUserGroup.CreateUserGroup("1");
@@ -1507,88 +1508,8 @@ namespace Umbraco.Tests.Services
var parentPage = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(parentPage);
- ServiceContext.ContentService.AssignContentPermission(parentPage, 'A', new[] { 1 });
+ ServiceContext.ContentService.AssignContentPermission(parentPage, 'A', new[] { userGroup.Id });
- var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage);
- ServiceContext.ContentService.Save(childPage);
-
- //Ok, now copy, what should happen is the childPage will have it's new parent permissions copied over
- var parentPage2 = MockedContent.CreateSimpleContent(contentType);
- ServiceContext.ContentService.Save(parentPage2);
- ServiceContext.ContentService.AssignContentPermission(parentPage2, 'B', new[] { 1 });
-
- var copy = ServiceContext.ContentService.Copy(childPage, parentPage2.Id, false, true);
-
- //Re-get the permissions, since there was none assigned to the new parent, the child shouldn't have any directly assigned
- var copyPermissions = ServiceContext.ContentService.GetPermissionsForEntity(copy);
- Assert.AreEqual(1, copyPermissions.Count());
- Assert.AreEqual("B", copyPermissions.Single().AssignedPermissions.First());
- }
-
- [Test]
- public void Ensures_Permissions_Are_Set_On_Copied_Descendants_To_Parent_With_Permissions()
- {
- // Arrange
- var userGroup = MockedUserGroup.CreateUserGroup("1");
- ServiceContext.UserService.Save(userGroup);
-
- var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
- contentType.AllowedContentTypes = new List
- {
- new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias)
- };
- ServiceContext.ContentTypeService.Save(contentType);
-
- var parentPage = MockedContent.CreateSimpleContent(contentType);
- ServiceContext.ContentService.Save(parentPage);
- ServiceContext.ContentService.AssignContentPermission(parentPage, 'A', new[] { 1 });
-
- var childPage1 = MockedContent.CreateSimpleContent(contentType, "child1", parentPage);
- ServiceContext.ContentService.Save(childPage1);
- var childPage2 = MockedContent.CreateSimpleContent(contentType, "child2", childPage1);
- ServiceContext.ContentService.Save(childPage2);
- var childPage3 = MockedContent.CreateSimpleContent(contentType, "child3", childPage2);
- ServiceContext.ContentService.Save(childPage3);
-
- //Ok, now copy, what should happen is the childPage will have it's new parent permissions copied over
- var parentPage2 = MockedContent.CreateSimpleContent(contentType);
- ServiceContext.ContentService.Save(parentPage2);
- ServiceContext.ContentService.AssignContentPermission(parentPage2, 'B', new[] { 1 });
-
- var copy = ServiceContext.ContentService.Copy(childPage1, parentPage2.Id, false, true);
-
- //Re-get the permissions, since there was none assigned to the new parent, the child shouldn't have any directly assigned
- var copyPermissions = ServiceContext.ContentService.GetPermissionsForEntity(copy);
- Assert.AreEqual(1, copyPermissions.Count());
- Assert.AreEqual("B", copyPermissions.Single().AssignedPermissions.First());
-
- var descendants = ServiceContext.ContentService.GetDescendants(copy).ToArray();
- Assert.AreEqual(2, descendants.Length);
-
- foreach (var descendant in descendants)
- {
- var permissions = ServiceContext.ContentService.GetPermissionsForEntity(descendant);
- Assert.AreEqual(1, permissions.Count());
- Assert.AreEqual("B", permissions.Single().AssignedPermissions.First());
- }
- }
-
- [Test]
- public void Ensures_Permissions_Are_Set_On_Descendants_When_Permissions_Added()
- {
- // Arrange
- var userGroup = MockedUserGroup.CreateUserGroup("1");
- ServiceContext.UserService.Save(userGroup);
-
- var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
- contentType.AllowedContentTypes = new List
- {
- new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias)
- };
- ServiceContext.ContentTypeService.Save(contentType);
-
- var parentPage = MockedContent.CreateSimpleContent(contentType);
- ServiceContext.ContentService.Save(parentPage);
var childPage1 = MockedContent.CreateSimpleContent(contentType, "child1", parentPage);
ServiceContext.ContentService.Save(childPage1);
var childPage2 = MockedContent.CreateSimpleContent(contentType, "child2", childPage1);
@@ -1596,37 +1517,33 @@ namespace Umbraco.Tests.Services
var childPage3 = MockedContent.CreateSimpleContent(contentType, "child3", childPage2);
ServiceContext.ContentService.Save(childPage3);
- //ensure there are no permissions on any node
-
- var permissions = ServiceContext.ContentService.GetPermissionsForEntity(parentPage);
- Assert.AreEqual(0, permissions.Count());
-
+ //Verify that the children have the inherited permissions
var descendants = ServiceContext.ContentService.GetDescendants(parentPage).ToArray();
Assert.AreEqual(3, descendants.Length);
foreach (var descendant in descendants)
{
- permissions = ServiceContext.ContentService.GetPermissionsForEntity(descendant);
- Assert.AreEqual(0, permissions.Count());
+ var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions:true);
+ Assert.AreEqual(1, permissions.AssignedPermissions.Length);
+ Assert.AreEqual("A", permissions.AssignedPermissions[0]);
}
-
- //Ok, now assign permissions to the parent, all descenents should get these right?
- ServiceContext.ContentService.AssignContentPermission(parentPage, 'A', new[] { 1 });
-
- //re-test
- permissions = ServiceContext.ContentService.GetPermissionsForEntity(parentPage);
- Assert.AreEqual(1, permissions.Count());
- Assert.AreEqual("A", permissions.Single().AssignedPermissions.First());
+ //create a new parent with a new permission structure
+ var parentPage2 = MockedContent.CreateSimpleContent(contentType);
+ ServiceContext.ContentService.Save(parentPage2);
+ ServiceContext.ContentService.AssignContentPermission(parentPage2, 'B', new[] { userGroup.Id });
- descendants = ServiceContext.ContentService.GetDescendants(parentPage).ToArray();
+ //Now copy, what should happen is the child pages will now have permissions inherited from the new parent
+ var copy = ServiceContext.ContentService.Copy(childPage1, parentPage2.Id, false, true);
+
+ descendants = ServiceContext.ContentService.GetDescendants(parentPage2).ToArray();
Assert.AreEqual(3, descendants.Length);
foreach (var descendant in descendants)
{
- permissions = ServiceContext.ContentService.GetPermissionsForEntity(descendant);
- Assert.AreEqual(1, permissions.Count());
- Assert.AreEqual("A", permissions.Single().AssignedPermissions.First());
+ var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true);
+ Assert.AreEqual(1, permissions.AssignedPermissions.Length);
+ Assert.AreEqual("B", permissions.AssignedPermissions[0]);
}
}
diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs
index d672229e6b..ac58f9f734 100644
--- a/src/Umbraco.Tests/Services/UserServiceTests.cs
+++ b/src/Umbraco.Tests/Services/UserServiceTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
@@ -10,6 +11,7 @@ using Umbraco.Core.Persistence.Querying;
using Umbraco.Tests.TestHelpers;
using Umbraco.Core;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
+using Umbraco.Core.Services;
namespace Umbraco.Tests.Services
{
@@ -151,7 +153,7 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { userGroup.Id });
// Act
- var permissions = userService.GetPermissions(userGroup, true, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id)
+ var permissions = userService.GetPermissions(userGroup, true, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id)
.ToArray();
//assert
@@ -161,6 +163,132 @@ namespace Umbraco.Tests.Services
Assert.AreEqual(17,permissions[2].AssignedPermissions.Length);
}
+ [Test]
+
+ [Test]
+ public void Calculate_Permissions_For_User_For_Path_1()
+ {
+ //see: http://issues.umbraco.org/issue/U4-10075#comment=67-40085
+ // for an overview of what this is testing
+
+ const string path = "-1,1,2,3,4";
+ var pathIds = path.GetIdsFromPathReversed();
+
+ const int groupA = 7;
+ const int groupB = 8;
+ const int groupC = 9;
+
+ var userGroups = new Dictionary
+ {
+ {groupA, new[] {"S", "D", "F"}},
+ {groupB, new[] {"S", "D", "G", "K"}},
+ {groupC, new[] {"F", "G"}}
+ };
+
+ var permissions = new []
+ {
+ new EntityPermission(groupA, 1, userGroups[groupA], isDefaultPermissions:true),
+ new EntityPermission(groupA, 2, userGroups[groupA], isDefaultPermissions:true),
+ new EntityPermission(groupA, 3, userGroups[groupA], isDefaultPermissions:true),
+ new EntityPermission(groupA, 4, userGroups[groupA], isDefaultPermissions:true),
+
+ new EntityPermission(groupB, 1, userGroups[groupB], isDefaultPermissions:true),
+ new EntityPermission(groupB, 2, new []{"F", "R"}, isDefaultPermissions:false),
+ new EntityPermission(groupB, 3, userGroups[groupB], isDefaultPermissions:true),
+ new EntityPermission(groupB, 4, userGroups[groupB], isDefaultPermissions:true),
+
+ new EntityPermission(groupC, 1, userGroups[groupC], isDefaultPermissions:true),
+ new EntityPermission(groupC, 2, userGroups[groupC], isDefaultPermissions:true),
+ new EntityPermission(groupC, 3, new []{"Q", "Z"}, isDefaultPermissions:false),
+ new EntityPermission(groupC, 4, userGroups[groupC], isDefaultPermissions:true),
+ };
+
+ //Permissions for Id 4
+ var result = UserService.CalculatePermissionsForPathForUser(permissions, pathIds);
+ Assert.AreEqual(4, result.EntityId);
+ var allPermissions = result.GetAllPermissions().ToArray();
+ Assert.AreEqual(6, allPermissions.Length, string.Join(",", allPermissions));
+ Assert.IsTrue(allPermissions.ContainsAll(new[] { "S", "D", "F", "R", "Q", "Z" }));
+
+ //Permissions for Id 3
+ result = UserService.CalculatePermissionsForPathForUser(permissions, pathIds.Skip(1).ToArray());
+ Assert.AreEqual(3, result.EntityId);
+ allPermissions = result.GetAllPermissions().ToArray();
+ Assert.AreEqual(6, allPermissions.Length, string.Join(",", allPermissions));
+ Assert.IsTrue(allPermissions.ContainsAll(new[] { "S", "D", "F", "R", "Q", "Z" }));
+
+ //Permissions for Id 2
+ result = UserService.CalculatePermissionsForPathForUser(permissions, pathIds.Skip(2).ToArray());
+ Assert.AreEqual(2, result.EntityId);
+ allPermissions = result.GetAllPermissions().ToArray();
+ Assert.AreEqual(5, allPermissions.Length, string.Join(",", allPermissions));
+ Assert.IsTrue(allPermissions.ContainsAll(new[] { "S", "D", "F", "G", "R" }));
+
+ //Permissions for Id 1
+ result = UserService.CalculatePermissionsForPathForUser(permissions, pathIds.Skip(3).ToArray());
+ Assert.AreEqual(1, result.EntityId);
+ allPermissions = result.GetAllPermissions().ToArray();
+ Assert.AreEqual(5, allPermissions.Length, string.Join(",", allPermissions));
+ Assert.IsTrue(allPermissions.ContainsAll(new[] { "S", "D", "F", "G", "K" }));
+
+ }
+
+ [Test]
+ public void Determine_Deepest_Explicit_Permissions_For_Group_For_Path_1()
+ {
+ var path = "-1,1,2,3";
+ var pathIds = path.GetIdsFromPathReversed();
+ var defaults = new[] {"A", "B"};
+ var permissions = new List
+ {
+ new EntityPermission(9876, 1, defaults, isDefaultPermissions:true),
+ new EntityPermission(9876, 2, new []{"B","C", "D"}, isDefaultPermissions:false),
+ new EntityPermission(9876, 3, defaults, isDefaultPermissions:true)
+ };
+ var result = UserService.GetPermissionsForPathForGroup(permissions, pathIds, fallbackToDefaultPermissions: true);
+ Assert.AreEqual(3, result.AssignedPermissions.Length);
+ Assert.IsFalse(result.IsDefaultPermissions);
+ Assert.IsTrue(result.AssignedPermissions.ContainsAll(new[] { "B", "C", "D" }));
+ Assert.AreEqual(2, result.EntityId);
+ Assert.AreEqual(9876, result.UserGroupId);
+ }
+
+ [Test]
+ public void Determine_Deepest_Explicit_Permissions_For_Group_For_Path_2()
+ {
+ var path = "-1,1,2,3";
+ var pathIds = path.GetIdsFromPathReversed();
+ var defaults = new[] { "A", "B", "C" };
+ var permissions = new List
+ {
+ new EntityPermission(9876, 1, defaults, isDefaultPermissions:true),
+ new EntityPermission(9876, 2, defaults, isDefaultPermissions:true),
+ new EntityPermission(9876, 3, defaults, isDefaultPermissions:true)
+ };
+ var result = UserService.GetPermissionsForPathForGroup(permissions, pathIds, fallbackToDefaultPermissions:false);
+ Assert.IsNull(result);
+ }
+
+ [Test]
+ public void Determine_Deepest_Explicit_Permissions_For_Group_For_Path_3()
+ {
+ var path = "-1,1,2,3";
+ var pathIds = path.GetIdsFromPathReversed();
+ var defaults = new[] { "A", "B" };
+ var permissions = new List
+ {
+ new EntityPermission(9876, 1, defaults, isDefaultPermissions:true),
+ new EntityPermission(9876, 2, defaults, isDefaultPermissions:true),
+ new EntityPermission(9876, 3, defaults, isDefaultPermissions:true)
+ };
+ var result = UserService.GetPermissionsForPathForGroup(permissions, pathIds, fallbackToDefaultPermissions: true);
+ Assert.AreEqual(2, result.AssignedPermissions.Length);
+ Assert.IsTrue(result.IsDefaultPermissions);
+ Assert.IsTrue(result.AssignedPermissions.ContainsAll(defaults));
+ Assert.AreEqual(3, result.EntityId);
+ Assert.AreEqual(9876, result.UserGroupId);
+ }
+
[Test]
public void Get_User_Implicit_Permissions()
{
diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs
index f4480ca636..bc1f5dfe77 100644
--- a/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs
@@ -50,7 +50,8 @@ namespace Umbraco.Tests.Web.Controllers
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock();
var permissions = new List();
- userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act/assert
@@ -73,7 +74,8 @@ namespace Umbraco.Tests.Web.Controllers
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock();
var permissions = new List();
- userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -100,9 +102,10 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock();
var permissions = new List
{
- new EntityPermission(1234, new string[]{ "A", "B", "C" })
+ new EntityPermission(9876, 1234, new string[]{ "A", "B", "C" })
};
- userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -129,9 +132,10 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock();
var permissions = new List
{
- new EntityPermission(1234, new string[]{ "A", "F", "C" })
+ new EntityPermission(9876, 1234, new string[]{ "A", "F", "C" })
};
- userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -217,9 +221,10 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock();
var permissions = new List
{
- new EntityPermission(1234, new string[]{ "A" })
+ new EntityPermission(9876, 1234, new string[]{ "A" })
};
- userServiceMock.Setup(x => x.GetPermissions(user, -1)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -241,9 +246,10 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock();
var permissions = new List
{
- new EntityPermission(1234, new string[]{ "A" })
+ new EntityPermission(9876, 1234, new string[]{ "A" })
};
- userServiceMock.Setup(x => x.GetPermissions(user, -1)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -264,10 +270,12 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock();
var permissions = new List
- {
- new EntityPermission(1234, new string[]{ "A" })
- };
- userServiceMock.Setup(x => x.GetPermissions(user, -20)).Returns(permissions);
+ {
+ new EntityPermission(9876, 1234, new string[]{ "A" })
+ };
+ var permissionSet = new EntityPermissionSet(-20, permissions);
+
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-20")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -289,9 +297,10 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock();
var permissions = new List
{
- new EntityPermission(1234, new string[]{ "A" })
+ new EntityPermission(9876, 1234, new string[]{ "A" })
};
- userServiceMock.Setup(x => x.GetPermissions(user, -20)).Returns(permissions);
+ var permissionSet = new EntityPermissionSet(1234, permissions);
+ userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-20")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
diff --git a/src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs b/src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs
index 8e84dcf030..49ce356324 100644
--- a/src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs
@@ -112,10 +112,10 @@ namespace Umbraco.Tests.Web.Controllers
//we're only assigning 3 nodes browse permissions so that is what we expect as a result
var permissions = new List
{
- new EntityPermission(1, new string[]{ "F" }),
- new EntityPermission(2, new string[]{ "F" }),
- new EntityPermission(3, new string[]{ "F" }),
- new EntityPermission(4, new string[]{ "A" })
+ new EntityPermission(9876, 1, new string[]{ "F" }),
+ new EntityPermission(9876, 2, new string[]{ "F" }),
+ new EntityPermission(9876, 3, new string[]{ "F" }),
+ new EntityPermission(9876, 4, new string[]{ "A" })
};
userServiceMock.Setup(x => x.GetPermissions(user, ids)).Returns(permissions);
var userService = userServiceMock.Object;
diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
index 4b65eb1b3a..8e628204d8 100644
--- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
+++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
@@ -599,10 +599,13 @@ namespace Umbraco.Web.Cache
#region User/permissions event handlers
- static void CacheRefresherEventHandler_AssignedPermissions(PermissionRepository sender, SaveEventArgs e)
+ static void CacheRefresherEventHandler_AssignedPermissions(PermissionRepository sender, SaveEventArgs e)
{
var groupIds = e.SavedEntities.Select(x => x.UserGroupId).Distinct();
- groupIds.ForEach(x => DistributedCache.Instance.RefreshUserGroupPermissionsCache(x));
+ foreach (var groupId in groupIds)
+ {
+ DistributedCache.Instance.RefreshUserGroupPermissionsCache(groupId);
+ }
}
static void PermissionDeleted(UserGroupPermission sender, DeleteEventArgs e)
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index 8fd2d8f221..f935673317 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -1076,17 +1076,21 @@ namespace Umbraco.Web.Editors
return false;
}
- if (permissionsToCheck == null || permissionsToCheck.Any() == false)
+ if (permissionsToCheck == null || permissionsToCheck.Length == 0)
{
return true;
}
-
- var permission = userService.GetPermissions(user, nodeId).FirstOrDefault();
+
+ //get the implicit/inherited permissions for the user for this path,
+ //if there is no content item for this id, than just use the id as the path (i.e. -1 or -20)
+ var path = contentItem != null ? contentItem.Path : nodeId.ToString();
+ var permission = userService.GetPermissionsForPath(user, path);
var allowed = true;
foreach (var p in permissionsToCheck)
{
- if (permission == null || permission.AssignedPermissions.Contains(p.ToString(CultureInfo.InvariantCulture)) == false)
+ if (permission == null
+ || permission.GetAllPermissions().Contains(p.ToString(CultureInfo.InvariantCulture)) == false)
{
allowed = false;
}
diff --git a/src/umbraco.businesslogic/User.cs b/src/umbraco.businesslogic/User.cs
index 0f92a4427f..dcac5a0caf 100644
--- a/src/umbraco.businesslogic/User.cs
+++ b/src/umbraco.businesslogic/User.cs
@@ -572,7 +572,7 @@ namespace umbraco.BusinessLogic
var userService = ApplicationContext.Current.Services.UserService;
return string.Join("",
- userService.GetPermissionsForPath(UserEntity, path).PermissionsSet.SelectMany(x => x.Permission));
+ userService.GetPermissionsForPath(UserEntity, path).GetAllPermissions());
}
///