Merge pull request #2046 from umbraco/temp-U4-10075
U4-10075 Inherited permissions for content nodes
This commit is contained in:
@@ -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")]
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>(); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user