Merge pull request #2046 from umbraco/temp-U4-10075

U4-10075 Inherited permissions for content nodes
This commit is contained in:
Shannon Deminick
2017-07-18 11:56:08 +10:00
committed by GitHub
57 changed files with 1427 additions and 1027 deletions
+3 -1
View File
@@ -55,7 +55,9 @@ namespace Umbraco.Core.Cache
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserCacheKey = "UmbracoUser";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserGroupPermissionsCacheKey = "UmbracoUserGroupPermissions";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
+1 -11
View File
@@ -87,7 +87,6 @@ namespace Umbraco.Core.Models
public readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo<Content, DateTime?>(x => x.ExpireDate);
public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.WriterId);
public readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.NodeName);
public readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo<Content, bool>(x => x.PermissionsChanged);
}
/// <summary>
@@ -196,16 +195,7 @@ namespace Umbraco.Core.Models
get { return _nodeName; }
set { SetPropertyValueAndDetectChanges(value, ref _nodeName, Ps.Value.NodeNameSelector); }
}
/// <summary>
/// Used internally to track if permissions have been changed during the saving process for this entity
/// </summary>
[IgnoreDataMember]
internal bool PermissionsChanged
{
get { return _permissionsChanged; }
set { SetPropertyValueAndDetectChanges(value, ref _permissionsChanged, Ps.Value.PermissionsChangedSelector); }
}
/// <summary>
/// Gets the ContentType used by this content object
@@ -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, EntityPermissionCollection 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
}
}
@@ -1,39 +1,65 @@
using System.Linq;
using System;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an entity permission (defined on the user group and derived to retrieve permissions for a given user)
/// </summary>
public class EntityPermission
public class EntityPermission : IEquatable<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 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
/// </summary>
public string[] AssignedPermissions { get; private set; }
/// <summary>
/// Adds additional permissions to an existing instance of <see cref="EntityPermission"/>
/// ensuring that only ones that aren't already assigned are added
/// True if the permissions assigned to this object are the group's default permissions and not explicitly defined permissions
/// </summary>
/// <param name="additionalPermissions"></param>
public void AddAdditionalPermissions(string[] additionalPermissions)
{
//TODO: Fix the performance of this, we need to use things like HashSet and equality checkers, we are iterating too much
/// <remarks>
/// This will be the case when looking up entity permissions and falling back to the default permissions
/// </remarks>
public bool IsDefaultPermissions { get; private set; }
var newPermissions = AssignedPermissions.ToList();
newPermissions.AddRange(additionalPermissions);
AssignedPermissions = newPermissions
.Distinct()
.ToArray();
public bool Equals(EntityPermission other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return EntityId == other.EntityId && UserGroupId == other.UserGroupId;
}
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((EntityPermission) obj);
}
public override int GetHashCode()
{
unchecked
{
return (EntityId * 397) ^ UserGroupId;
}
}
}
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// A <see cref="HashSet{T}"/> of <see cref="EntityPermission"/>
/// </summary>
public class EntityPermissionCollection : HashSet<EntityPermission>
{
public EntityPermissionCollection()
{
}
public EntityPermissionCollection(IEnumerable<EntityPermission> collection) : base(collection)
{
}
/// <summary>
/// Returns the aggregate permissions in the permission set
/// </summary>
/// <returns></returns>
/// <remarks>
/// This value is only calculated once
/// </remarks>
public IEnumerable<string> GetAllPermissions()
{
return _aggregatePermissions ?? (_aggregatePermissions =
this.SelectMany(x => x.AssignedPermissions).Distinct().ToArray());
}
private string[] _aggregatePermissions;
}
}
@@ -1,60 +1,55 @@
using System.Collections.Generic;
using System;
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
{
private static readonly Lazy<EntityPermissionSet> EmptyInstance = new Lazy<EntityPermissionSet>(() => new EntityPermissionSet(-1, new EntityPermissionCollection()));
/// <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 EmptyInstance.Value;
}
/// <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, EntityPermissionCollection 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 EntityPermissionCollection PermissionsSet { get; private set; }
/// <summary>
/// Returns the aggregate 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 PermissionsSet.GetAllPermissions();
}
}
}
@@ -18,6 +18,14 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
string Alias { get; }
/// <summary>
/// The set of default permissions
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
IEnumerable<string> Permissions { get; set; }
IEnumerable<string> AllowedSections { get; }
}
}
@@ -5,13 +5,15 @@ namespace Umbraco.Core.Models.Membership
{
public class ReadOnlyUserGroup : IReadOnlyUserGroup, IEquatable<ReadOnlyUserGroup>
{
public ReadOnlyUserGroup(int id, string name, string icon, int? startContentId, int? startMediaId, string @alias, IEnumerable<string> allowedSections)
public ReadOnlyUserGroup(int id, string name, string icon, int? startContentId, int? startMediaId, string @alias,
IEnumerable<string> allowedSections, IEnumerable<string> permissions)
{
Name = name;
Icon = icon;
Id = id;
Alias = alias;
AllowedSections = allowedSections;
Permissions = permissions;
//Zero is invalid and will be treated as Null
StartContentId = startContentId == 0 ? null : startContentId;
@@ -24,6 +26,14 @@ namespace Umbraco.Core.Models.Membership
public int? StartContentId { get; private set; }
public int? StartMediaId { get; private set; }
public string Alias { get; private set; }
/// <summary>
/// The set of default permissions
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
public IEnumerable<string> Permissions { get; set; }
public IEnumerable<string> AllowedSections { get; private set; }
public bool Equals(ReadOnlyUserGroup other)
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class UserGroup : Entity, IUserGroup
internal class UserGroup : Entity, IUserGroup, IReadOnlyUserGroup
{
private int? _startContentId;
private int? _startMediaId;
@@ -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; }
}
}
@@ -7,12 +7,17 @@ namespace Umbraco.Core.Models.Membership
{
public static IReadOnlyUserGroup ToReadOnlyGroup(this IUserGroup group)
{
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.AllowedSections);
//this will generally always be the case
var readonlyGroup = group as IReadOnlyUserGroup;
if (readonlyGroup != null) return readonlyGroup;
//otherwise create one
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.AllowedSections, group.Permissions);
}
public static IReadOnlyUserGroup ToReadOnlyGroup(this UserGroupDto group)
{
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.UserGroup2AppDtos.Select(x => x.AppAlias).ToArray());
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.UserGroup2AppDtos.Select(x => x.AppAlias).ToArray(), group.DefaultPermissions.ToCharArray().Select(x => x.ToString()));
}
}
}
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Factories
var userGroup = new UserGroup(dto.UserCount, dto.Alias, dto.Name,
dto.DefaultPermissions.IsNullOrWhiteSpace()
? Enumerable.Empty<string>()
: dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)),
: dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)).ToList(),
dto.Icon);
try
@@ -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.Any())
{
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 EntityPermissionCollection 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);
EntityPermissionCollection 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>
@@ -26,11 +26,19 @@ namespace Umbraco.Core.Persistence.Repositories
void AddOrUpdateGroupWithUsers(IUserGroup userGroup, int[] userIds);
/// <summary>
/// Gets the group permissions for the specified entities
/// Gets explicilty defined permissions for the group for specified entities
/// </summary>
/// <param name="groupId">Id of group</param>
/// <param name="entityIds">Array of entity Ids</param>
IEnumerable<EntityPermission> GetPermissionsForEntities(int groupId, params int[] entityIds);
/// <param name="groupIds"></param>
/// <param name="entityIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
EntityPermissionCollection GetPermissions(int[] groupIds, params int[] entityIds);
/// <summary>
/// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
/// </summary>
/// <param name="groups"></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>
EntityPermissionCollection GetPermissions(IReadOnlyUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds);
/// <summary>
/// Replaces the same permission set for a single group to any number of entities
@@ -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,131 +22,105 @@ 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>
/// Returns permissions for a given group for any number of nodes
/// Returns explicitly defined permissions for a user group for any number of nodes
/// </summary>
/// <param name="groupId"></param>
/// <param name="groupIds">
/// The group ids to lookup permissions for
/// </param>
/// <param name="entityIds"></param>
/// <returns></returns>
public IEnumerable<EntityPermission> GetPermissionsForEntities(int groupId, params int[] entityIds)
{
var entityIdKey = GetEntityIdKey(entityIds);
return _runtimeCache.GetCacheItem<IEnumerable<EntityPermission>>(
string.Format("{0}{1}{2}",
CacheKeys.UserGroupPermissionsCacheKey,
groupId,
entityIdKey),
() =>
{
var whereCriteria = GetPermissionsForEntitiesCriteria(groupId, entityIds);
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>()
.Where(whereCriteria);
var result = _unitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql).ToArray();
// ToArray() to ensure it's all fetched from the db once
return ConvertToPermissionList(result);
},
GetCacheTimeout(),
priority: GetCachePriority());
}
/// <remarks>
/// This method will not support passing in more than 2000 group Ids
/// </remarks>
public EntityPermissionCollection GetPermissionsForEntities(int[] groupIds, params int[] entityIds)
{
var result = new EntityPermissionCollection();
private static string GetEntityIdKey(int[] entityIds)
{
return string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture)));
}
private string GetPermissionsForEntitiesCriteria(int groupId, params int[] entityIds)
{
var whereBuilder = new StringBuilder();
whereBuilder.Append(_sqlSyntax.GetQuotedColumnName("userGroupId"));
whereBuilder.Append("=");
whereBuilder.Append(groupId);
if (entityIds.Any())
foreach (var groupOfGroupIds in groupIds.InGroupsOf(2000))
{
whereBuilder.Append(" AND ");
//copy local
var localIds = groupOfGroupIds.ToArray();
//where nodeId = @nodeId1 OR nodeId = @nodeId2, etc...
whereBuilder.Append("(");
for (var index = 0; index < entityIds.Length; index++)
if (entityIds.Length == 0)
{
var entityId = entityIds[index];
whereBuilder.Append(_sqlSyntax.GetQuotedColumnName("nodeId"));
whereBuilder.Append("=");
whereBuilder.Append(entityId);
if (index < entityIds.Length - 1)
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => localIds.Contains(dto.UserGroupId), SqlSyntax);
var permissions = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
foreach (var permission in ConvertToPermissionList(permissions))
{
whereBuilder.Append(" OR ");
result.Add(permission);
}
}
whereBuilder.Append(")");
}
return whereBuilder.ToString();
}
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)
{
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)
else
{
var perms = permission.Select(x => x.Permission).ToArray();
permissions.Add(new UserGroupEntityPermission(permission.Key, permission.First().NodeId, perms));
}
}
//iterate in groups of 2000 since we don't want to exceed the max SQL param count
foreach (var groupOfEntityIds in entityIds.InGroupsOf(2000))
{
var ids = groupOfEntityIds;
var sql = new Sql();
sql.Select("*")
.From<UserGroup2NodePermissionDto>(SqlSyntax)
.Where<UserGroup2NodePermissionDto>(dto => localIds.Contains(dto.UserGroupId) && ids.Contains(dto.NodeId), SqlSyntax);
var permissions = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
foreach (var permission in ConvertToPermissionList(permissions))
{
result.Add(permission);
}
}
}
}
return result;
}
/// <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 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 EntityPermissionCollection 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).ToArray();
// ToArray() to ensure it's all fetched from the db once
var result = UnitOfWork.Database.Fetch<UserGroup2NodePermissionDto>(sql);
return ConvertToPermissionList(result);
}
@@ -158,7 +135,10 @@ namespace Umbraco.Core.Persistence.Repositories
/// </remarks>
public void ReplacePermissions(int groupId, IEnumerable<char> permissions, params int[] entityIds)
{
var db = _unitOfWork.Database;
if (entityIds.Length == 0)
return;
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)";
@@ -181,10 +161,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
_unitOfWork.Database.BulkInsertRecords(toInsert, _sqlSyntax);
//Raise the event
_unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<UserGroupEntityPermission>(ConvertToPermissionList(toInsert), false));
UnitOfWork.Database.BulkInsertRecords(toInsert, SqlSyntax);
}
@@ -196,7 +173,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
@@ -213,11 +190,8 @@ namespace Umbraco.Core.Persistence.Repositories
UserGroupId = groupId
}).ToArray();
_unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
//Raise the event
_unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<UserGroupEntityPermission>(ConvertToPermissionList(actions), false));
UnitOfWork.Database.BulkInsertRecords(actions, SqlSyntax);
}
/// <summary>
@@ -228,7 +202,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
@@ -245,15 +219,12 @@ namespace Umbraco.Core.Persistence.Repositories
UserGroupId = id
}).ToArray();
_unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
//Raise the event
_unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<UserGroupEntityPermission>(ConvertToPermissionList(actions), false));
UnitOfWork.Database.BulkInsertRecords(actions, SqlSyntax);
}
/// <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>
@@ -262,25 +233,113 @@ 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 });
_unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax);
//Raise the event
_unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs<UserGroupEntityPermission>(ConvertToPermissionList(actions), false));
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);
}
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 EntityPermissionCollection ConvertToPermissionList(IEnumerable<UserGroup2NodePermissionDto> result)
{
var permissions = new EntityPermissionCollection();
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).Distinct().ToArray();
permissions.Add(new EntityPermission(permission.Key, np.Key, perms));
}
}
return permissions;
}
}
}
@@ -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_";
@@ -89,28 +91,69 @@ namespace Umbraco.Core.Persistence.Repositories
_userGroupWithUsersRepository.AddOrUpdate(new UserGroupWithUsers(userGroup, userIds));
}
/// <summary>
/// Gets the group permissions for the specified entities
/// Gets explicilty defined permissions for the group for specified entities
/// </summary>
/// <param name="groupId">Id of group</param>
/// <param name="entityIds">Array of entity Ids</param>
public IEnumerable<EntityPermission> GetPermissionsForEntities(int groupId, params int[] entityIds)
/// <param name="groupIds"></param>
/// <param name="entityIds">Array of entity Ids, if empty will return permissions for the group for all entities</param>
public EntityPermissionCollection GetPermissions(int[] groupIds, params int[] entityIds)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper, SqlSyntax);
return repo.GetPermissionsForEntities(groupId, entityIds);
return _permissionRepository.GetPermissionsForEntities(groupIds, entityIds);
}
/// <summary>
/// Gets explicilt and default permissions (if requested) permissions for the group for specified entities
/// </summary>
/// <param name="groups"></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 EntityPermissionCollection GetPermissions(IReadOnlyUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
if (groups == null) throw new ArgumentNullException("groups");
var groupIds = groups.Select(x => x.Id).ToArray();
var explicitPermissions = GetPermissions(groupIds, nodeIds);
var result = new EntityPermissionCollection(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)
{
//if no node ids are passed in, then we need to determine the node ids for the explicit permissions set
nodeIds = nodeIds.Length == 0
? explicitPermissions.Select(x => x.EntityId).Distinct().ToArray()
: nodeIds;
//if there are still no nodeids we can just exit
if (nodeIds.Length == 0)
return result;
foreach (var group in groups)
{
foreach (var nodeId in nodeIds)
{
//TODO: We could/should change the EntityPermissionsCollection into a KeyedCollection and they key could be
// a struct of the nodeid + groupid so then we don't actually allocate this class just to check if it's not
// going to be included in the result!
var defaultPermission = new EntityPermission(group.Id, nodeId, group.Permissions.ToArray(), isDefaultPermissions: true);
//Since this is a hashset, this will not add anything that already exists by group/node combination
result.Add(defaultPermission);
}
}
}
return result;
}
/// <summary>
/// Replaces the same permission set for a single group to any number of entities
/// </summary>
/// <param name="groupId">Id of group</param>
/// <param name="permissions">Permissions as enumerable list of <see cref="char"/></param>
/// <param name="entityIds">Specify the nodes to replace permissions for. If nothing is specified all permissions are removed.</param>
/// <param name="permissions">Permissions as enumerable list of <see cref="char"/> If nothing is specified all permissions are removed.</param>
/// <param name="entityIds">Specify the nodes to replace permissions for. </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 +164,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,IUserGroup>
+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 EntityPermissionCollection 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);
currentPermissions.RemoveWhere(p => p.IsDefaultPermissions);
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.Count > 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, new EntityPermissionCollection()));
}
/// <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);
EntityPermissionCollection GetPermissionsForEntity(IContent content);
bool SendToPublication(IContent content, int userId = 0);
+20 -45
View File
@@ -83,72 +83,47 @@ namespace Umbraco.Core.Services
/// </summary>
/// <remarks>This is useful when an entire section is removed from config</remarks>
/// <param name="sectionAlias">Alias of the section to remove</param>
void DeleteSectionFromAllUserGroups(string sectionAlias);
void DeleteSectionFromAllUserGroups(string sectionAlias);
/// <summary>
/// Get permissions set for a user and optional node ids
/// Get explicitly assigned permissions for a user and optional node ids
/// </summary>
/// <remarks>If no permissions are found for a particular entity then the user's default permissions will be applied</remarks>
/// <param name="user">User to retrieve permissions for</param>
/// <param name="nodeIds">Specifiying nothing will return all user permissions for all nodes</param>
/// <param name="nodeIds">Specifiying nothing will return all user permissions for all nodes that have explicit permissions defined</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
IEnumerable<EntityPermission> GetPermissions(IUser user, params int[] nodeIds);
/// <remarks>
/// This will return the default permissions for the user's groups for node ids that don't have explicitly defined permissions
/// </remarks>
EntityPermissionCollection GetPermissions(IUser user, params int[] nodeIds);
/// <summary>
/// Get permissions set for a group and optional node Ids
/// Get explicitly assigned permissions for groups and optional node Ids
/// </summary>
/// <param name="groupAlias">Group to retrieve permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// <param name="groups"></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>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
IEnumerable<EntityPermission> GetPermissions(string groupAlias, bool directlyAssignedOnly, params int[] nodeIds);
EntityPermissionCollection GetPermissions(IUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds);
/// <summary>
/// Get permissions set for a group and optional node Ids
/// </summary>
/// <param name="group">Group to retrieve permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// </param>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
IEnumerable<EntityPermission> GetPermissions(IUserGroup group, bool directlyAssignedOnly, params int[] nodeIds);
/// <summary>
/// Gets the permissions for the provided user and path
/// Gets the implicit/inherited permissions for the user for the given path
/// </summary>
/// <param name="user">User to check permissions for</param>
/// <param name="path">Path to check permissions for</param>
/// <returns>String indicating permissions for provided user and path</returns>
string GetPermissionsForPath(IUser user, string path);
EntityPermissionSet GetPermissionsForPath(IUser user, string path);
/// <summary>
/// Gets the permissions for the provided group and path
/// Gets the permissions for the provided groups and path
/// </summary>
/// <param name="groupAlias">Group alias to check permissions for</param>
/// <param name="groups"></param>
/// <param name="path">Path to check permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// <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>String indicating permissions for provided user and path</returns>
string GetPermissionsForPath(string groupAlias, string path, bool directlyAssignedOnly = true);
/// <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="directlyAssignedOnly">
/// 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
/// </param>
/// <returns>String indicating permissions for provided user and path</returns>
string GetPermissionsForPath(IUserGroup group, string path, bool directlyAssignedOnly = true);
EntityPermissionSet GetPermissionsForPath(IUserGroup[] groups, string path, bool fallbackToDefaultPermissions = false);
/// <summary>
/// Replaces the same permission set for a single group to any number of entities
+214 -160
View File
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
@@ -13,7 +15,6 @@ using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Security;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Services
{
@@ -121,7 +122,7 @@ namespace Umbraco.Core.Services
Language = GlobalSettings.DefaultUILanguage,
Name = username,
RawPasswordValue = passwordValue,
Username = username,
Username = username,
IsLockedOut = false,
IsApproved = isApproved
};
@@ -208,11 +209,11 @@ namespace Umbraco.Core.Services
public void Delete(IUser membershipUser)
{
//disable
membershipUser.IsApproved = false;
membershipUser.IsApproved = false;
Save(membershipUser);
}
}
/// <summary>
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
/// </summary>
@@ -616,12 +617,12 @@ namespace Umbraco.Core.Services
{
return repository.GetAllNotInGroup(groupId);
}
}
}
#endregion
#region Implementation of IUserService
/// <summary>
/// Gets an IProfile by User Id.
/// </summary>
@@ -680,15 +681,26 @@ namespace Umbraco.Core.Services
/// </summary>
/// <remarks>If no 'entityIds' are specified all permissions will be removed for the specified group.</remarks>
/// <param name="groupId">Id of the group</param>
/// <param name="permissions">Permissions as enumerable list of <see cref="char"/></param>
/// <param name="entityIds">Specify the nodes to replace permissions for. If nothing is specified all permissions are removed.</param>
/// <param name="permissions">Permissions as enumerable list of <see cref="char"/> If nothing is specified all permissions are removed.</param>
/// <param name="entityIds">Specify the nodes to replace permissions for. </param>
public void ReplaceUserGroupPermissions(int groupId, IEnumerable<char> permissions, params int[] entityIds)
{
if (entityIds.Length == 0)
return;
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
repository.ReplaceGroupPermissions(groupId, permissions, entityIds);
uow.Commit();
uow.Events.Dispatch(UserGroupPermissionsAssigned, this, new SaveEventArgs<EntityPermission>(
entityIds.Select(
x => new EntityPermission(
groupId,
x,
permissions.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray()))
.ToArray(), false));
}
}
@@ -700,14 +712,25 @@ namespace Umbraco.Core.Services
/// <param name="entityIds">Specify the nodes to replace permissions for</param>
public void AssignUserGroupPermission(int groupId, char permission, params int[] entityIds)
{
if (entityIds.Length == 0)
return;
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
repository.AssignGroupPermission(groupId, permission, entityIds);
uow.Commit();
uow.Events.Dispatch(UserGroupPermissionsAssigned, this, new SaveEventArgs<EntityPermission>(
entityIds.Select(
x => new EntityPermission(
groupId,
x,
new[] {permission.ToString(CultureInfo.InvariantCulture)}))
.ToArray(), false));
}
}
}
/// <summary>
/// Gets all UserGroups or those specified as parameters
/// </summary>
@@ -720,8 +743,8 @@ namespace Umbraco.Core.Services
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
return repository.GetAll(ids).OrderBy(x => x.Name);
}
}
}
public IEnumerable<IUserGroup> GetUserGroupsByAlias(params string[] aliases)
{
if (aliases.Length == 0) return Enumerable.Empty<IUserGroup>();
@@ -788,8 +811,8 @@ namespace Umbraco.Core.Services
}
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
repository.AddOrUpdateGroupWithUsers(userGroup, userIds);
repository.AddOrUpdateGroupWithUsers(userGroup, userIds);
uow.Commit();
if (raiseEvents)
@@ -838,199 +861,226 @@ namespace Umbraco.Core.Services
uow.Commit();
//TODO: Events?
}
}
}
/// <summary>
/// Get permissions set for a user and node Id
/// Get explicitly assigned permissions for a user and optional node ids
/// </summary>
/// <param name="user">User to retrieve permissions for</param>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
public IEnumerable<EntityPermission> GetPermissions(IUser user, params int[] nodeIds)
public EntityPermissionCollection GetPermissions(IUser user, params int[] nodeIds)
{
var result = new List<EntityPermission>();
foreach (var group in user.Groups)
{
//TODO: This may perform horribly :/
foreach (var permission in GetPermissions(group.Alias, false, nodeIds))
{
AddOrAmendPermissionList(result, permission);
}
}
return result;
}
/// <summary>
/// Get permissions set for a group and node Id
/// </summary>
/// <param name="groupAlias">Group to retrieve permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// </param>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
public IEnumerable<EntityPermission> GetPermissions(string groupAlias, bool directlyAssignedOnly, params int[] nodeIds)
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
var group = repository.Get(groupAlias);
return GetPermissionsInternal(repository, group, directlyAssignedOnly, nodeIds);
}
}
return repository.GetPermissions(user.Groups.ToArray(), true, nodeIds);
}
}
/// <summary>
/// Get permissions set for a group and optional node Ids
/// Get explicitly assigned permissions for a group and optional node Ids
/// </summary>
/// <param name="group">Group to retrieve permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// <param name="groups">Groups to retrieve permissions for</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>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
public IEnumerable<EntityPermission> GetPermissions(IUserGroup group, bool directlyAssignedOnly, params int[] nodeIds)
private IEnumerable<EntityPermission> GetPermissions(IReadOnlyUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
if (group == null) throw new ArgumentNullException("group");
if (groups == null) throw new ArgumentNullException("group");
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
return GetPermissionsInternal(repository, group, directlyAssignedOnly, nodeIds);
return repository.GetPermissions(groups, fallbackToDefaultPermissions, nodeIds);
}
}
private IEnumerable<EntityPermission> GetPermissionsInternal(IUserGroupRepository repository, IUserGroup group, bool directlyAssignedOnly, params int[] nodeIds)
{
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 (directlyAssignedOnly == false)
{
var missingIds = nodeIds.Except(result.Select(x => x.EntityId)).ToList();
if (missingIds.Any())
{
result.AddRange(missingIds
.Select(i => new EntityPermission(i, group.Permissions.ToArray())));
}
}
return result;
}
/// <summary>
/// For an existing list of <see cref="EntityPermission"/>, takes a new <see cref="EntityPermission"/> and aggregates it.
/// If a permission for the entity associated with the new permission already exists, it's updated with those permissions to create a distinct, most permissive set.
/// If it doesn't, it's added to the list.
/// Get explicitly assigned permissions for a group and optional node Ids
/// </summary>
/// <param name="permissions">List of already found permissions</param>
/// <param name="groupPermission">New permission to aggregate</param>
private void AddOrAmendPermissionList(IList<EntityPermission> permissions, EntityPermission groupPermission)
/// <param name="groups"></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>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
public EntityPermissionCollection GetPermissions(IUserGroup[] groups, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
//TODO: Fix the performance of this, we need to use things like HashSet and equality checkers, we are iterating too much
var existingPermission = permissions.FirstOrDefault(x => x.EntityId == groupPermission.EntityId);
if (existingPermission != null)
if (groups == null) throw new ArgumentNullException("groups");
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
existingPermission.AddAdditionalPermissions(groupPermission.AssignedPermissions);
}
else
{
permissions.Add(groupPermission);
var repository = RepositoryFactory.CreateUserGroupRepository(uow);
return repository.GetPermissions(groups.Select(x => x.ToReadOnlyGroup()).ToArray(), fallbackToDefaultPermissions, nodeIds);
}
}
/// <summary>
/// Gets the permissions for the provided user and path
/// Gets the implicit/inherited permissions for the user for the given path
/// </summary>
/// <param name="user">User to check permissions for</param>
/// <param name="path">Path to check permissions for</param>
/// <returns>String indicating permissions for provided user and path</returns>
public string GetPermissionsForPath(IUser user, string path)
{
var assignedPermissions = GetPermissionsForGroupsAndPath(user.Groups.Select(x => x.Alias), path);
return GetAggregatePermissions(assignedPermissions);
}
/// <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="path">Path to check permissions for</param>
/// <returns>List of strings indicating permissions for each groups</returns>
private IEnumerable<string> GetPermissionsForGroupsAndPath(IEnumerable<string> groups, string path)
public EntityPermissionSet GetPermissionsForPath(IUser user, string path)
{
return groups
.Select(g => GetPermissionsForPath(g, path, directlyAssignedOnly: false))
.ToList();
}
var nodeIds = path.GetIdsFromPathReversed();
/// <summary>
/// Aggregates a set of permissions strings to return a unique permissions string containing the most permissive set
/// </summary>
/// <param name="assignedPermissions">List of permission strings</param>
/// <returns>Single permission string</returns>
private static string GetAggregatePermissions(IEnumerable<string> assignedPermissions)
{
return string.Join(string.Empty, assignedPermissions
.SelectMany(s => s.ToCharArray())
.Distinct());
if (nodeIds.Length == 0)
return EntityPermissionSet.Empty();
//collect all permissions structures for all nodes for all groups belonging to the user
var groupPermissions = GetPermissionsForPath(user.Groups.ToArray(), nodeIds, fallbackToDefaultPermissions: true).ToArray();
return CalculatePermissionsForPathForUser(groupPermissions, nodeIds);
}
/// <summary>
/// Gets the permissions for the provided group and path
/// </summary>
/// <param name="groupAlias">User to check permissions for</param>
/// <param name="groups"></param>
/// <param name="path">Path to check permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// <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>String indicating permissions for provided user and path</returns>
public string GetPermissionsForPath(string groupAlias, string path, bool directlyAssignedOnly = true)
public EntityPermissionSet GetPermissionsForPath(IUserGroup[] groups, string path, bool fallbackToDefaultPermissions = false)
{
var nodeId = GetNodeIdFromPath(path);
var permission = GetPermissions(groupAlias, directlyAssignedOnly, nodeId)
.FirstOrDefault();
return permission != null
? string.Join(string.Empty, permission.AssignedPermissions)
: string.Empty;
var nodeIds = path.GetIdsFromPathReversed();
if (nodeIds.Length == 0)
return EntityPermissionSet.Empty();
//collect all permissions structures for all nodes for all groups
var groupPermissions = GetPermissionsForPath(groups.Select(x => x.ToReadOnlyGroup()).ToArray(), nodeIds, fallbackToDefaultPermissions: true).ToArray();
return CalculatePermissionsForPathForUser(groupPermissions, nodeIds);
}
private EntityPermissionCollection GetPermissionsForPath(IReadOnlyUserGroup[] groups, int[] pathIds, bool fallbackToDefaultPermissions = false)
{
if (pathIds.Length == 0)
return new EntityPermissionCollection(Enumerable.Empty<EntityPermission>());
//get permissions for all nodes in the path by group
var permissions = GetPermissions(groups, fallbackToDefaultPermissions, pathIds)
.GroupBy(x => x.UserGroupId);
return new EntityPermissionCollection(
permissions.Select(x => GetPermissionsForPathForGroup(x, pathIds, fallbackToDefaultPermissions)));
}
/// <summary>
/// Gets the permissions for the provided group and path
/// This performs the calculations for inherited nodes based on this http://issues.umbraco.org/issue/U4-10075#comment=67-40085
/// </summary>
/// <param name="group">Group to check permissions for</param>
/// <param name="path">Path to check permissions for</param>
/// <param name="directlyAssignedOnly">
/// 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
/// <param name="groupPermissions"></param>
/// <param name="pathIds"></param>
/// <returns></returns>
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 EntityPermissionCollection();
//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, the collection is a hashset anyways
//so only supports adding one element per groupid/contentid
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
/// based on a single group
/// </param>
/// <returns>String indicating permissions for provided user and path</returns>
public string GetPermissionsForPath(IUserGroup group, string path, bool directlyAssignedOnly = true)
/// <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)
{
var nodeId = GetNodeIdFromPath(path);
var permission = GetPermissions(group, directlyAssignedOnly, nodeId)
.FirstOrDefault();
return permission != null
? string.Join(string.Empty, permission.AssignedPermissions)
: string.Empty;
}
//get permissions for all nodes in the path
var permissionsByEntityId = pathPermissions.ToDictionary(x => x.EntityId, x => x);
//then the permissions assigned to the path will be the 'deepest' node found that has permissions
foreach (var id in pathIds)
{
EntityPermission permission;
if (permissionsByEntityId.TryGetValue(id, out permission))
{
//don't return the default permissions if that is the one assigned here (we'll do that below if nothing was found)
if (permission.IsDefaultPermissions == false)
return permission;
}
}
/// <summary>
/// Parses a path to find the lowermost node id
/// </summary>
/// <param name="path">Path as string</param>
/// <returns>Node id</returns>
private static int GetNodeIdFromPath(string path)
{
return path.Contains(",")
? int.Parse(path.Substring(path.LastIndexOf(",", StringComparison.Ordinal) + 1))
: int.Parse(path);
}
//if we've made it here it means that no implicit/inherited permissions were found so we return the defaults if that is specified
if (fallbackToDefaultPermissions == false)
return null;
return permissionsByEntityId[pathIds[0]];
}
/// <summary>
/// Checks in a set of permissions associated with a user for those related to a given nodeId
/// </summary>
@@ -1109,6 +1159,10 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserGroup>> DeletedUserGroup;
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserGroup>> DeletedUserGroup;
//TODO: still don't know if we need this yet unless we start caching permissions, but that also means we'll need another
// event on the ContentService since there's a method there to modify node permissions too, or we can proxy events if needed.
internal static event TypedEventHandler<IUserService, SaveEventArgs<EntityPermission>> UserGroupPermissionsAssigned;
}
}
@@ -4,8 +4,37 @@ using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Services
{
internal static class UserServiceExtensions
public static class UserServiceExtensions
{
/// <summary>
/// Get explicitly assigned permissions for a group and optional node Ids
/// </summary>
/// <param name="service"></param>
/// <param name="group"></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>
/// <param name="nodeIds">Specifiying nothing will return all permissions for all nodes</param>
/// <returns>An enumerable list of <see cref="EntityPermission"/></returns>
public static EntityPermissionCollection GetPermissions(this IUserService service, IUserGroup group, bool fallbackToDefaultPermissions, params int[] nodeIds)
{
return service.GetPermissions(new[] {group}, fallbackToDefaultPermissions, nodeIds);
}
/// <summary>
/// Gets the permissions for the provided group and path
/// </summary>
/// <param name="service"></param>
/// <param name="group"></param>
/// <param name="path">Path to check permissions for</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>
public static EntityPermissionSet GetPermissionsForPath(this IUserService service, IUserGroup group, string path, bool fallbackToDefaultPermissions = false)
{
return service.GetPermissionsForPath(new[] { group }, path, fallbackToDefaultPermissions);
}
/// <summary>
/// Remove all permissions for this user group for all nodes specified
/// </summary>
@@ -36,7 +65,7 @@ namespace Umbraco.Core.Services
/// To maintain compatibility we have to check the login name if the provider key lookup fails but otherwise
/// we'll store the provider user key in the login column.
/// </remarks>
public static IUser CreateUserMappingForCustomProvider(this IUserService userService, MembershipUser member)
internal static IUser CreateUserMappingForCustomProvider(this IUserService userService, MembershipUser member)
{
if (member == null) throw new ArgumentNullException("member");
+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>
+3 -1
View File
@@ -346,6 +346,8 @@
<Compile Include="HashCodeHelper.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
<Compile Include="Models\Membership\ContentPermissionSet.cs" />
<Compile Include="Models\Membership\EntityPermissionCollection.cs" />
<Compile Include="Models\Membership\IReadOnlyUserGroup.cs" />
<Compile Include="Models\Membership\ReadOnlyUserGroup.cs" />
<Compile Include="Models\Membership\UserGroupExtensions.cs" />
@@ -457,7 +459,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" />
@@ -589,6 +590,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" />
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models.Membership;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Mapping;
namespace Umbraco.Tests.Models.Mapping
{
[TestFixture]
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
public class UserModelMapperTests : BaseDatabaseFactoryTest
{
[Test]
public void Map_UserGroupSave_To_IUserGroup()
{
var userModelMapper = new UserModelMapper();
Mapper.Initialize(configuration => userModelMapper.ConfigureMappings(configuration, ApplicationContext.Current));
var userService = ApplicationContext.Services.UserService;
IUserGroup userGroup = new UserGroup(0, "alias", "name", new List<string> { "c" }, "icon");
userService.Save(userGroup);
// userGroup.permissions is System.Collections.Generic.List`1[System.String]
userGroup = userService.GetUserGroupById(userGroup.Id);
// userGroup.permissions is System.Linq.Enumerable+WhereSelectArrayIterator`2[System.Char, System.String]
// fixed: now System.Collections.Generic.List`1[System.String]
const string json = "{\"id\":@@@ID@@@,\"alias\":\"perm1\",\"name\":\"Perm1\",\"icon\":\"icon-users\",\"sections\":[\"content\"],\"users\":[],\"defaultPermissions\":[\"F\",\"C\",\"A\"],\"assignedPermissions\":{},\"startContentId\":-1,\"startMediaId\":-1,\"action\":\"save\",\"parentId\":-1}";
var userGroupSave = JsonConvert.DeserializeObject<UserGroupSave>(json.Replace("@@@ID@@@", userGroup.Id.ToString()));
// failed, AutoMapper complained, "Unable to cast object of type 'WhereSelectArrayIterator`2[System.Char,System.String]' to type 'System.Collections.IList'".
// fixmed: added ToList() in UserGroupFactory
Mapper.Map(userGroupSave, userGroup);
}
}
}
@@ -135,11 +135,11 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
repository.AddOrUpdate(content1);
unitOfWork.Commit();
}
var versionDtos = new List<ContentVersionDto>();
@@ -167,7 +167,7 @@ namespace Umbraco.Tests.Persistence.Repositories
VersionId = version,
WriterUserId = 0,
UpdateDate = versionDate,
TemplateId = content1.Template == null || content1.Template.Id <= 0 ? null : (int?) content1.Template.Id
TemplateId = content1.Template == null || content1.Template.Id <= 0 ? null : (int?)content1.Template.Id
});
}
@@ -188,7 +188,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual(contentItem.Version, versionDtos.Single(x => x.Id == versionDtos.Max(y => y.Id)).VersionId);
var allVersions = repository.GetAllVersions(content[0].Id);
var allKnownVersions = versionDtos.Select(x => x.VersionId).Union(new[]{ content1.Version }).ToArray();
var allKnownVersions = versionDtos.Select(x => x.VersionId).Union(new[] { content1.Version }).ToArray();
Assert.IsTrue(allKnownVersions.ContainsAll(allVersions.Select(x => x.Version)));
Assert.IsTrue(allVersions.Select(x => x.Version).ContainsAll(allKnownVersions));
}
@@ -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()
@@ -1458,6 +1458,98 @@ namespace Umbraco.Tests.Services
Assert.That(contents.Any(), Is.False);
}
[Test]
public void Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explicit_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);
var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage);
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);
//get the permissions and verify
var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, copy.Path, fallbackToDefaultPermissions: true);
var allPermissions = permissions.GetAllPermissions().ToArray();
Assert.AreEqual(1, allPermissions.Length);
Assert.AreEqual("A", allPermissions[0]);
}
[Test]
public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants()
{
// 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[] { userGroup.Id });
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);
//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)
{
var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true);
var allPermissions = permissions.GetAllPermissions().ToArray();
Assert.AreEqual(1, allPermissions.Length);
Assert.AreEqual("A", allPermissions[0]);
}
//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 });
//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)
{
var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true);
var allPermissions = permissions.GetAllPermissions().ToArray();
Assert.AreEqual(1, allPermissions.Length);
Assert.AreEqual("B", allPermissions[0]);
}
}
[Test]
public void Can_Empty_RecycleBin_With_Content_That_Has_All_Related_Data()
{
+315 -42
View File
@@ -1,19 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using NUnit.Framework;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers.Entities;
using umbraco.BusinessLogic.Actions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
using umbraco.BusinessLogic.Actions;
using Umbraco.Core;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Services;
namespace Umbraco.Tests.Services
{
@@ -37,7 +35,7 @@ namespace Umbraco.Tests.Services
}
[Test]
public void UserService_Get_User_Permissions_For_Unassigned_Permission_Nodes()
public void Get_User_Permissions_For_Unassigned_Permission_Nodes()
{
// Arrange
var userService = ServiceContext.UserService;
@@ -55,17 +53,18 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.Save(content);
// Act
var permissions = userService.GetPermissions(user, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id);
var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id)
.ToArray();
//assert
Assert.AreEqual(3, permissions.Count());
Assert.AreEqual(17, permissions.ElementAt(0).AssignedPermissions.Count());
Assert.AreEqual(17, permissions.ElementAt(1).AssignedPermissions.Count());
Assert.AreEqual(17, permissions.ElementAt(2).AssignedPermissions.Count());
Assert.AreEqual(3, permissions.Length);
Assert.AreEqual(17, permissions[0].AssignedPermissions.Length);
Assert.AreEqual(17, permissions[1].AssignedPermissions.Length);
Assert.AreEqual(17, permissions[2].AssignedPermissions.Length);
}
[Test]
public void UserService_Get_User_Permissions_For_Assigned_Permission_Nodes()
public void Get_User_Permissions_For_Assigned_Permission_Nodes()
{
// Arrange
var userService = ServiceContext.UserService;
@@ -81,25 +80,25 @@ namespace Umbraco.Tests.Services
MockedContent.CreateSimpleContent(contentType)
};
ServiceContext.ContentService.Save(content);
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionMove.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(2), ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[2], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
// Act
var permissions = userService.GetPermissions(user, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id);
var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray();
//assert
Assert.AreEqual(3, permissions.Count());
Assert.AreEqual(3, permissions.ElementAt(0).AssignedPermissions.Length);
Assert.AreEqual(2, permissions.ElementAt(1).AssignedPermissions.Length);
Assert.AreEqual(1, permissions.ElementAt(2).AssignedPermissions.Length);
Assert.AreEqual(3, permissions.Length);
Assert.AreEqual(3, permissions[0].AssignedPermissions.Length);
Assert.AreEqual(2, permissions[1].AssignedPermissions.Length);
Assert.AreEqual(1, permissions[2].AssignedPermissions.Length);
}
[Test]
public void UserService_Get_UserGroup_Assigned_Permissions()
public void Get_UserGroup_Assigned_Permissions()
{
// Arrange
var userService = ServiceContext.UserService;
@@ -122,17 +121,17 @@ namespace Umbraco.Tests.Services
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(2), ActionBrowse.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, false, content[0].Id, content[1].Id, content[2].Id).ToArray();
//assert
Assert.AreEqual(3, permissions.Count());
Assert.AreEqual(3, permissions.ElementAt(0).AssignedPermissions.Length);
Assert.AreEqual(2, permissions.ElementAt(1).AssignedPermissions.Length);
Assert.AreEqual(1, permissions.ElementAt(2).AssignedPermissions.Length);
Assert.AreEqual(3, permissions.Length);
Assert.AreEqual(3, permissions[0].AssignedPermissions.Length);
Assert.AreEqual(2, permissions[1].AssignedPermissions.Length);
Assert.AreEqual(1, permissions[2].AssignedPermissions.Length);
}
[Test]
public void UserService_Get_UserGroup_Assigned_And_Default_Permissions()
public void Get_UserGroup_Assigned_And_Default_Permissions()
{
// Arrange
var userService = ServiceContext.UserService;
@@ -147,20 +146,294 @@ namespace Umbraco.Tests.Services
MockedContent.CreateSimpleContent(contentType)
};
ServiceContext.ContentService.Save(content);
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionMove.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
// Act
var permissions = userService.GetPermissions(userGroup, false, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id);
var permissions = userService.GetPermissions(userGroup, true, content[0].Id, content[1].Id, content[2].Id)
.ToArray();
//assert
Assert.AreEqual(3, permissions.Count());
Assert.AreEqual(3, permissions.ElementAt(0).AssignedPermissions.Length);
Assert.AreEqual(2, permissions.ElementAt(1).AssignedPermissions.Length);
Assert.AreEqual(17, permissions.ElementAt(2).AssignedPermissions.Length);
Assert.AreEqual(3, permissions.Length);
Assert.AreEqual(3, permissions[0].AssignedPermissions.Length);
Assert.AreEqual(2, permissions[1].AssignedPermissions.Length);
Assert.AreEqual(17,permissions[2].AssignedPermissions.Length);
}
[Test]
public void Get_All_User_Permissions_For_All_Nodes_With_Explicit_Permission()
{
// Arrange
var userService = ServiceContext.UserService;
var userGroup1 = CreateTestUserGroup();
var userGroup2 = CreateTestUserGroup("test2", "Test 2");
var userGroup3 = CreateTestUserGroup("test3", "Test 3");
var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io");
var defaultPermissionCount = userGroup3.Permissions.Count();
user.AddGroup(userGroup1);
user.AddGroup(userGroup2);
user.AddGroup(userGroup3);
userService.Save(user);
var contentType = MockedContentTypes.CreateSimpleContentType();
ServiceContext.ContentTypeService.Save(contentType);
var content = new[]
{
MockedContent.CreateSimpleContent(contentType),
MockedContent.CreateSimpleContent(contentType),
MockedContent.CreateSimpleContent(contentType)
};
ServiceContext.ContentService.Save(content);
//assign permissions - we aren't assigning anything explicit for group3 and nothing explicit for content[2] /w group2
ServiceContext.ContentService.AssignContentPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup1.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup1.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup2.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup1.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup2.Id });
ServiceContext.ContentService.AssignContentPermission(content[2], ActionDelete.Instance.Letter, new int[] { userGroup1.Id });
// Act
//we don't pass in any nodes so it will return all of them
var result = userService.GetPermissions(user).ToArray();
var permissions = result
.GroupBy(x => x.EntityId)
.ToDictionary(x => x.Key, x => x.GroupBy(a => a.UserGroupId).ToDictionary(a => a.Key, a => a.ToArray()));
//assert
//there will be 3 since that is how many content items there are
Assert.AreEqual(3, permissions.Count);
//test permissions contains content[0]
Assert.IsTrue(permissions.ContainsKey(content[0].Id));
//test that this permissions set contains permissions for all groups
Assert.IsTrue(permissions[content[0].Id].ContainsKey(userGroup1.Id));
Assert.IsTrue(permissions[content[0].Id].ContainsKey(userGroup2.Id));
Assert.IsTrue(permissions[content[0].Id].ContainsKey(userGroup3.Id));
//test that the correct number of permissions are returned for each group
Assert.AreEqual(2, permissions[content[0].Id][userGroup1.Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.AreEqual(1, permissions[content[0].Id][userGroup2.Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.AreEqual(defaultPermissionCount, permissions[content[0].Id][userGroup3.Id].SelectMany(x => x.AssignedPermissions).Count());
//test permissions contains content[1]
Assert.IsTrue(permissions.ContainsKey(content[1].Id));
//test that this permissions set contains permissions for all groups
Assert.IsTrue(permissions[content[1].Id].ContainsKey(userGroup1.Id));
Assert.IsTrue(permissions[content[1].Id].ContainsKey(userGroup2.Id));
Assert.IsTrue(permissions[content[1].Id].ContainsKey(userGroup3.Id));
//test that the correct number of permissions are returned for each group
Assert.AreEqual(1, permissions[content[1].Id][userGroup1.Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.AreEqual(1, permissions[content[1].Id][userGroup2.Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.AreEqual(defaultPermissionCount, permissions[content[1].Id][userGroup3.Id].SelectMany(x => x.AssignedPermissions).Count());
//test permissions contains content[2]
Assert.IsTrue(permissions.ContainsKey(content[2].Id));
//test that this permissions set contains permissions for all groups
Assert.IsTrue(permissions[content[2].Id].ContainsKey(userGroup1.Id));
Assert.IsTrue(permissions[content[2].Id].ContainsKey(userGroup2.Id));
Assert.IsTrue(permissions[content[2].Id].ContainsKey(userGroup3.Id));
//test that the correct number of permissions are returned for each group
Assert.AreEqual(1, permissions[content[2].Id][userGroup1.Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.AreEqual(defaultPermissionCount, permissions[content[2].Id][userGroup2.Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.AreEqual(defaultPermissionCount, permissions[content[2].Id][userGroup3.Id].SelectMany(x => x.AssignedPermissions).Count());
}
[Test]
public void Get_All_User_Group_Permissions_For_All_Nodes()
{
// Arrange
var userService = ServiceContext.UserService;
var userGroup = CreateTestUserGroup();
var contentType = MockedContentTypes.CreateSimpleContentType();
ServiceContext.ContentTypeService.Save(contentType);
var content = new[]
{
MockedContent.CreateSimpleContent(contentType),
MockedContent.CreateSimpleContent(contentType),
MockedContent.CreateSimpleContent(contentType)
};
ServiceContext.ContentService.Save(content);
ServiceContext.ContentService.AssignContentPermission(content[0], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[0], ActionMove.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[1], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(content[2], ActionDelete.Instance.Letter, new int[] { userGroup.Id });
// Act
//we don't pass in any nodes so it will return all of them
var permissions = userService.GetPermissions(userGroup, true)
.GroupBy(x => x.EntityId)
.ToDictionary(x => x.Key, x => x);
//assert
Assert.AreEqual(3, permissions.Count);
Assert.IsTrue(permissions.ContainsKey(content[0].Id));
Assert.AreEqual(3, permissions[content[0].Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.IsTrue(permissions.ContainsKey(content[1].Id));
Assert.AreEqual(2, permissions[content[1].Id].SelectMany(x => x.AssignedPermissions).Count());
Assert.IsTrue(permissions.ContainsKey(content[2].Id));
Assert.AreEqual(1, permissions[content[2].Id].SelectMany(x => x.AssignedPermissions).Count());
}
[Test]
public void Calculate_Permissions_For_User_For_Path()
{
//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()
{
// Arrange
var userService = ServiceContext.UserService;
var userGroup = CreateTestUserGroup();
var contentType = MockedContentTypes.CreateSimpleContentType();
ServiceContext.ContentTypeService.Save(contentType);
var parent = MockedContent.CreateSimpleContent(contentType);
ServiceContext.ContentService.Save(parent);
var child1 = MockedContent.CreateSimpleContent(contentType, "child1", parent);
ServiceContext.ContentService.Save(child1);
var child2 = MockedContent.CreateSimpleContent(contentType, "child2", child1);
ServiceContext.ContentService.Save(child2);
ServiceContext.ContentService.AssignContentPermission(parent, ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(parent, ActionDelete.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(parent, ActionMove.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(parent, ActionBrowse.Instance.Letter, new int[] { userGroup.Id });
ServiceContext.ContentService.AssignContentPermission(parent, ActionDelete.Instance.Letter, new int[] { userGroup.Id });
// Act
var permissions = userService.GetPermissionsForPath(userGroup, child2.Path);
//assert
var allPermissions = permissions.GetAllPermissions().ToArray();
Assert.AreEqual(3, allPermissions.Length);
}
[Test]
@@ -702,12 +975,12 @@ namespace Umbraco.Tests.Services
return user;
}
private UserGroup CreateTestUserGroup()
private UserGroup CreateTestUserGroup(string alias = "testGroup", string name = "Test Group")
{
var userGroup = new UserGroup
{
Alias = "testGroup",
Name = "Test Group",
Alias = alias,
Name = name,
Permissions = "ABCDEFGHIJ1234567".ToCharArray().Select(x => x.ToString())
};
+1
View File
@@ -186,6 +186,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Cache\CacheRefresherEventHandlerTests.cs" />
<Compile Include="Models\Mapping\UserModelMapperTests.cs" />
<Compile Include="TestHelpers\ControllerTesting\AuthenticateEverythingExtensions.cs" />
<Compile Include="TestHelpers\ControllerTesting\AuthenticateEverythingMiddleware.cs" />
<Compile Include="TestHelpers\ControllerTesting\SpecificAssemblyResolver.cs" />
@@ -49,8 +49,9 @@ namespace Umbraco.Tests.Web.Controllers
contentServiceMock.Setup(x => x.GetById(0)).Returns(content);
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>();
userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions);
var permissions = new EntityPermissionCollection();
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act/assert
@@ -72,8 +73,9 @@ namespace Umbraco.Tests.Web.Controllers
contentServiceMock.Setup(x => x.GetById(1234)).Returns(content);
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>();
userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions);
var permissions = new EntityPermissionCollection();
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234")).Returns(permissionSet);
var userService = userServiceMock.Object;
//act
@@ -98,11 +100,12 @@ namespace Umbraco.Tests.Web.Controllers
contentServiceMock.Setup(x => x.GetById(1234)).Returns(content);
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>
var permissions = new EntityPermissionCollection
{
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
@@ -127,11 +130,12 @@ namespace Umbraco.Tests.Web.Controllers
contentServiceMock.Setup(x => x.GetById(1234)).Returns(content);
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>
var permissions = new EntityPermissionCollection
{
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
@@ -215,11 +219,12 @@ namespace Umbraco.Tests.Web.Controllers
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>
var permissions = new EntityPermissionCollection
{
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
@@ -239,11 +244,12 @@ namespace Umbraco.Tests.Web.Controllers
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>
var permissions = new EntityPermissionCollection
{
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
@@ -263,11 +269,13 @@ namespace Umbraco.Tests.Web.Controllers
var user = userMock.Object;
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);
var permissions = new EntityPermissionCollection
{
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
@@ -287,11 +295,12 @@ namespace Umbraco.Tests.Web.Controllers
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new List<EntityPermission>
var permissions = new EntityPermissionCollection
{
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
@@ -110,12 +110,12 @@ namespace Umbraco.Tests.Web.Controllers
var userServiceMock = new Mock<IUserService>();
//we're only assigning 3 nodes browse permissions so that is what we expect as a result
var permissions = new List<EntityPermission>
var permissions = new EntityPermissionCollection
{
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;
@@ -68,6 +68,8 @@ namespace Umbraco.Web.Cache
() => UserService.SavedUser -= UserService_SavedUser);
Bind(() => UserService.DeletedUser += UserService_DeletedUser,
() => UserService.DeletedUser -= UserService_DeletedUser);
Bind(() => UserService.UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned,
() => UserService.UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned);
// bind to dictionary events
Bind(() => LocalizationService.DeletedDictionaryItem += LocalizationService_DeletedDictionaryItem,
@@ -113,19 +115,7 @@ namespace Umbraco.Web.Cache
Bind(() => MemberTypeService.Deleted += MemberTypeService_Deleted,
() => MemberTypeService.Deleted -= MemberTypeService_Deleted);
// bind to permission events
// we should wrap legacy permissions so we can get rid of this
// fixme - the method names here (PermissionNew...) are not supported
// by the event handling mechanism for scopes and deploy, and not sure
// how to fix with the generic repository
Bind(() => Permission.New += PermissionNew,
() => Permission.New -= PermissionNew);
Bind(() => Permission.Updated += PermissionUpdated,
() => Permission.Updated -= PermissionUpdated);
Bind(() => Permission.Deleted += PermissionDeleted,
() => Permission.Deleted -= PermissionDeleted);
Bind(() => PermissionRepository<IContent>.AssignedPermissions += CacheRefresherEventHandler_AssignedPermissions,
() => PermissionRepository<IContent>.AssignedPermissions -= CacheRefresherEventHandler_AssignedPermissions);
// bind to template events
Bind(() => FileService.SavedTemplate += FileService_SavedTemplate,
@@ -360,13 +350,6 @@ namespace Umbraco.Web.Cache
/// </remarks>
static void ContentService_Copied(IContentService sender, CopyEventArgs<IContent> e)
{
//check if permissions have changed
var permissionsChanged = ((Content)e.Copy).WasPropertyDirty("PermissionsChanged");
if (permissionsChanged)
{
DistributedCache.Instance.RefreshAllUserGroupPermissionsCache();
}
//run the un-published cache refresher since copied content is not published
DistributedCache.Instance.RefreshUnpublishedPageCache(e.Copy);
}
@@ -388,33 +371,10 @@ namespace Umbraco.Web.Cache
/// <param name="e"></param>
/// <remarks>
/// When an entity is saved we need to notify other servers about the change in order for the Examine indexes to
/// stay up-to-date for unpublished content.
///
/// When an entity is created new permissions may be assigned to it based on it's parent, if that is the
/// case then we need to clear all user group permissions cache.
/// stay up-to-date for unpublished content.
/// </remarks>
static void ContentService_Saved(IContentService sender, SaveEventArgs<IContent> e)
{
var clearUserGroupPermissions = false;
e.SavedEntities.ForEach(x =>
{
//check if it is new
if (x.IsNewEntity())
{
//check if permissions have changed
var permissionsChanged = ((Content)x).WasPropertyDirty("PermissionsChanged");
if (permissionsChanged)
{
clearUserGroupPermissions = true;
}
}
});
if (clearUserGroupPermissions)
{
DistributedCache.Instance.RefreshAllUserGroupPermissionsCache();
}
//filter out the entities that have only been saved (not newly published) since
// newly published ones will be synced with the published page cache refresher
var unpublished = e.SavedEntities.Where(x => x.JustPublished() == false);
@@ -592,32 +552,21 @@ namespace Umbraco.Web.Cache
static void MemberTypeService_Saved(IMemberTypeService sender, SaveEventArgs<IMemberType> e)
{
e.SavedEntities.ForEach(x => DistributedCache.Instance.RefreshMemberTypeCache(x));
}
}
#endregion
#region User/permissions event handlers
static void CacheRefresherEventHandler_AssignedPermissions(PermissionRepository<IContent> sender, SaveEventArgs<UserGroupEntityPermission> e)
static void UserService_UserGroupPermissionsAssigned(IUserService sender, SaveEventArgs<EntityPermission> e)
{
var groupIds = e.SavedEntities.Select(x => x.UserGroupId).Distinct();
groupIds.ForEach(x => DistributedCache.Instance.RefreshUserGroupPermissionsCache(x));
}
static void PermissionDeleted(UserGroupPermission sender, DeleteEventArgs e)
{
InvalidateCacheForPermissionsChange(sender);
}
static void PermissionUpdated(UserGroupPermission sender, SaveEventArgs e)
{
InvalidateCacheForPermissionsChange(sender);
}
static void PermissionNew(UserGroupPermission sender, NewEventArgs e)
{
InvalidateCacheForPermissionsChange(sender);
//TODO: Not sure if we need this yet depends if we start caching permissions
//var groupIds = e.SavedEntities.Select(x => x.UserGroupId).Distinct();
//foreach (var groupId in groupIds)
//{
// DistributedCache.Instance.RefreshUserGroupPermissionsCache(groupId);
//}
}
static void UserService_SavedUser(IUserService sender, SaveEventArgs<IUser> e)
@@ -639,22 +588,7 @@ namespace Umbraco.Web.Cache
{
e.DeletedEntities.ForEach(x => DistributedCache.Instance.RemoveUserGroupCache(x.Id));
}
private static void InvalidateCacheForPermissionsChange(UserGroupPermission sender)
{
if (sender.UserGroup != null)
{
DistributedCache.Instance.RefreshUserGroupPermissionsCache(sender.UserGroup.Id);
}
else if (sender.UserId > -1)
{
DistributedCache.Instance.RefreshUserGroupPermissionsCache(sender.UserId);
}
else if (sender.NodeIds.Any())
{
DistributedCache.Instance.RefreshAllUserGroupPermissionsCache();
}
}
#endregion
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
@@ -34,8 +35,7 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
var jsonObject = JsonConvert.DeserializeObject<JsonPayload[]>(json);
return jsonObject;
}
@@ -79,9 +79,8 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(bool isDeleted, params IContentTypeBase[] contentTypes)
{
var serializer = new JavaScriptSerializer();
var items = contentTypes.Select(x => FromContentType(x, isDeleted)).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -3,6 +3,7 @@ using System.Web.Script.Serialization;
using Umbraco.Core;
using Umbraco.Core.Cache;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors.ValueConverters;
@@ -27,8 +28,7 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
private static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
var jsonObject = JsonConvert.DeserializeObject<JsonPayload[]>(json);
return jsonObject;
}
@@ -39,9 +39,8 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(params IDataTypeDefinition[] dataTypes)
{
var serializer = new JavaScriptSerializer();
var items = dataTypes.Select(FromDataTypeDefinition).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -88,7 +88,8 @@ namespace Umbraco.Web.Cache
public static void RefreshUserGroupPermissionsCache(this DistributedCache dc, int groupId)
{
dc.Refresh(DistributedCache.UserGroupPermissionsCacheRefresherGuid, groupId);
//TODO: Not sure if we need this yet depends if we start caching permissions
//dc.Refresh(DistributedCache.UserGroupPermissionsCacheRefresherGuid, groupId);
}
public static void RefreshAllUserGroupPermissionsCache(this DistributedCache dc)
+5 -8
View File
@@ -8,6 +8,7 @@ using umbraco;
using Umbraco.Core.Persistence.Repositories;
using umbraco.interfaces;
using System.Linq;
using Newtonsoft.Json;
using Macro = umbraco.cms.businesslogic.macro.Macro;
namespace Umbraco.Web.Cache
@@ -47,8 +48,7 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
private static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
var jsonObject = JsonConvert.DeserializeObject<JsonPayload[]>(json);
return jsonObject;
}
@@ -59,9 +59,8 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(params Macro[] macros)
{
var serializer = new JavaScriptSerializer();
var items = macros.Select(FromMacro).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -72,9 +71,8 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(params IMacro[] macros)
{
var serializer = new JavaScriptSerializer();
var items = macros.Select(FromMacro).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -85,9 +83,8 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(params macro[] macros)
{
var serializer = new JavaScriptSerializer();
var items = macros.Select(FromMacro).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
+5 -8
View File
@@ -11,6 +11,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Repositories;
using umbraco.interfaces;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Web.PublishedCache.XmlPublishedCache;
namespace Umbraco.Web.Cache
@@ -32,8 +33,7 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
public static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
var jsonObject = JsonConvert.DeserializeObject<JsonPayload[]>(json);
return jsonObject;
}
@@ -45,34 +45,31 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(OperationType operation, params IMedia[] media)
{
var serializer = new JavaScriptSerializer();
var items = media.Select(x => FromMedia(x, operation)).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
internal static string SerializeToJsonPayloadForMoving(OperationType operation, MoveEventInfo<IMedia>[] media)
{
var serializer = new JavaScriptSerializer();
var items = media.Select(x => new JsonPayload
{
Id = x.Entity.Id,
Operation = operation,
Path = x.OriginalPath
}).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
internal static string SerializeToJsonPayloadForPermanentDeletion(params int[] mediaIds)
{
var serializer = new JavaScriptSerializer();
var items = mediaIds.Select(x => new JsonPayload
{
Id = x,
Operation = OperationType.Deleted
}).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
@@ -20,8 +21,7 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
private static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
var jsonObject = JsonConvert.DeserializeObject<JsonPayload[]>(json);
return jsonObject;
}
@@ -32,9 +32,8 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static string SerializeToJsonPayload(params IMemberGroup[] groups)
{
var serializer = new JavaScriptSerializer();
var items = groups.Select(FromMemberGroup).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -5,7 +5,7 @@ using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Sync;
@@ -40,21 +40,19 @@ namespace Umbraco.Web.Cache
/// <returns></returns>
internal static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
var jsonObject = JsonConvert.DeserializeObject<JsonPayload[]>(json);
return jsonObject;
}
internal static string SerializeToJsonPayloadForPermanentDeletion(params int[] contentIds)
{
var serializer = new JavaScriptSerializer();
var items = contentIds.Select(x => new JsonPayload
{
Id = x,
Operation = OperationType.Deleted
}).ToArray();
var json = serializer.Serialize(items);
var json = JsonConvert.SerializeObject(items);
return json;
}
@@ -9,6 +9,9 @@ namespace Umbraco.Web.Cache
/// <summary>
/// Handles User group cache invalidation/refreshing
/// </summary>
/// <remarks>
/// This also needs to clear the user cache since IReadOnlyUserGroup's are attached to IUser objects
/// </remarks>
public sealed class UserGroupCacheRefresher : CacheRefresherBase<UserGroupCacheRefresher>
{
protected override UserGroupCacheRefresher Instance
@@ -34,10 +37,9 @@ namespace Umbraco.Web.Cache
{
userGroupCache.Result.ClearCacheByKeySearch(UserGroupRepository.GetByAliasCacheKeyPrefix);
}
if (UserGroupPermissionsCache)
{
UserGroupPermissionsCache.Result.ClearCacheByKeySearch(CacheKeys.UserGroupPermissionsCacheKey);
}
//We'll need to clear all user cache too
ClearAllIsolatedCacheByEntityType<IUser>();
base.RefreshAll();
}
@@ -57,19 +59,11 @@ namespace Umbraco.Web.Cache
userGroupCache.Result.ClearCacheByKeySearch(UserGroupRepository.GetByAliasCacheKeyPrefix);
}
if (UserGroupPermissionsCache)
{
//TODO: Is this good enough for all users attached to this?
var keyStartsWith = string.Format("{0}{1}", CacheKeys.UserGroupPermissionsCacheKey, id);
UserGroupPermissionsCache.Result.ClearCacheByKeySearch(keyStartsWith);
}
//we don't know what user's belong to this group without doing a look up so we'll need to just clear them all
ClearAllIsolatedCacheByEntityType<IUser>();
base.Remove(id);
}
private Attempt<IRuntimeCacheProvider> UserGroupPermissionsCache
{
get { return ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache<EntityPermission>(); }
}
}
}
@@ -1,17 +1,13 @@
using System;
using System.ComponentModel;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Web.Cache
{
/// <summary>
/// Used only to invalidate the user permissions cache
/// </summary>
/// <remarks>
/// The UserGroupCacheRefresher will also clear a groups's permissions cache, this refresher is for invalidating only permissions
/// for user groups/content, not the groups themselves.
/// </remarks>
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class UserGroupPermissionsCacheRefresher : CacheRefresherBase<UserGroupPermissionsCacheRefresher>
{
protected override UserGroupPermissionsCacheRefresher Instance
@@ -29,30 +25,6 @@ namespace Umbraco.Web.Cache
{
get { return "User group permissions cache refresher"; }
}
public override void RefreshAll()
{
if (UserGroupPermissionsCache)
UserGroupPermissionsCache.Result.ClearCacheByKeySearch(CacheKeys.UserGroupPermissionsCacheKey);
base.RefreshAll();
}
public override void Refresh(int id)
{
Remove(id);
base.Refresh(id);
}
public override void Remove(int id)
{
if (UserGroupPermissionsCache)
UserGroupPermissionsCache.Result.ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.UserGroupPermissionsCacheKey, id));
base.Remove(id);
}
private Attempt<IRuntimeCacheProvider> UserGroupPermissionsCache
{
get { return ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache<EntityPermission>(); }
}
}
}
+11 -7
View File
@@ -242,7 +242,7 @@ namespace Umbraco.Web.Editors
//set a custom path since the tree that renders this has the content type id as the parent
content.Path = string.Format("-1,{0},{1}", persistedContent.ContentTypeId, content.Id);
content.AllowedActions = new[] {'A'};
content.AllowedActions = new[] {"A"};
var excludeProps = new[] {"_umb_urls", "_umb_releasedate", "_umb_expiredate", "_umb_template"};
var propsTab = content.Tabs.Last();
@@ -440,8 +440,8 @@ namespace Umbraco.Web.Editors
[HttpGet]
public bool HasPermission(string permissionToCheck, int nodeId)
{
var p = Services.UserService.GetPermissions(Security.CurrentUser, nodeId).FirstOrDefault();
if (p != null && p.AssignedPermissions.Contains(permissionToCheck.ToString(CultureInfo.InvariantCulture)))
var p = Services.UserService.GetPermissions(Security.CurrentUser, nodeId).GetAllPermissions();
if (p.Contains(permissionToCheck.ToString(CultureInfo.InvariantCulture)))
{
return true;
}
@@ -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;
}
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Models.ContentEditing
/// Each char represents a button which we can then map on the front-end to the correct actions
/// </remarks>
[DataMember(Name = "allowedActions")]
public IEnumerable<char> AllowedActions { get; set; }
public IEnumerable<string> AllowedActions { get; set; }
}
}
@@ -135,7 +135,7 @@ namespace Umbraco.Web.Models.Mapping
Label = localizedText.Localize("content/releaseDate"),
Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null,
//Not editible for people without publish permission (U4-287)
View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View,
View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View,
Config = new Dictionary<string, object>
{
{"offsetTime", "1"}
@@ -148,7 +148,7 @@ namespace Umbraco.Web.Models.Mapping
Label = localizedText.Localize("content/unpublishDate"),
Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null,
//Not editible for people without publish permission (U4-287)
View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View,
View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View,
Config = new Dictionary<string, object>
{
{"offsetTime", "1"}
@@ -213,10 +213,9 @@ namespace Umbraco.Web.Models.Mapping
}
/// <summary>
//TODO: This is horribly inneficient
/// Creates the list of action buttons allowed for this user - Publish, Send to publish, save, unpublish returned as the button's 'letter'
/// </summary>
private class ActionButtonsResolver : ValueResolver<IContent, IEnumerable<char>>
private class ActionButtonsResolver : ValueResolver<IContent, IEnumerable<string>>
{
private readonly Lazy<IUserService> _userService;
@@ -225,12 +224,12 @@ namespace Umbraco.Web.Models.Mapping
_userService = userService;
}
protected override IEnumerable<char> ResolveCore(IContent source)
protected override IEnumerable<string> ResolveCore(IContent source)
{
if (UmbracoContext.Current == null)
{
//cannot check permissions without a context
return Enumerable.Empty<char>();
return Enumerable.Empty<string>();
}
var svc = _userService.Value;
@@ -242,11 +241,9 @@ namespace Umbraco.Web.Models.Mapping
// Here we need to do a special check since this could be new content, in which case we need to get the permissions
// from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0.
source.HasIdentity ? source.Id : source.ParentId)
.FirstOrDefault();
.GetAllPermissions();
return permissions == null
? Enumerable.Empty<char>()
: permissions.AssignedPermissions.Where(x => x.Length == 1).Select(x => x.ToUpperInvariant()[0]);
return permissions;
}
}
}
@@ -193,7 +193,7 @@ namespace Umbraco.Web.Models.Mapping
//Deal with assigned permissions:
var allContentPermissions = applicationContext.Services.UserService.GetPermissions(group, true)
var allContentPermissions = applicationContext.Services.UserService.GetPermissions(@group, true)
.ToDictionary(x => x.EntityId, x => x);
var contentEntities = allContentPermissions.Keys.Count == 0
@@ -74,7 +74,7 @@ namespace Umbraco.Web.WebApi.Filters
var nodePermission = permissions.Where(x => x.EntityId == Convert.ToInt32(item.Id)).ToArray();
//if there are no permissions for this id then we need to check what the user's default
// permissions are.
if (nodePermission.Any() == false)
if (nodePermission.Length == 0)
{
//var defaultP = user.DefaultPermissions
@@ -360,7 +360,7 @@ function openContent(id) {
}
else if (!this.IsDialog || (this.DialogMode == TreeDialogModes.id))
{
if (CurrentUser.GetPermissions(dd.Path).Contains(ActionUpdate.Instance.Letter.ToString()))
if (CurrentUser.GetPermissions(dd.Path).Contains(ActionUpdate.Instance.Letter.ToString(CultureInfo.InvariantCulture)))
{
treeElement.Action = String.Format("javascript:openContent({0});", dd.Id);
}
@@ -19,7 +19,8 @@ namespace umbraco.dialogs
/// <summary>
/// Summary description for cruds.
/// </summary>
public partial class cruds : BasePages.UmbracoEnsuredPage
[Obsolete("Remove this for 7.7 release!")]
public class cruds : BasePages.UmbracoEnsuredPage
{
public cruds()
@@ -37,78 +38,9 @@ namespace umbraco.dialogs
pane_form.Text = ui.Text("actions", "SetPermissionsForThePage",_node.Text);
}
override protected void OnInit(EventArgs e)
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_node = new CMSNode(Request.GetItemAs<int>("id"));
var ht = new HtmlTable();
ht.Attributes.Add("class", "table");
var names = new HtmlTableRow();
var corner = new HtmlTableCell("th");
corner.Style.Add("border", "none");
names.Cells.Add(corner);
foreach (var a in ActionsResolver.Current.Actions)
{
if (a.CanBePermissionAssigned == false) continue;
var permissionRow = new HtmlTableRow();
var label = new HtmlTableCell
{
InnerText = ui.Text("actions", a.Alias)
};
permissionRow.Cells.Add(label);
_permissions.Add(a.Alias, permissionRow);
}
ht.Rows.Add(names);
var userService = ApplicationContext.Current.Services.UserService;
foreach (var group in userService.GetAllUserGroups())
{
var hc = new HtmlTableCell("th")
{
InnerText = group.Name
};
hc.Style.Add("text-align", "center");
hc.Style.Add("border", "none");
names.Cells.Add(hc);
foreach (var a in ActionsResolver.Current.Actions)
{
var chk = new CheckBox
{
//Each checkbox is named with the group _ permission alias so we can parse
ID = group.Id + "_" + a.Letter
};
if (a.CanBePermissionAssigned == false) continue;
var permissions = userService.GetPermissionsForPath(group, _node.Path);
if (permissions.Contains(a.Letter))
{
chk.Checked = true;
}
var cell = new HtmlTableCell();
cell.Style.Add("text-align", "center");
cell.Controls.Add(chk);
_permissions[a.Alias].Cells.Add(cell);
}
}
//add all collected rows
foreach (var perm in _permissions.Values)
{
ht.Rows.Add(perm);
}
PlaceHolder1.Controls.Add(ht);
throw new NotSupportedException("This cruds.aspx.cs needs to be removed, it is no longer required");
}
@@ -137,8 +137,8 @@ namespace umbraco.dialogs
private bool CheckPermissions(IContentBase node, IAction currentAction)
{
var userService = ApplicationContext.Current.Services.UserService;
var currUserPermissions = userService.GetPermissions(UmbracoContext.Current.Security.CurrentUser, node.Id).FirstOrDefault();
return currUserPermissions != null && currUserPermissions.AssignedPermissions.Contains(currentAction.Letter.ToString());
var currUserPermissions = userService.GetPermissions(UmbracoContext.Current.Security.CurrentUser, node.Id).GetAllPermissions();
return currUserPermissions != null && currUserPermissions.Contains(currentAction.Letter.ToString(CultureInfo.InvariantCulture));
}
private void HandleDocumentTypeCopy()
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Globalization;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
@@ -49,7 +50,7 @@ namespace umbraco.dialogs
{
CheckBox c = new CheckBox();
c.ID = a.Letter.ToString();
c.ID = a.Letter.ToString(CultureInfo.InvariantCulture);
if (base.getUser().GetNotifications(node.Path).IndexOf(a.Letter) > -1)
c.Checked = true;
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
@@ -304,7 +305,7 @@ namespace umbraco.presentation.templateControls
protected virtual bool FieldEditableWithUserPermissions()
{
BusinessLogic.User u = helper.GetCurrentUmbracoUser();
return u != null && u.GetPermissions(PageElements["path"].ToString()).Contains(ActionUpdate.Instance.Letter.ToString());
return u != null && u.GetPermissions(PageElements["path"].ToString()).Contains(ActionUpdate.Instance.Letter.ToString(CultureInfo.InvariantCulture));
}
#endregion
+2 -1
View File
@@ -571,7 +571,8 @@ namespace umbraco.BusinessLogic
if (_lazyId.HasValue) SetupUser(_lazyId.Value);
var userService = ApplicationContext.Current.Services.UserService;
return userService.GetPermissionsForPath(UserEntity, path);
return string.Join("",
userService.GetPermissionsForPath(UserEntity, path).GetAllPermissions());
}
/// <summary>
+2 -1
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Web;
using System.Reflection;
using Umbraco.Core;
@@ -150,7 +151,7 @@ namespace umbraco.BusinessLogic.Actions
/// <returns></returns>
public static string ToString(List<IAction> actions)
{
string[] strMenu = Array.ConvertAll<IAction, string>(actions.ToArray(), delegate(IAction a) { return (a.Letter.ToString()); });
string[] strMenu = Array.ConvertAll<IAction, string>(actions.ToArray(), delegate(IAction a) { return (a.Letter.ToString(CultureInfo.InvariantCulture)); });
return string.Join("", strMenu);
}
+8 -130
View File
@@ -9,15 +9,15 @@ using Umbraco.Core.Events;
using umbraco.DataLayer;
using umbraco.cms.businesslogic;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using DeleteEventArgs = umbraco.cms.businesslogic.DeleteEventArgs;
namespace umbraco.BusinessLogic
{
/// <summary>
/// Summary description for Permission.
/// </summary>
[Obsolete("This is no longer used and will be removed in future versions, use the IUserService to manage permissions for Users")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class Permission
{
@@ -32,24 +32,8 @@ namespace umbraco.BusinessLogic
public static void MakeNew(IUserGroup userGroup, CMSNode node, char permissionKey)
{
MakeNew(userGroup, node, permissionKey, true);
}
private static void MakeNew(IUserGroup userGroup, IEnumerable<CMSNode> nodes, char permissionKey, bool raiseEvents)
{
var asArray = nodes.ToArray();
ApplicationContext.Current.Services.UserService.AssignUserGroupPermission(userGroup.Id, permissionKey, asArray.Select(x => x.Id).ToArray());
if (raiseEvents)
{
OnNew(new UserGroupPermission(userGroup, asArray, new[] { permissionKey }), new NewEventArgs());
}
}
private static void MakeNew(IUserGroup userGroup, CMSNode Node, char PermissionKey, bool raiseEvents)
{
MakeNew(userGroup, new[] {Node}, PermissionKey, raiseEvents);
ApplicationContext.Current.Services.UserService.AssignUserGroupPermission(
userGroup.Id, permissionKey, node.Id);
}
/// <summary>
@@ -99,17 +83,8 @@ namespace umbraco.BusinessLogic
/// <param name="userGroup"></param>
/// <param name="node"></param>
public static void DeletePermissions(IUserGroup userGroup, CMSNode node)
{
DeletePermissions(userGroup, node, true);
}
internal static void DeletePermissions(IUserGroup userGroup, CMSNode node, bool raiseEvents)
{
ApplicationContext.Current.Services.UserService.RemoveUserGroupPermissions(userGroup.Id, node.Id);
if (raiseEvents)
{
OnDeleted(new UserGroupPermission(userGroup, node, null), new DeleteEventArgs());
}
}
/// <summary>
@@ -119,15 +94,13 @@ namespace umbraco.BusinessLogic
public static void DeletePermissions(IUserGroup userGroup)
{
ApplicationContext.Current.Services.UserService.RemoveUserGroupPermissions(userGroup.Id);
OnDeleted(new UserGroupPermission(userGroup, Enumerable.Empty<CMSNode>(), null), new DeleteEventArgs());
}
public static void DeletePermissions(int userGroupId, int[] iNodeIDs)
{
ApplicationContext.Current.Services.UserService.RemoveUserGroupPermissions(userGroupId, iNodeIDs);
OnDeleted(new UserGroupPermission(userGroupId, iNodeIDs), new DeleteEventArgs());
}
public static void DeletePermissions(int userGroupId, int iNodeID)
{
@@ -142,7 +115,6 @@ namespace umbraco.BusinessLogic
{
ApplicationContext.Current.Services.ContentService.RemoveContentPermissions(node.Id);
OnDeleted(new UserGroupPermission(null, node, null), new DeleteEventArgs());
}
public static void UpdateCruds(IUserGroup userGroup, CMSNode node, string permissions)
@@ -151,103 +123,9 @@ namespace umbraco.BusinessLogic
userGroup.Id,
permissions.ToCharArray(),
node.Id);
OnUpdated(new UserGroupPermission(userGroup, node, permissions.ToCharArray()), new SaveEventArgs());
}
internal static event TypedEventHandler<UserGroupPermission, DeleteEventArgs> Deleted;
private static void OnDeleted(UserGroupPermission permission, DeleteEventArgs args)
{
if (Deleted != null)
{
Deleted(permission, args);
}
}
internal static event TypedEventHandler<UserGroupPermission, SaveEventArgs> Updated;
private static void OnUpdated(UserGroupPermission permission, SaveEventArgs args)
{
if (Updated != null)
{
Updated(permission, args);
}
}
internal static event TypedEventHandler<UserGroupPermission, NewEventArgs> New;
private static void OnNew(UserGroupPermission permission, NewEventArgs args)
{
if (New != null)
{
New(permission, args);
}
}
}
internal class UserGroupPermission
{
private int? _userGroupId;
private readonly int[] _nodeIds;
internal UserGroupPermission(int userGroupId)
{
_userGroupId = userGroupId;
}
internal UserGroupPermission(int userGroupId, IEnumerable<int> nodeIds)
{
_userGroupId = userGroupId;
_nodeIds = nodeIds.ToArray();
}
internal UserGroupPermission(IUserGroup userGroup, CMSNode node, char[] permissionKeys)
{
UserGroup = userGroup;
Nodes = new[] { node };
PermissionKeys = permissionKeys;
}
internal UserGroupPermission(IUserGroup userGroup, IEnumerable<CMSNode> nodes, char[] permissionKeys)
{
UserGroup = userGroup;
Nodes = nodes;
PermissionKeys = permissionKeys;
}
internal int UserId
{
get
{
if (_userGroupId.HasValue)
{
return _userGroupId.Value;
}
if (UserGroup != null)
{
return UserGroup.Id;
}
return -1;
}
}
internal IEnumerable<int> NodeIds
{
get
{
if (_nodeIds != null)
{
return _nodeIds;
}
if (Nodes != null)
{
return Nodes.Select(x => x.Id);
}
return Enumerable.Empty<int>();
}
}
internal IUserGroup UserGroup { get; private set; }
internal IEnumerable<CMSNode> Nodes { get; private set; }
internal char[] PermissionKeys { get; private set; }
}
}