Gets inherited permissions working, adds lots of unit tests, few more tests to write now.

This commit is contained in:
Shannon
2017-07-13 00:07:51 +10:00
parent 7115d85440
commit 044120ffd2
26 changed files with 725 additions and 501 deletions
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an <see cref="IContent"/> -> user group & permission key value pair collection
/// </summary>
/// <remarks>
/// This implements <see cref="IAggregateRoot"/> purely so it can be used with the repository layer which is why it's explicitly implemented.
/// </remarks>
public class ContentPermissionSet : EntityPermissionSet, IAggregateRoot
{
private readonly IContent _content;
public ContentPermissionSet(IContent content, IEnumerable<EntityPermission> 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
}
}
@@ -7,21 +7,24 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
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; }
/// <summary>
/// The assigned permissions for the user/entity combo
@@ -50,7 +53,9 @@ namespace Umbraco.Core.Models.Membership
AssignedPermissions = newPermissions
.Distinct()
.ToArray();
}
}
}
}
@@ -1,60 +1,56 @@
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an entity -> user group & permission key value pair collection
/// </summary>
/// </summary>
public class EntityPermissionSet
{
/// <summary>
/// The entity id with permissions assigned
/// Returns an empty permission set
/// </summary>
public int EntityId { get; private set; }
/// <returns></returns>
public static EntityPermissionSet Empty()
{
return new EntityPermissionSet(-1, new EntityPermission[0]);
}
/// <summary>
/// The key/value pairs of user group id & single permission
/// </summary>
public IEnumerable<UserGroupPermission> PermissionsSet { get; private set; }
public EntityPermissionSet(int entityId, IEnumerable<UserGroupPermission> permissionsSet)
public EntityPermissionSet(int entityId, IEnumerable<EntityPermission> permissionsSet)
{
EntityId = entityId;
PermissionsSet = permissionsSet;
}
public class UserGroupPermission
/// <summary>
/// The entity id with permissions assigned
/// </summary>
public virtual int EntityId { get; private set; }
/// <summary>
/// The key/value pairs of user group id & single permission
/// </summary>
public IEnumerable<EntityPermission> PermissionsSet { get; private set; }
/// <summary>
/// Returns the aggregte permissions in the permission set
/// </summary>
/// <returns></returns>
/// <remarks>
/// This value is only calculated once
/// </remarks>
public IEnumerable<string> 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;
}
}
@@ -1,16 +0,0 @@
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a user group -> entity permission
/// </summary>
public class UserGroupEntityPermission : EntityPermission
{
public UserGroupEntityPermission(int groupId, int entityId, string[] assignedPermissions)
: base(entityId, assignedPermissions)
{
UserGroupId = groupId;
}
public int UserGroupId { get; private set; }
}
}
@@ -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
{
/// <summary>
/// Override the base content repository so we can change the node object type
/// </summary>
/// <remarks>
/// 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
/// </remarks>
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; }
}
}
}
@@ -20,28 +20,6 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Override the base content repository so we can change the node object type
/// </summary>
/// <remarks>
/// 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
/// </remarks>
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; }
}
}
/// <summary>
/// Represents a repository for doing CRUD operations for <see cref="IContent"/>
/// </summary>
@@ -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<IContent> _contentPreviewRepository;
private readonly ContentXmlRepository<IContent> _contentXmlRepository;
private readonly PermissionRepository<IContent> _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<IContent>(work, CacheHelper.NoCache, logger, syntaxProvider);
_contentXmlRepository = new ContentXmlRepository<IContent>(work, CacheHelper.NoCache, logger, syntaxProvider);
_permissionRepository = new PermissionRepository<IContent>(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<IContent>(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<IContent>(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",
/// <param name="permission"></param>
/// <param name="groupIds"></param>
public void AssignEntityPermission(IContent entity, char permission, IEnumerable<int> groupIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper, SqlSyntax);
repo.AssignEntityPermission(entity, permission, groupIds);
{
_permissionRepository.AssignEntityPermission(entity, permission, groupIds);
}
/// <summary>
/// Returns permissions directly assigned to the content item for all user groups
/// Gets the explicit list of permissions for the content item
/// </summary>
/// <param name="entityId"></param>
/// <returns></returns>
public IEnumerable<UserGroupEntityPermission> GetPermissionsForEntity(int entityId)
public IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper, SqlSyntax);
return repo.GetPermissionsForEntity(entityId);
}
return _permissionRepository.GetPermissionsForEntity(entityId);
}
/// <summary>
/// Adds/updates content/published xml
@@ -906,6 +862,15 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
_contentXmlRepository.AddOrUpdate(new ContentXmlEntity<IContent>(content, xml));
}
/// <summary>
/// Used to add/update a permission for a content item
/// </summary>
/// <param name="permission"></param>
public void AddOrUpdatePermissions(ContentPermissionSet permission)
{
_permissionRepository.AddOrUpdate(permission);
}
/// <summary>
/// Used to remove the content xml for a content item
/// </summary>
@@ -57,11 +57,18 @@ namespace Umbraco.Core.Persistence.Repositories
void AssignEntityPermission(IContent entity, char permission, IEnumerable<int> groupIds);
/// <summary>
/// Gets the list of permissions for the content item
/// Gets the explicit list of permissions for the content item
/// </summary>
/// <param name="entityId"></param>
/// <returns></returns>
IEnumerable<UserGroupEntityPermission> GetPermissionsForEntity(int entityId);
IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId);
///// <summary>
///// Gets the implicit/inherited list of permissions for the content item
///// </summary>
///// <param name="path"></param>
///// <returns></returns>
//IEnumerable<EntityPermission> GetPermissionsForPath(string path);
/// <summary>
/// Used to add/update published xml for the content item
@@ -70,6 +77,12 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="xml"></param>
void AddOrUpdateContentXml(IContent content, Func<IContent, XElement> xml);
/// <summary>
/// Used to add/update a permission for a content item
/// </summary>
/// <param name="permission"></param>
void AddOrUpdatePermissions(ContentPermissionSet permission);
/// <summary>
/// Used to remove the content xml for a content item
/// </summary>
@@ -32,6 +32,14 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entityIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
IEnumerable<EntityPermission> GetPermissionsForEntities(int groupId, params int[] entityIds);
/// <summary>
/// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
/// </summary>
/// <param name="group">The group</param>
/// <param name="fallbackToDefaultPermissions">If true will include the group's default permissions if no permissions are explicitly assigned</param>
/// <param name="nodeIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
IEnumerable<EntityPermission> GetPermissionsForEntities(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds);
/// <summary>
/// Replaces the same permission set for a single group to any number of entities
/// </summary>
@@ -47,6 +55,6 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="permission">Permissions as enumerable list of <see cref="char"/></param>
/// <param name="entityIds">Specify the nodes to replace permissions for</param>
void AssignGroupPermission(int groupId, char permission, params int[] entityIds);
}
}
@@ -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
/// </summary>
/// <typeparam name="TEntity"></typeparam>
internal class PermissionRepository<TEntity>
/// <remarks>
/// This repo implements the base <see cref="PetaPocoRepositoryBase{TId,TEntity}"/> 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 <see cref="NotImplementedException"/>
/// </remarks>
internal class PermissionRepository<TEntity> : PetaPocoRepositoryBase<int, ContentPermissionSet>
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<EntityPermission>();
_sqlSyntax = sqlSyntax;
}
/// <summary>
@@ -41,7 +43,6 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entityIds"></param>
/// <returns></returns>
public IEnumerable<EntityPermission> GetPermissionsForEntities(int groupId, params int[] entityIds)
{
//var whereCriteria = GetPermissionsForEntitiesCriteria(groupId, entityIds);
var result = new List<EntityPermission>();
//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<UserGroup2NodePermissionDto>(_sqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => dto.UserGroupId == groupId && ids.Contains(dto.NodeId), _sqlSyntax);
var permissions = _unitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => dto.UserGroupId == groupId && ids.Contains(dto.NodeId), SqlSyntax);
var permissions = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
result.AddRange(ConvertToPermissionList(permissions));
}
return result;
@@ -73,62 +74,62 @@ namespace Umbraco.Core.Persistence.Repositories
// sql.Select("*")
// .From<UserGroup2NodePermissionDto>()
// .Where(whereCriteria);
// var result = _unitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
// var result = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(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<UserGroupEntityPermission> ConvertToPermissionList(IEnumerable<UserGroup2NodePermissionDto> 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;
//}
/// <summary>
/// Returns permissions directly assigned to the content items for all user groups
/// </summary>
/// <param name="entityIds"></param>
/// <returns></returns>
public IEnumerable<EntityPermission> GetPermissionsForEntities(int[] entityIds)
{
var permissions = new List<UserGroupEntityPermission>();
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<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => entityIds.Contains(dto.NodeId), SqlSyntax)
.OrderBy<UserGroup2NodePermissionDto>(dto => dto.NodeId, SqlSyntax);
return permissions;
}
var result = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
return ConvertToPermissionList(result);
}
/// <summary>
/// Returns permissions directly assigned to the content item for all user groups
/// </summary>
/// <param name="entityId"></param>
/// <returns></returns>
public IEnumerable<UserGroupEntityPermission> GetPermissionsForEntity(int entityId)
public IEnumerable<EntityPermission> GetPermissionsForEntity(int entityId)
{
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>()
.Where<UserGroup2NodePermissionDto>(dto => dto.NodeId == entityId)
.OrderBy<UserGroup2NodePermissionDto>(dto => dto.NodeId);
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => dto.NodeId == entityId, SqlSyntax)
.OrderBy<UserGroup2NodePermissionDto>(dto => dto.NodeId, SqlSyntax);
var result = _unitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
var result = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
return ConvertToPermissionList(result);
}
@@ -143,7 +144,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// </remarks>
public void ReplacePermissions(int groupId, IEnumerable<char> 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<UserGroupEntityPermission>(ConvertToPermissionList(toInsert), false));
UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<EntityPermission>(ConvertToPermissionList(toInsert), false));
}
@@ -181,7 +182,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entityIds"></param>
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<UserGroupEntityPermission>(ConvertToPermissionList(actions), false));
UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<EntityPermission>(ConvertToPermissionList(actions), false));
}
@@ -213,7 +214,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="groupIds"></param>
public void AssignEntityPermission(TEntity entity, char permission, IEnumerable<int> 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<UserGroupEntityPermission>(ConvertToPermissionList(actions), false));
UnitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<EntityPermission>(ConvertToPermissionList(actions), false));
}
/// <summary>
/// Assigns permissions to an entity for multiple users/permission entries
/// Assigns permissions to an entity for multiple group/permission entries
/// </summary>
/// <param name="permissionSet">
/// </param>
@@ -247,25 +248,118 @@ namespace Umbraco.Core.Persistence.Repositories
/// </remarks>
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<UserGroup2NodePermissionDto>();
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<EntityPermission>(permissionSet.PermissionsSet, false));
_unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
//Raise the event
_unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<UserGroupEntityPermission>(ConvertToPermissionList(actions), false));
}
public static event TypedEventHandler<PermissionRepository<TEntity>, SaveEventArgs<UserGroupEntityPermission>> 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<ContentPermissionSet> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
}
protected override IEnumerable<ContentPermissionSet> PerformGetByQuery(IQuery<ContentPermissionSet> query)
{
throw new NotImplementedException();
}
protected override Sql GetBaseQuery(bool isCount)
{
throw new NotImplementedException();
}
protected override string GetBaseWhereClause()
{
throw new NotImplementedException();
}
protected override IEnumerable<string> GetDeleteClauses()
{
return new List<string>();
}
protected override Guid NodeObjectTypeId
{
get { throw new NotImplementedException(); }
}
protected override void PersistDeletedItem(ContentPermissionSet entity)
{
throw new NotImplementedException();
}
#endregion
/// <summary>
/// Used to add or update entity permissions during a content item being updated
/// </summary>
/// <param name="entity"></param>
protected override void PersistNewItem(ContentPermissionSet entity)
{
//does the same thing as update
PersistUpdatedItem(entity);
}
/// <summary>
/// Used to add or update entity permissions during a content item being updated
/// </summary>
/// <param name="entity"></param>
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<EntityPermission> ConvertToPermissionList(IEnumerable<UserGroup2NodePermissionDto> result)
{
var permissions = new List<EntityPermission>();
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<PermissionRepository<TEntity>, SaveEventArgs<EntityPermission>> AssignedPermissions;
}
}
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Persistence.Repositories
return Database.Fetch<TDto>(sql).Select(ConvertToEntity);
}
protected override sealed IEnumerable<TEntity> PerformGetByQuery(IQuery<TEntity> query)
protected sealed override IEnumerable<TEntity> PerformGetByQuery(IQuery<TEntity> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<TEntity>(sqlClause, query);
@@ -76,22 +76,22 @@ namespace Umbraco.Core.Persistence.Repositories
#region Not implemented and not required
protected override sealed IEnumerable<string> GetDeleteClauses()
protected sealed override IEnumerable<string> 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();
}
@@ -22,12 +22,14 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly CacheHelper _cacheHelper;
private readonly UserGroupWithUsersRepository _userGroupWithUsersRepository;
private readonly PermissionRepository<IContent> _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<IContent>(work, _cacheHelper, logger, sqlSyntax);
}
public const string GetByAliasCacheKeyPrefix = "UserGroupRepository_GetByAlias_";
@@ -97,8 +99,33 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entityIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
public IEnumerable<EntityPermission> GetPermissionsForEntities(int groupId, params int[] entityIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper, SqlSyntax);
return repo.GetPermissionsForEntities(groupId, entityIds);
return _permissionRepository.GetPermissionsForEntities(groupId, entityIds);
}
/// <summary>
/// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
/// </summary>
/// <param name="group">The group</param>
/// <param name="fallbackToDefaultPermissions">If true will include the group's default permissions if no permissions are explicitly assigned</param>
/// <param name="nodeIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
public IEnumerable<EntityPermission> 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<EntityPermission>(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;
}
/// <summary>
@@ -109,8 +136,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entityIds">Specify the nodes to replace permissions for. If nothing is specified all permissions are removed.</param>
public void ReplaceGroupPermissions(int groupId, IEnumerable<char> permissions, params int[] entityIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper, SqlSyntax);
repo.ReplacePermissions(groupId, permissions, entityIds);
_permissionRepository.ReplacePermissions(groupId, permissions, entityIds);
}
/// <summary>
@@ -121,9 +147,8 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="entityIds">Specify the nodes to replace permissions for</param>
public void AssignGroupPermission(int groupId, char permission, params int[] entityIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper, SqlSyntax);
repo.AssignPermission(groupId, permission, entityIds);
}
_permissionRepository.AssignPermission(groupId, permission, entityIds);
}
#region Overrides of RepositoryBase<int,IUserType>
+15 -3
View File
@@ -130,11 +130,11 @@ namespace Umbraco.Core.Services
}
/// <summary>
/// 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
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public IEnumerable<UserGroupEntityPermission> GetPermissionsForEntity(IContent content)
public IEnumerable<EntityPermission> 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
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Services
/// <param name="contentId"></param>
public static void RemoveContentPermissions(this IContentService contentService, int contentId)
{
contentService.ReplaceContentPermissions(new EntityPermissionSet(contentId, Enumerable.Empty<EntityPermissionSet.UserGroupPermission>()));
contentService.ReplaceContentPermissions(new EntityPermissionSet(contentId, Enumerable.Empty<EntityPermission>()));
}
/// <summary>
+2 -2
View File
@@ -151,11 +151,11 @@ namespace Umbraco.Core.Services
void AssignContentPermission(IContent entity, char permission, IEnumerable<int> groupIds);
/// <summary>
/// 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
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
IEnumerable<UserGroupEntityPermission> GetPermissionsForEntity(IContent content);
IEnumerable<EntityPermission> GetPermissionsForEntity(IContent content);
bool SendToPublication(IContent content, int userId = 0);
+4 -6
View File
@@ -102,8 +102,7 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="group">Group to retrieve permissions for</param>
/// <param name="fallbackToDefaultPermissions">
/// 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
/// </param>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
@@ -114,16 +113,15 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="user">User to check permissions for</param>
/// <param name="path">Path to check permissions for</param>
EntityPermissionSet GetPermissionsForPath(IUser user, string path);
EntityPermissionSet GetPermissionsForPath(IUser user, string path);
/// <summary>
/// Gets the permissions for the provided group and path
/// </summary>
/// <param name="group">Group to check permissions for</param>
/// <param name="path">Path to check permissions for</param>
/// <param name="fallbackToDefaultPermissions">
/// 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
/// </param>
EntityPermission GetPermissionsForPath(IUserGroup group, string path, bool fallbackToDefaultPermissions = false);
+99 -97
View File
@@ -865,21 +865,18 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="group">Group to retrieve permissions for</param>
/// <param name="fallbackToDefaultPermissions">
/// 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
/// </param>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
private IEnumerable<EntityPermission> GetPermissions(IReadOnlyUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
if (group == null) throw new ArgumentNullException("group");
if (nodeIds.Length == 0)
return Enumerable.Empty<EntityPermission>();
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
/// </summary>
/// <param name="group">Group to retrieve permissions for</param>
/// <param name="fallbackToDefaultPermissions">
/// 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
/// </param>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
@@ -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<EntityPermission> 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<EntityPermission>(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;
}
/// <summary>
@@ -952,49 +928,18 @@ namespace Umbraco.Core.Services
/// <param name="path">Path to check permissions for</param>
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<EntityPermissionSet.UserGroupPermission>();
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;
}
/// <summary>
/// Retrieves the permissions assigned to each group for a given path
/// </summary>
/// <param name="groups">List of groups associated with the user</param>
/// <param name="pathIds">Path to check permissions for</param>
/// <returns>A dictionary of group ids and their associated node permissions</returns>
private IDictionary<int, EntityPermission> GetPermissionsForGroupsAndPath(IEnumerable<IReadOnlyUserGroup> 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);
}
/// <summary>
/// Gets the permissions for the provided group and path
@@ -1002,13 +947,12 @@ namespace Umbraco.Core.Services
/// <param name="group">Group to check permissions for</param>
/// <param name="path">Path to check permissions for</param>
/// <param name="fallbackToDefaultPermissions">
/// 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
/// </param>
/// <returns>String indicating permissions for provided user and path</returns>
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);
}
/// <summary>
/// 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
/// </summary>
/// <param name="pathPermissions"></param>
/// <param name="pathIds">Must be ordered deepest to shallowest (right to left)</param>
/// <param name="fallbackToDefaultPermissions"></param>
/// <param name="groupPermissions"></param>
/// <param name="pathIds"></param>
/// <returns></returns>
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<EntityPermission>();
//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;
}
/// <summary>
/// Returns the resulting permission set for a group for the path based on all permissions provided for the branch
/// </summary>
/// <param name="pathPermissions">The collective set of permissions provided to calculate the resulting permissions set for the path</param>
/// <param name="pathIds">Must be ordered deepest to shallowest (right to left)</param>
/// <param name="fallbackToDefaultPermissions">
/// Flag indicating if we want to include the default group permissions for each result if there are not explicit permissions set
/// </param>
/// <returns></returns>
internal static EntityPermission GetPermissionsForPathForGroup(
IEnumerable<EntityPermission> pathPermissions,
int[] pathIds,
bool fallbackToDefaultPermissions = false)
@@ -1051,24 +1069,8 @@ namespace Umbraco.Core.Services
return null;
return permissionsByEntityId[pathIds[0]];
}
/// <summary>
/// Convert a path to node ids in the order from right to left (deepest to shallowest)
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private int[] GetIdsFromPath(string path)
{
var nodeIds = path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.TryConvertTo<int>())
.Where(x => x.Success)
.Select(x => x.Result)
.Reverse()
.ToArray();
return nodeIds;
}
/// <summary>
/// Checks in a set of permissions associated with a user for those related to a given nodeId
/// </summary>
+16
View File
@@ -41,6 +41,22 @@ namespace Umbraco.Core
ToCSharpEscapeChars[escape[0]] = escape[1];
}
/// <summary>
/// Convert a path to node ids in the order from right to left (deepest to shallowest)
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
internal static int[] GetIdsFromPathReversed(this string path)
{
var nodeIds = path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.TryConvertTo<int>())
.Where(x => x.Success)
.Select(x => x.Result)
.Reverse()
.ToArray();
return nodeIds;
}
/// <summary>
/// Removes new lines and tabs
/// </summary>
+2 -1
View File
@@ -345,6 +345,7 @@
<Compile Include="HashCodeHelper.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
<Compile Include="Models\Membership\ContentPermissionSet.cs" />
<Compile Include="Models\Membership\IReadOnlyUserGroup.cs" />
<Compile Include="Models\Membership\ReadOnlyUserGroup.cs" />
<Compile Include="Models\Membership\UserGroupExtensions.cs" />
@@ -456,7 +457,6 @@
<Compile Include="Models\IServerRegistration.cs" />
<Compile Include="Models\IXsltFile.cs" />
<Compile Include="Models\Mapping\MappingExpressionExtensions.cs" />
<Compile Include="Models\Membership\UserGroupEntityPermission.cs" />
<Compile Include="Models\Membership\IUserGroup.cs" />
<Compile Include="Models\MigrationEntry.cs" />
<Compile Include="Models\PartialViewType.cs" />
@@ -588,6 +588,7 @@
<Compile Include="Persistence\Relators\UserGroupSectionRelator.cs" />
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
<Compile Include="Persistence\Repositories\BaseQueryType.cs" />
<Compile Include="Persistence\Repositories\ContentBlueprintRepository.cs" />
<Compile Include="Persistence\Repositories\EntityContainerRepository.cs" />
<Compile Include="Persistence\Repositories\DomainRepository.cs" />
<Compile Include="Persistence\Repositories\ExternalLoginRepository.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<ContentTypeSort>
{
new ContentTypeSort(new Lazy<int>(() => 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()
+29 -112
View File
@@ -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<ContentTypeSort>
{
new ContentTypeSort(new Lazy<int>(() => 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<ContentTypeSort>
{
new ContentTypeSort(new Lazy<int>(() => 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]);
}
}
+129 -1
View File
@@ -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<int, string[]>
{
{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<EntityPermission>
{
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<EntityPermission>
{
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<EntityPermission>
{
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()
{
@@ -50,7 +50,8 @@ namespace Umbraco.Tests.Web.Controllers
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>();
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<IUserService>();
var permissions = new List<EntityPermission>();
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<IUserService>();
var permissions = new List<EntityPermission>
{
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<IUserService>();
var permissions = new List<EntityPermission>
{
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<IUserService>();
var permissions = new List<EntityPermission>
{
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<IUserService>();
var permissions = new List<EntityPermission>
{
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<IUserService>();
var permissions = new List<EntityPermission>
{
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<IUserService>();
var permissions = new List<EntityPermission>
{
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
@@ -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<EntityPermission>
{
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;
@@ -599,10 +599,13 @@ namespace Umbraco.Web.Cache
#region User/permissions event handlers
static void CacheRefresherEventHandler_AssignedPermissions(PermissionRepository<IContent> sender, SaveEventArgs<UserGroupEntityPermission> e)
static void CacheRefresherEventHandler_AssignedPermissions(PermissionRepository<IContent> sender, SaveEventArgs<EntityPermission> 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)
+8 -4
View File
@@ -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;
}
+1 -1
View File
@@ -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());
}
/// <summary>