diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 3b9ee9c63a..a4c0cc717f 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -56,7 +56,7 @@ namespace Umbraco.Core.Cache [EditorBrowsable(EditorBrowsableState.Never)] public const string UserCacheKey = "UmbracoUser"; - public const string UserPermissionsCacheKey = "UmbracoUserPermissions"; + public const string UserGroupPermissionsCacheKey = "UmbracoUserGroupPermissions"; [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string ContentTypeCacheKey = "UmbracoContentType"; diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index 50dc7d06f8..03631bda05 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -34,10 +34,9 @@ namespace Umbraco.Core.Models.Identity public int StartContentId { get; set; } public int StartMediaId { get; set; } public string[] AllowedSections { get; set; } + public string[] Groups { get; set; } public string Culture { get; set; } - public string UserTypeAlias { get; set; } - /// /// Lockout is always enabled /// diff --git a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs index fab34e5f17..56e3c995be 100644 --- a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs +++ b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs @@ -23,16 +23,16 @@ namespace Umbraco.Core.Models.Identity .ForMember(user => user.Name, expression => expression.MapFrom(user => user.Name)) .ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId)) .ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId)) - .ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias)) .ForMember(user => user.AccessFailedCount, expression => expression.MapFrom(user => user.FailedPasswordAttempts)) + .ForMember(user => user.Groups, expression => expression.MapFrom(user => user.Groups.Select(x => x.Name).ToArray())) .ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray())); config.CreateMap() .ConstructUsing((BackOfficeIdentityUser user) => new UserData(Guid.NewGuid().ToString("N"))) //this is the 'session id' .ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id)) .ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections)) + .ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Groups)) .ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name)) - .ForMember(detail => detail.Roles, opt => opt.MapFrom(user => new[] { user.UserTypeAlias })) .ForMember(detail => detail.StartContentNode, opt => opt.MapFrom(user => user.StartContentId)) .ForMember(detail => detail.StartMediaNode, opt => opt.MapFrom(user => user.StartMediaId)) .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.UserName)) diff --git a/src/Umbraco.Core/Models/Membership/EntityPermission.cs b/src/Umbraco.Core/Models/Membership/EntityPermission.cs index 7ab1ddc817..90430e26a8 100644 --- a/src/Umbraco.Core/Models/Membership/EntityPermission.cs +++ b/src/Umbraco.Core/Models/Membership/EntityPermission.cs @@ -1,26 +1,38 @@ -using System.Collections; +using System.Linq; namespace Umbraco.Core.Models.Membership { /// - /// Represents a user -> entity permission + /// Represents an entity permission (defined on the user group and derived to retrieve permissions for a given user) /// public class EntityPermission { - public EntityPermission(int userId, int entityId, string[] assignedPermissions) + public EntityPermission(int entityId, string[] assignedPermissions) { - UserId = userId; EntityId = entityId; AssignedPermissions = assignedPermissions; } - public int UserId { get; private set; } public int EntityId { get; private set; } /// /// The assigned permissions for the user/entity combo /// public string[] AssignedPermissions { get; private set; } + + /// + /// Adds additional permissions to an existing instance of + /// ensuring that only ones that aren't already assigned are added + /// + /// + public void AddAdditionalPermissions(string[] additionalPermissions) + { + var newPermissions = AssignedPermissions.ToList(); + newPermissions.AddRange(additionalPermissions); + AssignedPermissions = newPermissions + .Distinct() + .ToArray(); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs b/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs index c4669caf59..ea1e927a59 100644 --- a/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs +++ b/src/Umbraco.Core/Models/Membership/EntityPermissionSet.cs @@ -13,30 +13,31 @@ namespace Umbraco.Core.Models.Membership public int EntityId { get; private set; } /// - /// The key/value pairs of user id & single permission + /// The key/value pairs of user group id & single permission /// - public IEnumerable UserPermissionsSet { get; private set; } + public IEnumerable PermissionsSet { get; private set; } - public EntityPermissionSet(int entityId, IEnumerable userPermissionsSet) + public EntityPermissionSet(int entityId, IEnumerable permissionsSet) { EntityId = entityId; - UserPermissionsSet = userPermissionsSet; + PermissionsSet = permissionsSet; } - public class UserPermission + public class UserGroupPermission { - public UserPermission(int userId, string permission) + public UserGroupPermission(int groupId, string permission) { - UserId = userId; + UserGroupId = groupId; Permission = permission; } - public int UserId { get; private set; } + public int UserGroupId { get; private set; } + public string Permission { get; private set; } - protected bool Equals(UserPermission other) + protected bool Equals(UserGroupPermission other) { - return UserId == other.UserId && string.Equals(Permission, other.Permission); + return UserGroupId == other.UserGroupId && string.Equals(Permission, other.Permission); } public override bool Equals(object obj) @@ -44,14 +45,14 @@ namespace Umbraco.Core.Models.Membership if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; - return Equals((UserPermission) obj); + return Equals((UserGroupPermission) obj); } public override int GetHashCode() { unchecked { - return (UserId*397) ^ Permission.GetHashCode(); + return (UserGroupId * 397) ^ Permission.GetHashCode(); } } } diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index f1f9c23971..171a9f0c99 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using Umbraco.Core.Models.EntityBase; -using Umbraco.Core.Persistence.Mappers; namespace Umbraco.Core.Models.Membership { @@ -15,24 +14,24 @@ namespace Umbraco.Core.Models.Membership int StartContentId { get; set; } int StartMediaId { get; set; } string Language { get; set; } - - /// - /// Gets/sets the user type for the user - /// - IUserType UserType { get; set; } - //TODO: This should be a private set /// - /// The default permission set for the user + /// Gets the groups that user is part of /// - /// - /// Currently in umbraco each permission is a single char but with an Enumerable{string} collection this allows for flexible changes to this in the future - /// - IEnumerable DefaultPermissions { get; set; } + IEnumerable Groups { get; } + + /// + /// Indicates if the groups for a user have been loaded + /// + bool GroupsLoaded { get; } + + void RemoveGroup(IUserGroup group); + + void AddGroup(IUserGroup group); + + void SetGroupsLoaded(); IEnumerable AllowedSections { get; } - void RemoveAllowedSection(string sectionAlias); - void AddAllowedSection(string sectionAlias); /// /// Exposes the basic profile data diff --git a/src/Umbraco.Core/Models/Membership/IUserType.cs b/src/Umbraco.Core/Models/Membership/IUserGroup.cs similarity index 64% rename from src/Umbraco.Core/Models/Membership/IUserType.cs rename to src/Umbraco.Core/Models/Membership/IUserGroup.cs index fe678afd2b..336caa4c47 100644 --- a/src/Umbraco.Core/Models/Membership/IUserType.cs +++ b/src/Umbraco.Core/Models/Membership/IUserGroup.cs @@ -1,28 +1,34 @@ -using System.Collections.Generic; -using Umbraco.Core.Models.EntityBase; -using Umbraco.Core.Persistence.Mappers; - -namespace Umbraco.Core.Models.Membership -{ - - public interface IUserType : IAggregateRoot - { - /// - /// The user type alias - /// - string Alias { get; set; } - - /// - /// The user type name - /// - string Name { get; set; } - - /// - /// The set of default permissions for the user type - /// - /// - /// 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. - /// - IEnumerable Permissions { get; set; } - } +using System.Collections.Generic; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Models.Membership +{ + public interface IUserGroup : IAggregateRoot + { + /// + /// The alias + /// + string Alias { get; set; } + + /// + /// The name + /// + string Name { get; set; } + + /// + /// The set of default permissions + /// + /// + /// 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. + /// + IEnumerable Permissions { get; set; } + + IEnumerable AllowedSections { get; } + + void RemoveAllowedSection(string sectionAlias); + + void AddAllowedSection(string sectionAlias); + + void ClearAllowedSections(); + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/UmbracoMembershipUser.cs b/src/Umbraco.Core/Models/Membership/UmbracoMembershipUser.cs index ada2a7102d..0ada5c3d0e 100644 --- a/src/Umbraco.Core/Models/Membership/UmbracoMembershipUser.cs +++ b/src/Umbraco.Core/Models/Membership/UmbracoMembershipUser.cs @@ -34,12 +34,11 @@ namespace Umbraco.Core.Models.Membership /// The last lockout date. /// The full name. /// The language. - /// Type of the user. /// public UmbracoMembershipUser(string providerName, string name, object providerUserKey, string email, string passwordQuestion, string comment, bool isApproved, bool isLockedOut, DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate, DateTime lastPasswordChangedDate, - DateTime lastLockoutDate, string fullName, string language, IUserType userType, T user) + DateTime lastLockoutDate, string fullName, string language, T user) : base( providerName, name, providerUserKey, email, passwordQuestion, comment, isApproved, isLockedOut, creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate) { diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index cadda14508..8dd1f31654 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -8,7 +8,6 @@ using System.Runtime.Serialization; using Umbraco.Core.Configuration; using Umbraco.Core.Models.EntityBase; - namespace Umbraco.Core.Models.Membership { /// @@ -18,19 +17,11 @@ namespace Umbraco.Core.Models.Membership [DataContract(IsReference = true)] public class User : Entity, IUser { - public User(IUserType userType) + public User() { - if (userType == null) throw new ArgumentNullException("userType"); - - _userType = userType; - _defaultPermissions = _userType.Permissions == null ? Enumerable.Empty() : new List(_userType.Permissions); - //Groups = new List { userType }; SessionTimeout = 60; - _sectionCollection = new ObservableCollection(); - _addedSections = new List(); - _removedSections = new List(); + _groupCollection = new List(); _language = GlobalSettings.DefaultUILanguage; - _sectionCollection.CollectionChanged += SectionCollectionChanged; _isApproved = true; _isLockedOut = false; _startContentId = -1; @@ -39,8 +30,8 @@ namespace Umbraco.Core.Models.Membership _rawPasswordValue = ""; } - public User(string name, string email, string username, string rawPasswordValue, IUserType userType) - : this(userType) + public User(string name, string email, string username, string rawPasswordValue) + : this() { _name = name; _email = email; @@ -52,12 +43,10 @@ namespace Umbraco.Core.Models.Membership _startMediaId = -1; } - private IUserType _userType; private string _name; private string _securityStamp; - private List _addedSections; - private List _removedSections; - private ObservableCollection _sectionCollection; + private List _groupCollection; + private bool _groupsLoaded; private int _sessionTimeout; private int _startContentId; private int _startMediaId; @@ -73,8 +62,6 @@ namespace Umbraco.Core.Models.Membership private DateTime _lastLoginDate; private DateTime _lastLockoutDate; - private IEnumerable _defaultPermissions; - private bool _defaultToLiveEditing; private static readonly Lazy Ps = new Lazy(); @@ -90,7 +77,6 @@ namespace Umbraco.Core.Models.Membership public readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo(x => x.SessionTimeout); public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentId); public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaId); - public readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedSections); public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); public readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo(x => x.Username); @@ -101,7 +87,6 @@ namespace Umbraco.Core.Models.Membership public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language); public readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultToLiveEditing); - public readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.UserType); } #region Implementation of IMembershipUser @@ -198,22 +183,16 @@ namespace Umbraco.Core.Models.Membership public IEnumerable AllowedSections { - get { return _sectionCollection; } - } - - public void RemoveAllowedSection(string sectionAlias) - { - if (_sectionCollection.Contains(sectionAlias)) + get { - _sectionCollection.Remove(sectionAlias); - } - } + if (GroupsLoaded == false) + { + return Enumerable.Empty(); + } - public void AddAllowedSection(string sectionAlias) - { - if (_sectionCollection.Contains(sectionAlias) == false) - { - _sectionCollection.Add(sectionAlias); + return Groups + .SelectMany(x => x.AllowedSections) + .Distinct(); } } @@ -232,22 +211,6 @@ namespace Umbraco.Core.Models.Membership set { SetPropertyValueAndDetectChanges(value, ref _securityStamp, Ps.Value.SecurityStampSelector); } } - /// - /// Used internally to check if we need to add a section in the repository to the db - /// - internal IEnumerable AddedSections - { - get { return _addedSections; } - } - - /// - /// Used internally to check if we need to remove a section in the repository to the db - /// - internal IEnumerable RemovedSections - { - get { return _removedSections; } - } - /// /// Gets or sets the session timeout. /// @@ -294,14 +257,6 @@ namespace Umbraco.Core.Models.Membership set { SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector); } } - //TODO: This should be a private set - [DataMember] - public IEnumerable DefaultPermissions - { - get { return _defaultPermissions;} - set { _defaultPermissions = value; } - } - [IgnoreDataMember] internal bool DefaultToLiveEditing { @@ -309,78 +264,51 @@ namespace Umbraco.Core.Models.Membership set { SetPropertyValueAndDetectChanges(value, ref _defaultToLiveEditing, Ps.Value.DefaultToLiveEditingSelector); } } - [IgnoreDataMember] - public IUserType UserType + /// + /// Gets or sets the groups that user is part of + /// + [DataMember] + public IEnumerable Groups { - get { return _userType; } - set - { - if (value.HasIdentity == false) - { - throw new InvalidOperationException("Cannot assign a User Type that has not been persisted"); - } + get { return _groupCollection; } + } - SetPropertyValueAndDetectChanges(value, ref _userType, Ps.Value.UserTypeSelector); + /// + /// Indicates if the groups for a user have been loaded + /// + public bool GroupsLoaded { get { return _groupsLoaded; } } + + public void RemoveGroup(IUserGroup group) + { + if (_groupCollection.Select(x => x.Id).Contains(group.Id)) + { + _groupCollection.Remove(group); } } + public void AddGroup(IUserGroup group) + { + if (_groupCollection.Select(x => x.Id).Contains(group.Id) == false) + { + _groupCollection.Add(group); + } + } + + public void SetGroupsLoaded() + { + _groupsLoaded = true; + } + #endregion - /// - /// Whenever resetting occurs, clear the remembered add/removed collections, even if - /// rememberPreviouslyChangedProperties is true, the AllowedSections property will still - /// be flagged as dirty. - /// - /// - public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties) - { - _addedSections.Clear(); - _removedSections.Clear(); - base.ResetDirtyProperties(rememberPreviouslyChangedProperties); - } - - /// - /// Handles the collection changed event in order for us to flag the AllowedSections property as changed - /// - /// - /// - void SectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - OnPropertyChanged(Ps.Value.AllowedSectionsSelector); - - if (e.Action == NotifyCollectionChangedAction.Add) - { - var item = e.NewItems.Cast().First(); - - if (_addedSections.Contains(item) == false) - { - _addedSections.Add(item); - } - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - var item = e.OldItems.Cast().First(); - - if (_removedSections.Contains(item) == false) - { - _removedSections.Add(item); - } - - } - } - public override object DeepClone() { var clone = (User)base.DeepClone(); //turn off change tracking clone.DisableChangeTracking(); //need to create new collections otherwise they'll get copied by ref - clone._addedSections = new List(); - clone._removedSections = new List(); - clone._sectionCollection = new ObservableCollection(_sectionCollection.ToList()); - clone._defaultPermissions = new List(_defaultPermissions.ToList()); + clone._groupCollection = new List(_groupCollection.ToList()); //re-create the event handler - clone._sectionCollection.CollectionChanged += clone.SectionCollectionChanged; //this shouldn't really be needed since we're not tracking clone.ResetDirtyProperties(false); //re-enable tracking diff --git a/src/Umbraco.Core/Models/Membership/UserGroup.cs b/src/Umbraco.Core/Models/Membership/UserGroup.cs index b0f10d9ff1..885a7cbe55 100644 --- a/src/Umbraco.Core/Models/Membership/UserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/UserGroup.cs @@ -1,20 +1,102 @@ using System; +using System.Collections.Generic; +using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Strings; namespace Umbraco.Core.Models.Membership { /// /// Represents a Group for a Backoffice User /// - /// - /// Should be internal until a proper user/membership implementation - /// is part of the roadmap. - /// [Serializable] [DataContract(IsReference = true)] - internal class UserGroup : Entity + internal class UserGroup : Entity, IUserGroup { - //Add UserCollection ? + private string _alias; + private string _name; + private IEnumerable _permissions; + private readonly List _sectionCollection; + + private static readonly Lazy Ps = new Lazy(); + + private class PropertySelectors + { + public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); + public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); + public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Permissions); + } + + public UserGroup() + { + _sectionCollection = new List(); + } + + [DataMember] + public string Alias + { + get { return _alias; } + set + { + SetPropertyValueAndDetectChanges( + value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase), + ref _alias, + Ps.Value.AliasSelector); + } + } + + [DataMember] + public string Name + { + get { return _name; } + set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } + } + + /// + /// The set of default permissions for the user type + /// + /// + /// 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. + /// + [DataMember] + public IEnumerable Permissions + { + get { return _permissions; } + set + { + SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector, + //Custom comparer for enumerable + new DelegateEqualityComparer>( + (enum1, enum2) => enum1.UnsortedSequenceEqual(enum2), + enum1 => enum1.GetHashCode())); + } + } + + public IEnumerable AllowedSections + { + get { return _sectionCollection; } + } + + public void RemoveAllowedSection(string sectionAlias) + { + if (_sectionCollection.Contains(sectionAlias)) + { + _sectionCollection.Remove(sectionAlias); + } + } + + public void AddAllowedSection(string sectionAlias) + { + if (_sectionCollection.Contains(sectionAlias) == false) + { + _sectionCollection.Add(sectionAlias); + } + } + + public void ClearAllowedSections() + { + _sectionCollection.Clear(); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/UserGroupEntityPermission.cs b/src/Umbraco.Core/Models/Membership/UserGroupEntityPermission.cs new file mode 100644 index 0000000000..619223f01a --- /dev/null +++ b/src/Umbraco.Core/Models/Membership/UserGroupEntityPermission.cs @@ -0,0 +1,16 @@ +namespace Umbraco.Core.Models.Membership +{ + /// + /// Represents a user group -> entity permission + /// + public class UserGroupEntityPermission : EntityPermission + { + public UserGroupEntityPermission(int groupId, int entityId, string[] assignedPermissions) + : base(entityId, assignedPermissions) + { + UserGroupId = groupId; + } + + public int UserGroupId { get; private set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/UserType.cs b/src/Umbraco.Core/Models/Membership/UserType.cs deleted file mode 100644 index 01183e9d9d..0000000000 --- a/src/Umbraco.Core/Models/Membership/UserType.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; -using Umbraco.Core.Models.EntityBase; -using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.Strings; - -namespace Umbraco.Core.Models.Membership -{ - /// - /// Represents the Type for a Backoffice User - /// - [Serializable] - [DataContract(IsReference = true)] - internal class UserType : Entity, IUserType - { - private string _alias; - private string _name; - private IEnumerable _permissions; - - private static readonly Lazy Ps = new Lazy(); - - private class PropertySelectors - { - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); - public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Permissions); - } - - [DataMember] - public string Alias - { - get { return _alias; } - set - { - SetPropertyValueAndDetectChanges( - value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase), - ref _alias, - Ps.Value.AliasSelector); - } - } - - [DataMember] - public string Name - { - get { return _name; } - set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } - } - - /// - /// The set of default permissions for the user type - /// - /// - /// 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. - /// - [DataMember] - public IEnumerable Permissions - { - get { return _permissions; } - set - { - SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector, - //Custom comparer for enumerable - new DelegateEqualityComparer>( - (enum1, enum2) => enum1.UnsortedSequenceEqual(enum2), - enum1 => enum1.GetHashCode())); - } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Rdbms/User2UserGroupDto.cs b/src/Umbraco.Core/Models/Rdbms/User2UserGroupDto.cs new file mode 100644 index 0000000000..afdbf661b5 --- /dev/null +++ b/src/Umbraco.Core/Models/Rdbms/User2UserGroupDto.cs @@ -0,0 +1,19 @@ +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.DatabaseAnnotations; + +namespace Umbraco.Core.Models.Rdbms +{ + [TableName("umbracoUser2UserGroup")] + [ExplicitColumns] + internal class User2UserGroupDto + { + [Column("userId")] + [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_user2userGroup", OnColumns = "userId, userGroupId")] + [ForeignKey(typeof(UserDto))] + public int UserId { get; set; } + + [Column("userGroupId")] + [ForeignKey(typeof(UserGroupDto))] + public int UserGroupId { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Rdbms/UserDto.cs b/src/Umbraco.Core/Models/Rdbms/UserDto.cs index 05a93c86bf..73434ef9f3 100644 --- a/src/Umbraco.Core/Models/Rdbms/UserDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/UserDto.cs @@ -22,10 +22,6 @@ namespace Umbraco.Core.Models.Rdbms [Constraint(Default = "0")] public bool NoConsole { get; set; } - [Column("userType")] - [ForeignKey(typeof(UserTypeDto))] - public short Type { get; set; } - [Column("startStructureID")] public int ContentStartId { get; set; } @@ -73,8 +69,5 @@ namespace Umbraco.Core.Models.Rdbms [Column("lastLoginDate")] [NullSetting(NullSetting = NullSettings.Null)] public DateTime? LastLoginDate { get; set; } - - [ResultColumn] - public List User2AppDtos { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Rdbms/User2AppDto.cs b/src/Umbraco.Core/Models/Rdbms/UserGroup2AppDto.cs similarity index 54% rename from src/Umbraco.Core/Models/Rdbms/User2AppDto.cs rename to src/Umbraco.Core/Models/Rdbms/UserGroup2AppDto.cs index eafc6be230..14fc60e197 100644 --- a/src/Umbraco.Core/Models/Rdbms/User2AppDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/UserGroup2AppDto.cs @@ -1,20 +1,19 @@ -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.DatabaseAnnotations; - -namespace Umbraco.Core.Models.Rdbms -{ - [TableName("umbracoUser2app")] - [PrimaryKey("user", autoIncrement = false)] - [ExplicitColumns] - internal class User2AppDto - { - [Column("user")] - [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_user2app", OnColumns = "user, app")] - [ForeignKey(typeof(UserDto))] - public int UserId { get; set; } - - [Column("app")] - [Length(50)] - public string AppAlias { get; set; } - } +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.DatabaseAnnotations; + +namespace Umbraco.Core.Models.Rdbms +{ + [TableName("umbracoUserGroup2App")] + [ExplicitColumns] + internal class UserGroup2AppDto + { + [Column("userGroupId")] + [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_userGroup2App", OnColumns = "userGroupId, app")] + [ForeignKey(typeof(UserGroupDto))] + public int UserGroupId { get; set; } + + [Column("app")] + [Length(50)] + public string AppAlias { get; set; } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Rdbms/User2NodePermissionDto.cs b/src/Umbraco.Core/Models/Rdbms/UserGroup2NodePermissionDto.cs similarity index 59% rename from src/Umbraco.Core/Models/Rdbms/User2NodePermissionDto.cs rename to src/Umbraco.Core/Models/Rdbms/UserGroup2NodePermissionDto.cs index f0d769a21e..8c75dcf4f7 100644 --- a/src/Umbraco.Core/Models/Rdbms/User2NodePermissionDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/UserGroup2NodePermissionDto.cs @@ -3,15 +3,14 @@ using Umbraco.Core.Persistence.DatabaseAnnotations; namespace Umbraco.Core.Models.Rdbms { - [TableName("umbracoUser2NodePermission")] - [PrimaryKey("userId", autoIncrement = false)] + [TableName("umbracoUserGroup2NodePermission")] [ExplicitColumns] - internal class User2NodePermissionDto + internal class UserGroup2NodePermissionDto { - [Column("userId")] - [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUser2NodePermission", OnColumns = "userId, nodeId, permission")] - [ForeignKey(typeof(UserDto))] - public int UserId { get; set; } + [Column("userGroupId")] + [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUserGroup2NodePermission", OnColumns = "userGroupId, nodeId, permission")] + [ForeignKey(typeof(UserGroupDto))] + public int UserGroupId { get; set; } [Column("nodeId")] [ForeignKey(typeof(NodeDto))] diff --git a/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs b/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs new file mode 100644 index 0000000000..dd1023b68a --- /dev/null +++ b/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.DatabaseAnnotations; + +namespace Umbraco.Core.Models.Rdbms +{ + [TableName("umbracoUserGroup")] + [PrimaryKey("id")] + [ExplicitColumns] + internal class UserGroupDto + { + [Column("id")] + [PrimaryKeyColumn(IdentitySeed = 5)] + public int Id { get; set; } + + [Column("userGroupAlias")] + [Length(200)] + public string Alias { get; set; } + + [Column("userGroupName")] + [Length(200)] + public string Name { get; set; } + + [Column("userGroupDefaultPermissions")] + [Length(50)] + [NullSetting(NullSetting = NullSettings.Null)] + public string DefaultPermissions { get; set; } + + [ResultColumn] + public List UserGroup2AppDtos { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Rdbms/UserTypeDto.cs b/src/Umbraco.Core/Models/Rdbms/UserTypeDto.cs index d3268a14fb..cff36f6c32 100644 --- a/src/Umbraco.Core/Models/Rdbms/UserTypeDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/UserTypeDto.cs @@ -1,8 +1,10 @@ -using Umbraco.Core.Persistence; +using System; +using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.DatabaseAnnotations; namespace Umbraco.Core.Models.Rdbms { + [Obsolete("Table no longer exists as of 7.6 - retained only to support migrations from previous versions")] [TableName("umbracoUserType")] [PrimaryKey("id")] [ExplicitColumns] diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index ece63b4889..7cadc1c892 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -80,8 +81,7 @@ namespace Umbraco.Core.Models if (media == null) throw new ArgumentNullException("media"); return HasPathAccess(media.Path, user.StartMediaId, Constants.System.RecycleBinMedia); } - - + /// /// Determines whether this user is an admin. /// @@ -92,7 +92,7 @@ namespace Umbraco.Core.Models public static bool IsAdmin(this IUser user) { if (user == null) throw new ArgumentNullException("user"); - return user.UserType.Alias == "admin"; + return user.Groups != null && user.Groups.Any(x => x.Alias == "admin"); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs index 0a13c82447..3d4b02f804 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; @@ -9,19 +7,12 @@ namespace Umbraco.Core.Persistence.Factories { internal class UserFactory { - private readonly IUserType _userType; - - public UserFactory(IUserType userType) - { - _userType = userType; - } - #region Implementation of IEntityFactory public IUser BuildEntity(UserDto dto) { var guidId = dto.Id.ToGuid(); - var user = new User(_userType); + var user = new User(); try { @@ -44,11 +35,6 @@ namespace Umbraco.Core.Persistence.Factories user.LastLoginDate = dto.LastLoginDate ?? DateTime.MinValue; user.LastPasswordChangeDate = dto.LastPasswordChangeDate ?? DateTime.MinValue; - foreach (var app in dto.User2AppDtos) - { - user.AddAllowedSection(app.AppAlias); - } - //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 user.ResetDirtyProperties(false); @@ -64,41 +50,27 @@ namespace Umbraco.Core.Persistence.Factories public UserDto BuildDto(IUser entity) { var dto = new UserDto - { - ContentStartId = entity.StartContentId, - MediaStartId = entity.StartMediaId, - Disabled = entity.IsApproved == false, - Email = entity.Email, - Login = entity.Username, - NoConsole = entity.IsLockedOut, - Password = entity.RawPasswordValue, - UserLanguage = entity.Language, - UserName = entity.Name, - Type = short.Parse(entity.UserType.Id.ToString(CultureInfo.InvariantCulture)), - User2AppDtos = new List(), - SecurityStampToken = entity.SecurityStamp, - FailedLoginAttempts = entity.FailedPasswordAttempts, - LastLockoutDate = entity.LastLockoutDate == DateTime.MinValue ? (DateTime?)null : entity.LastLockoutDate, - LastLoginDate = entity.LastLoginDate == DateTime.MinValue ? (DateTime?)null : entity.LastLoginDate, - LastPasswordChangeDate = entity.LastPasswordChangeDate == DateTime.MinValue ? (DateTime?)null : entity.LastPasswordChangeDate, - }; - - foreach (var app in entity.AllowedSections) { - var appDto = new User2AppDto - { - AppAlias = app - }; - if (entity.HasIdentity) - { - appDto.UserId = (int) entity.Id; - } - - dto.User2AppDtos.Add(appDto); - } + ContentStartId = entity.StartContentId, + MediaStartId = entity.StartMediaId, + Disabled = entity.IsApproved == false, + Email = entity.Email, + Login = entity.Username, + NoConsole = entity.IsLockedOut, + Password = entity.RawPasswordValue, + UserLanguage = entity.Language, + UserName = entity.Name, + SecurityStampToken = entity.SecurityStamp, + FailedLoginAttempts = entity.FailedPasswordAttempts, + LastLockoutDate = entity.LastLockoutDate == DateTime.MinValue ? (DateTime?)null : entity.LastLockoutDate, + LastLoginDate = entity.LastLoginDate == DateTime.MinValue ? (DateTime?)null : entity.LastLoginDate, + LastPasswordChangeDate = entity.LastPasswordChangeDate == DateTime.MinValue ? (DateTime?)null : entity.LastPasswordChangeDate, + }; if (entity.HasIdentity) + { dto.Id = entity.Id.SafeCast(); + } return dto; } diff --git a/src/Umbraco.Core/Persistence/Factories/UserGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserGroupFactory.cs new file mode 100644 index 0000000000..323ef3319a --- /dev/null +++ b/src/Umbraco.Core/Persistence/Factories/UserGroupFactory.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Factories +{ + internal class UserGroupFactory + { + #region Implementation of IEntityFactory + + public IUserGroup BuildEntity(UserGroupDto dto) + { + var userGroup = new UserGroup(); + + try + { + userGroup.DisableChangeTracking(); + + userGroup.Alias = dto.Alias; + userGroup.Id = dto.Id; + userGroup.Name = dto.Name; + userGroup.Permissions = dto.DefaultPermissions.IsNullOrWhiteSpace() + ? Enumerable.Empty() + : dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)); + + if (dto.UserGroup2AppDtos != null) + { + foreach (var app in dto.UserGroup2AppDtos) + { + userGroup.AddAllowedSection(app.AppAlias); + } + } + + userGroup.ResetDirtyProperties(false); + return userGroup; + } + finally + { + userGroup.EnableChangeTracking(); + } + } + + public UserGroupDto BuildDto(IUserGroup entity) + { + var dto = new UserGroupDto + { + Alias = entity.Alias, + DefaultPermissions = entity.Permissions == null ? "" : string.Join("", entity.Permissions), + Name = entity.Name, + UserGroup2AppDtos = new List(), + }; + + foreach (var app in entity.AllowedSections) + { + var appDto = new UserGroup2AppDto + { + AppAlias = app + }; + if (entity.HasIdentity) + { + appDto.UserGroupId = entity.Id; + } + + dto.UserGroup2AppDtos.Add(appDto); + } + + if (entity.HasIdentity) + dto.Id = short.Parse(entity.Id.ToString()); + + return dto; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs deleted file mode 100644 index 0e6a17594f..0000000000 --- a/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoMapper; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Models.Rdbms; - -namespace Umbraco.Core.Persistence.Factories -{ - internal class UserSectionFactory - { - private readonly IUser _user; - - public UserSectionFactory(IUser user) - { - _user = user; - } - - public IEnumerable BuildEntity(IEnumerable dto) - { - return dto.Select(x => x.AppAlias); - } - - public IEnumerable BuildDto(IEnumerable entity) - { - return entity.Select(x => new User2AppDto - { - //NOTE: We're force casting to int here! this might not work in the future - UserId = (int)_user.Id, - AppAlias = x - }); - } - - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs deleted file mode 100644 index 5f9cfac994..0000000000 --- a/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Globalization; -using System.Linq; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Models.Rdbms; - -namespace Umbraco.Core.Persistence.Factories -{ - internal class UserTypeFactory - { - #region Implementation of IEntityFactory - - public IUserType BuildEntity(UserTypeDto dto) - { - var userType = new UserType(); - - try - { - userType.DisableChangeTracking(); - - userType.Alias = dto.Alias; - userType.Id = dto.Id; - userType.Name = dto.Name; - userType.Permissions = dto.DefaultPermissions.IsNullOrWhiteSpace() - ? Enumerable.Empty() - : dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)); - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - userType.ResetDirtyProperties(false); - return userType; - } - finally - { - userType.EnableChangeTracking(); - } - } - - public UserTypeDto BuildDto(IUserType entity) - { - var userType = new UserTypeDto - { - Alias = entity.Alias, - DefaultPermissions = entity.Permissions == null ? "" : string.Join("", entity.Permissions), - Name = entity.Name - }; - - if(entity.HasIdentity) - userType.Id = short.Parse(entity.Id.ToString()); - - return userType; - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Mappers/UserTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/UserGroupMapper.cs similarity index 56% rename from src/Umbraco.Core/Persistence/Mappers/UserTypeMapper.cs rename to src/Umbraco.Core/Persistence/Mappers/UserGroupMapper.cs index 82f362b6f4..69386063db 100644 --- a/src/Umbraco.Core/Persistence/Mappers/UserTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/UserGroupMapper.cs @@ -1,44 +1,41 @@ -using System; -using System.Collections.Concurrent; -using System.Linq.Expressions; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Models.Rdbms; - -namespace Umbraco.Core.Persistence.Mappers -{ - /// - /// Represents a to DTO mapper used to translate the properties of the public api - /// implementation to that of the database's DTO as sql: [tableName].[columnName]. - /// - [MapperFor(typeof(IUserType))] - [MapperFor(typeof(UserType))] - public sealed class UserTypeMapper : BaseMapper - { - private static readonly ConcurrentDictionary PropertyInfoCacheInstance = new ConcurrentDictionary(); - - //NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it - // otherwise that would fail because there is no public constructor. - public UserTypeMapper() - { - BuildMap(); - } - - #region Overrides of BaseMapper - - internal override ConcurrentDictionary PropertyInfoCache - { - get { return PropertyInfoCacheInstance; } - } - - internal override void BuildMap() - { - CacheMap(src => src.Id, dto => dto.Id); - CacheMap(src => src.Alias, dto => dto.Alias); - CacheMap(src => src.Name, dto => dto.Name); - CacheMap(src => src.Permissions, dto => dto.DefaultPermissions); - } - - - #endregion - } +using System.Collections.Concurrent; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Mappers +{ + /// + /// Represents a to DTO mapper used to translate the properties of the public api + /// implementation to that of the database's DTO as sql: [tableName].[columnName]. + /// + [MapperFor(typeof(IUserGroup))] + [MapperFor(typeof(UserGroup))] + public sealed class UserGroupMapper : BaseMapper + { + private static readonly ConcurrentDictionary PropertyInfoCacheInstance = new ConcurrentDictionary(); + + //NOTE: its an internal class but the ctor must be public since we're using Activator.CreateInstance to create it + // otherwise that would fail because there is no public constructor. + public UserGroupMapper() + { + BuildMap(); + } + + #region Overrides of BaseMapper + + internal override ConcurrentDictionary PropertyInfoCache + { + get { return PropertyInfoCacheInstance; } + } + + internal override void BuildMap() + { + CacheMap(src => src.Id, dto => dto.Id); + CacheMap(src => src.Alias, dto => dto.Alias); + CacheMap(src => src.Name, dto => dto.Name); + CacheMap(src => src.Permissions, dto => dto.DefaultPermissions); + } + + #endregion + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs b/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs index 0ffd6cbfe1..baefd56db5 100644 --- a/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs @@ -69,7 +69,6 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.StartContentId, dto => dto.ContentStartId); CacheMap(src => src.IsApproved, dto => dto.Disabled); CacheMap(src => src.IsLockedOut, dto => dto.NoConsole); - CacheMap(src => src.UserType, dto => dto.Type); CacheMap(src => src.Language, dto => dto.UserLanguage); } diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 002af11611..dbf66cebdd 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -48,14 +48,19 @@ namespace Umbraco.Core.Persistence.Migrations.Initial CreateUmbracoUserData(); } - if (tableName.Equals("umbracoUserType")) + if (tableName.Equals("umbracoUserGroup")) { - CreateUmbracoUserTypeData(); + CreateUmbracoUserGroupData(); } - if (tableName.Equals("umbracoUser2app")) + if (tableName.Equals("umbracoUser2UserGroup")) { - CreateUmbracoUser2AppData(); + CreateUmbracoUser2UserGroupData(); + } + + if (tableName.Equals("umbracoUserGroup2App")) + { + CreateUmbracooUserGroup2AppData(); } if (tableName.Equals("cmsPropertyTypeGroup")) @@ -164,29 +169,37 @@ namespace Umbraco.Core.Persistence.Migrations.Initial private void CreateUmbracoUserData() { - _database.Insert("umbracoUser", "id", false, new UserDto { Id = 0, Disabled = false, NoConsole = false, Type = 1, ContentStartId = -1, MediaStartId = -1, UserName = "Administrator", Login = "admin", Password = "default", Email = "", UserLanguage = "en" }); + _database.Insert("umbracoUser", "id", false, new UserDto { Id = 0, Disabled = false, NoConsole = false, ContentStartId = -1, MediaStartId = -1, UserName = "Administrator", Login = "admin", Password = "default", Email = "", UserLanguage = "en" }); //_database.Update("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" }); } - private void CreateUmbracoUserTypeData() + private void CreateUmbracoUserGroupData() { - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7" }); - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 2, Alias = "writer", Name = "Writer", DefaultPermissions = "CAH:F" }); - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 3, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5F" }); - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 4, Alias = "translator", Name = "Translator", DefaultPermissions = "AF" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 2, Alias = "writer", Name = "Writers", DefaultPermissions = "CAH:F" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 3, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5F" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 4, Alias = "translator", Name = "Translators", DefaultPermissions = "AF" }); } - private void CreateUmbracoUser2AppData() + private void CreateUmbracoUser2UserGroupData() { - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Content }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Developer }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Media }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Members }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Settings }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Users }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Forms }); + _database.Insert(new User2UserGroupDto { UserGroupId = 1, UserId = 0 }); } - + + private void CreateUmbracooUserGroup2AppData() + { + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Content }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Media }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Settings }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Developer }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Users }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Members }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 2, AppAlias = Constants.Applications.Content }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Content }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Media }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 4, AppAlias = Constants.Applications.Translation }); + } + private void CreateCmsPropertyTypeGroupData() { _database.Insert("cmsPropertyTypeGroup", "id", false, new PropertyTypeGroupDto { Id = 3, ContentTypeNodeId = 1032, Text = "Image", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.Image) }); diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs index 83ae1de7e1..609087c4bc 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs @@ -67,15 +67,15 @@ namespace Umbraco.Core.Persistence.Migrations.Initial {28, typeof (TagDto)}, {29, typeof (TagRelationshipDto)}, - {31, typeof (UserTypeDto)}, + // Removed in 7.6 {31, typeof (UserTypeDto)}, {32, typeof (UserDto)}, {33, typeof (TaskTypeDto)}, {34, typeof (TaskDto)}, {35, typeof (ContentType2ContentTypeDto)}, {36, typeof (ContentTypeAllowedContentTypeDto)}, - {37, typeof (User2AppDto)}, + // Removed in 7.6 {37, typeof (User2AppDto)}, {38, typeof (User2NodeNotifyDto)}, - {39, typeof (User2NodePermissionDto)}, + // Removed in 7.6 {39, typeof (User2NodePermissionDto)}, {40, typeof (ServerRegistrationDto)}, {41, typeof (AccessDto)}, {42, typeof (AccessRuleDto)}, @@ -86,6 +86,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial //47, removed: UmbracoDeployDependencyDto {48, typeof (RedirectUrlDto) }, {49, typeof (LockDto) } + {49, typeof (UserGroupDto) }, + {50, typeof (User2UserGroupDto) }, + {51, typeof (UserGroup2NodePermissionDto) }, + {52, typeof (UserGroup2AppDto) }, }; #endregion diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenSixZero/AddUserGroupTables.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenSixZero/AddUserGroupTables.cs new file mode 100644 index 0000000000..ea566c0238 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenSixZero/AddUserGroupTables.cs @@ -0,0 +1,194 @@ +using System; +using System.Linq; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.SqlSyntax; +using System.Data; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero +{ + [Migration("7.6.0", 100, GlobalSettings.UmbracoMigrationName)] + public class AddUserGroupTables : MigrationBase + { + public AddUserGroupTables(ISqlSyntaxProvider sqlSyntax, ILogger logger) + : base(sqlSyntax, logger) + { } + + public override void Up() + { + var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray(); + var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); + + AddNewTables(tables); + MigrateUserPermissions(); + MigrateUserTypesToGroups(); + DeleteOldTables(tables, constraints); + } + + private void AddNewTables(string[] tables) + { + if (tables.InvariantContains("umbracoUserGroup") == false) + { + Create.Table("umbracoUserGroup") + .WithColumn("id").AsInt32().Identity().PrimaryKey("PK_umbracoUserGroup") + .WithColumn("userGroupAlias").AsString(200).NotNullable() + .WithColumn("userGroupName").AsString(200).NotNullable() + .WithColumn("userGroupDefaultPermissions").AsString(50).Nullable(); + } + + if (tables.InvariantContains("umbracoUser2UserGroup") == false) + { + Create.Table("umbracoUser2UserGroup") + .WithColumn("userId").AsInt32().NotNullable() + .WithColumn("userGroupId").AsInt32().NotNullable(); + Create.PrimaryKey("PK_user2userGroup") + .OnTable("umbracoUser2UserGroup") + .Columns(new[] {"userId", "userGroupId"}); + Create.ForeignKey("FK_umbracoUser2UserGroup_userId") + .FromTable("umbracoUser2UserGroup").ForeignColumn("userId") + .ToTable("umbracoUser").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); + Create.ForeignKey("FK_umbracoUser2UserGroup_userGroupId") + .FromTable("umbracoUser2UserGroup").ForeignColumn("userGroupId") + .ToTable("umbracoUserGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); + } + + if (tables.InvariantContains("umbracoUserGroup2App") == false) + { + Create.Table("umbracoUserGroup2App") + .WithColumn("userGroupId").AsInt32().NotNullable() + .WithColumn("app").AsString(50).NotNullable(); + Create.PrimaryKey("PK_userGroup2App") + .OnTable("umbracoUserGroup2App") + .Columns(new[] {"userGroupId", "app"}); + Create.ForeignKey("FK_umbracoUserGroup2App_umbracoGroupUser_id") + .FromTable("umbracoUserGroup2App").ForeignColumn("userGroupId") + .ToTable("umbracoUserGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); + } + + if (tables.InvariantContains("umbracoUserGroup2NodePermission") == false) + { + Create.Table("umbracoUserGroup2NodePermission") + .WithColumn("userGroupId").AsInt32().NotNullable() + .WithColumn("nodeId").AsInt32().NotNullable() + .WithColumn("permission").AsString(10).NotNullable(); + Create.PrimaryKey("PK_umbracoUserGroup2NodePermission") + .OnTable("umbracoUserGroup2NodePermission") + .Columns(new[] {"userGroupId", "nodeId", "permission"}); + Create.ForeignKey("FK_umbracoUserGroup2NodePermission_umbracoNode_id") + .FromTable("umbracoUserGroup2NodePermission").ForeignColumn("nodeId") + .ToTable("umbracoNode").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); + Create.ForeignKey("FK_umbracoUserGroup2NodePermission_umbracoUserGroup_id") + .FromTable("umbracoUserGroup2NodePermission").ForeignColumn("userGroupId") + .ToTable("umbracoUserGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); + } + } + + private void MigrateUserTypesToGroups() + { + // TODO: review for MySQL and CE (tested only on SQL Express) + + // Create a user group for each user type + Execute.Sql(@"INSERT INTO umbracoUserGroup (userGroupAlias, userGroupName, userGroupDefaultPermissions) + SELECT userTypeAlias, userTypeName, userTypeDefaultPermissions + FROM umbracoUserType"); + + // Add each user to the group created from their type + Execute.Sql(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId) + SELECT u.id,( + SELECT ug.id + FROM umbracoUserGroup ug + INNER JOIN umbracoUserType ut ON ut.userTypeAlias = ug.userGroupAlias + WHERE u.userType = ut.id + ) + FROM umbracoUser u"); + + // Add the built-in administrator account to all apps + Execute.Sql(@"INSERT INTO umbracoUserGroup2app (userGroupId,app) + SELECT ug.id, app + FROM umbracoUserGroup ug + INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id + INNER JOIN umbracoUser u ON u.id = u2ug.userId + INNER JOIN umbracoUser2app u2a ON u2a.[user] = u.id + WHERE u.id = 0"); + + // Rename some groups for consistency (plural form) + Execute.Sql("UPDATE umbracoUserGroup SET userGroupName = 'Writers' WHERE userGroupName = 'Writer'"); + Execute.Sql("UPDATE umbracoUserGroup SET userGroupName = 'Translators' WHERE userGroupName = 'Translator'"); + } + + private void MigrateUserPermissions() + { + // TODO: review for MySQL and CE (tested only on SQL Express) + + // Create user group records for all non-admin users that have specific permissions set + Execute.Sql(@"INSERT INTO umbracoUserGroup(userGroupAlias, userGroupName) + SELECT userName + 'Group', 'Group for ' + userName + FROM umbracoUser + WHERE (id IN ( + SELECT [user] + FROM umbracoUser2app + ) OR id IN ( + SELECT userid + FROM umbracoUser2NodePermission + )) + AND id > 0"); + + // Associate those groups with the users + Execute.Sql(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId) + SELECT u.id, ug.id + FROM umbracoUser u + INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias = userName + 'Group'"); + + // Create node permissions on the groups + Execute.Sql(@"INSERT INTO umbracoUserGroup2NodePermission (userGroupId,nodeId,permission) + SELECT ug.id, nodeId, permission + FROM umbracoUserGroup ug + INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id + INNER JOIN umbracoUser u ON u.id = u2ug.userId + INNER JOIN umbracoUser2NodePermission u2np ON u2np.userId = u.id + WHERE ug.userGroupAlias NOT IN ( + SELECT userTypeAlias + FROM umbracoUserType + )"); + + // Create app permissions on the groups + Execute.Sql(@"INSERT INTO umbracoUserGroup2app (userGroupId,app) + SELECT ug.id, app + FROM umbracoUserGroup ug + INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id + INNER JOIN umbracoUser u ON u.id = u2ug.userId + INNER JOIN umbracoUser2app u2a ON u2a.[user] = u.id + WHERE ug.userGroupAlias NOT IN ( + SELECT userTypeAlias + FROM umbracoUserType + )"); + } + + private void DeleteOldTables(string[] tables, Tuple[] constraints) + { + if (tables.InvariantContains("umbracoUser2App")) + { + Delete.Table("umbracoUser2App"); + } + + if (tables.InvariantContains("umbracoUser2NodePermission")) + { + Delete.Table("umbracoUser2NodePermission"); + } + + if (tables.InvariantContains("umbracoUserType") && tables.InvariantContains("umbracoUser")) + { + if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id"))) + { + Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser"); + } + + Delete.Column("userType").FromTable("umbracoUser"); + Delete.Table("umbracoUserType"); + } + } + + public override void Down() + { } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Relators/UserSectionRelator.cs b/src/Umbraco.Core/Persistence/Relators/UserGroupSectionRelator.cs similarity index 60% rename from src/Umbraco.Core/Persistence/Relators/UserSectionRelator.cs rename to src/Umbraco.Core/Persistence/Relators/UserGroupSectionRelator.cs index 923348e729..03c5bcd398 100644 --- a/src/Umbraco.Core/Persistence/Relators/UserSectionRelator.cs +++ b/src/Umbraco.Core/Persistence/Relators/UserGroupSectionRelator.cs @@ -1,50 +1,50 @@ -using System.Collections.Generic; -using Umbraco.Core.Models.Rdbms; - -namespace Umbraco.Core.Persistence.Relators -{ - internal class UserSectionRelator - { - internal UserDto Current; - - internal UserDto Map(UserDto a, User2AppDto p) - { - // Terminating call. Since we can return null from this function - // we need to be ready for PetaPoco to callback later with null - // parameters - if (a == null) - return Current; - - // Is this the same DictionaryItem as the current one we're processing - if (Current != null && Current.Id == a.Id) - { - if (p.AppAlias.IsNullOrWhiteSpace() == false) - { - // Yes, just add this User2AppDto to the current item's collection - Current.User2AppDtos.Add(p); - } - - // Return null to indicate we're not done with this User yet - return null; - } - - // This is a different User to the current one, or this is the - // first time through and we don't have one yet - - // Save the current User - var prev = Current; - - // Setup the new current User - Current = a; - Current.User2AppDtos = new List(); - //this can be null since we are doing a left join - if (p.AppAlias.IsNullOrWhiteSpace() == false) - { - Current.User2AppDtos.Add(p); - } - - // Return the now populated previous User (or null if first time through) - return prev; - } - } +using System.Collections.Generic; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Relators +{ + internal class UserGroupSectionRelator + { + internal UserGroupDto Current; + + internal UserGroupDto Map(UserGroupDto a, UserGroup2AppDto p) + { + // Terminating call. Since we can return null from this function + // we need to be ready for PetaPoco to callback later with null + // parameters + if (a == null) + return Current; + + // Is this the same DictionaryItem as the current one we're processing + if (Current != null && Current.Id == a.Id) + { + if (p.AppAlias.IsNullOrWhiteSpace() == false) + { + // Yes, just add this UserGroup2AppDto to the current item's collection + Current.UserGroup2AppDtos.Add(p); + } + + // Return null to indicate we're not done with this User yet + return null; + } + + // This is a different user group to the current one, or this is the + // first time through and we don't have one yet + + // Save the current user group + var prev = Current; + + // Setup the new current user group + Current = a; + Current.UserGroup2AppDtos = new List(); + //this can be null since we are doing a left join + if (p.AppAlias.IsNullOrWhiteSpace() == false) + { + Current.UserGroup2AppDtos.Add(p); + } + + // Return the now populated previous user group (or null if first time through) + return prev; + } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index a34a77d3b4..81bf9c7b4f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -182,7 +182,7 @@ namespace Umbraco.Core.Persistence.Repositories "DELETE FROM umbracoRedirectUrl WHERE contentKey IN (SELECT uniqueID FROM umbracoNode WHERE id = @Id)", "DELETE FROM cmsTask WHERE nodeId = @Id", "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM umbracoRelation WHERE parentId = @Id", "DELETE FROM umbracoRelation WHERE childId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", @@ -456,12 +456,12 @@ namespace Umbraco.Core.Persistence.Repositories // user's default permissions. if (parentPermissions.Any()) { - var userPermissions = ( + var userGroupPermissions = ( from perm in parentPermissions from p in perm.AssignedPermissions - select new EntityPermissionSet.UserPermission(perm.UserId, p)).ToList(); + select new EntityPermissionSet.UserGroupPermission(perm.UserGroupId, p)).ToList(); - permissionsRepo.ReplaceEntityPermissions(new EntityPermissionSet(entity.Id, userPermissions)); + 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; @@ -837,18 +837,18 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder", } /// - /// Assigns a single permission to the current content item for the specified user ids + /// Assigns a single permission to the current content item for the specified user group ids /// /// /// - /// - public void AssignEntityPermission(IContent entity, char permission, IEnumerable userIds) + /// + public void AssignEntityPermission(IContent entity, char permission, IEnumerable groupIds) { var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); - repo.AssignEntityPermission(entity, permission, userIds); + repo.AssignEntityPermission(entity, permission, groupIds); } - public IEnumerable GetPermissionsForEntity(int entityId) + public IEnumerable GetPermissionsForEntity(int entityId) { var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); return repo.GetPermissionsForEntity(entityId); diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs index 985f9446b7..ddaa6aae39 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs @@ -135,7 +135,7 @@ namespace Umbraco.Core.Persistence.Repositories var list = new List { "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", "DELETE FROM cmsContentTypeAllowedContentType WHERE Id = @Id", "DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs index 1690b36148..6fd4c8f906 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs @@ -248,7 +248,7 @@ AND umbracoNode.id <> @id", Database.Delete("WHERE nodeId = @Id", new { Id = entity.Id }); //Remove Permissions - Database.Delete("WHERE nodeId = @Id", new { Id = entity.Id }); + Database.Delete("WHERE nodeId = @Id", new { Id = entity.Id }); //Remove associated tags Database.Delete("WHERE nodeId = @Id", new { Id = entity.Id }); diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs index e04608e9c6..799df877a1 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs @@ -49,19 +49,19 @@ namespace Umbraco.Core.Persistence.Repositories IEnumerable GetByPublishedVersion(IQuery query); /// - /// Assigns a single permission to the current content item for the specified user ids + /// Assigns a single permission to the current content item for the specified user group ids /// /// /// - /// - void AssignEntityPermission(IContent entity, char permission, IEnumerable userIds); + /// + void AssignEntityPermission(IContent entity, char permission, IEnumerable groupIds); /// /// Gets the list of permissions for the content item /// /// /// - IEnumerable GetPermissionsForEntity(int entityId); + IEnumerable GetPermissionsForEntity(int entityId); /// /// Used to add/update published xml for the content item diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs new file mode 100644 index 0000000000..45abdc70b4 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserGroupRepository.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using Umbraco.Core.Models.Membership; + +namespace Umbraco.Core.Persistence.Repositories +{ + public interface IUserGroupRepository : IRepositoryQueryable + { + /// + /// This is useful when an entire section is removed from config + /// + /// + IEnumerable GetGroupsAssignedToSection(string sectionAlias); + + /// + /// Removes all users from a group + /// + /// Id of group + void RemoveAllUsersFromGroup(int groupId); + + /// + /// Adds a set of users to a group + /// + /// Id of group + /// Ids of users + void AddUsersToGroup(int groupId, int[] userIds); + + /// + /// Gets the group permissions for the specified entities + /// + /// Id of group + /// Array of entity Ids + IEnumerable GetPermissionsForEntities(int groupId, params int[] entityIds); + + /// + /// Replaces the same permission set for a single group to any number of entities + /// + /// Id of group + /// Permissions as enumerable list of + /// Specify the nodes to replace permissions for. If nothing is specified all permissions are removed. + void ReplaceGroupPermissions(int groupId, IEnumerable permissions, params int[] entityIds); + + /// + /// Assigns the same permission set for a single group to any number of entities + /// + /// Id of group + /// Permissions as enumerable list of + /// Specify the nodes to replace permissions for + void AssignGroupPermission(int groupId, char permission, params int[] entityIds); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs index 542cceac40..620350f563 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserRepository.cs @@ -23,10 +23,23 @@ namespace Umbraco.Core.Persistence.Repositories bool Exists(string username); /// - /// This is useful when an entire section is removed from config + /// Gets all groups for a given user /// - /// - IEnumerable GetUsersAssignedToSection(string sectionAlias); + /// Id of user + /// An enumerable list of + IEnumerable GetGroupsForUser(int userId); + + /// + /// Gets a list of objects associated with a given group + /// + /// Id of group + IEnumerable GetAllInGroup(int groupId); + + /// + /// Gets a list of objects not associated with a given group + /// + /// Id of group + IEnumerable GetAllNotInGroup(int groupId); /// /// Gets paged member results @@ -38,30 +51,5 @@ namespace Umbraco.Core.Persistence.Repositories /// /// IEnumerable GetPagedResultsByQuery(IQuery query, int pageIndex, int pageSize, out int totalRecords, Expression> orderBy); - - - /// - /// Gets the user permissions for the specified entities - /// - /// - /// - /// - IEnumerable GetUserPermissionsForEntities(int userId, params int[] entityIds); - - /// - /// Replaces the same permission set for a single user to any number of entities - /// - /// - /// - /// - void ReplaceUserPermissions(int userId, IEnumerable permissions, params int[] entityIds); - - /// - /// Assigns the same permission set for a single user to any number of entities - /// - /// - /// - /// - void AssignUserPermission(int userId, char permission, params int[] entityIds); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserTypeRepository.cs deleted file mode 100644 index 43b6709aa7..0000000000 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserTypeRepository.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Umbraco.Core.Models.Membership; - -namespace Umbraco.Core.Persistence.Repositories -{ - public interface IUserTypeRepository : IRepositoryQueryable - { - - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index c9f06c6c75..9b33a62c2d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -117,7 +117,7 @@ namespace Umbraco.Core.Persistence.Repositories { "DELETE FROM cmsTask WHERE nodeId = @Id", "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM umbracoRelation WHERE parentId = @Id", "DELETE FROM umbracoRelation WHERE childId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs index 11542673be..6ac920d6d9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs @@ -101,7 +101,7 @@ namespace Umbraco.Core.Persistence.Repositories var list = new List { "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", "DELETE FROM cmsContentTypeAllowedContentType WHERE Id = @Id", "DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs index e9438b56f6..9e29cf0d83 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs @@ -88,7 +88,7 @@ namespace Umbraco.Core.Persistence.Repositories var list = new[] { "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM umbracoRelation WHERE parentId = @Id", "DELETE FROM umbracoRelation WHERE childId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs index 2ef795282b..00d77c8c13 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs @@ -160,7 +160,7 @@ namespace Umbraco.Core.Persistence.Repositories { "DELETE FROM cmsTask WHERE nodeId = @Id", "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM umbracoRelation WHERE parentId = @Id", "DELETE FROM umbracoRelation WHERE childId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs index 8d489644b5..5865878aa9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs @@ -128,7 +128,7 @@ namespace Umbraco.Core.Persistence.Repositories var list = new List { "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", "DELETE FROM cmsContentTypeAllowedContentType WHERE Id = @Id", "DELETE FROM cmsContentTypeAllowedContentType WHERE AllowedId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs index 3d6acb777b..5cbffdeee5 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -15,6 +15,15 @@ using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Services; using CacheKeys = Umbraco.Core.Cache.CacheKeys; using Umbraco.Core.Cache; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Persistence.Repositories { @@ -38,112 +47,148 @@ namespace Umbraco.Core.Persistence.Repositories } /// - /// Returns permissions for a given user for any number of nodes + /// Returns permissions for a given group for any number of nodes /// - /// + /// /// /// - public IEnumerable GetUserPermissionsForEntities(int userId, params int[] entityIds) + public IEnumerable GetPermissionsForEntities(int groupId, params int[] entityIds) { - var entityIdKey = string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture))); + var entityIdKey = GetEntityIdKey(entityIds); return _runtimeCache.GetCacheItem>( - string.Format("{0}{1}{2}", CacheKeys.UserPermissionsCacheKey, userId, entityIdKey), + string.Format("{0}{1}{2}", + CacheKeys.UserGroupPermissionsCacheKey, + groupId, + entityIdKey), () => - { - - var whereBuilder = new StringBuilder(); - - //where userId = @userId AND - whereBuilder.Append(_sqlSyntax.GetQuotedColumnName("userId")); - whereBuilder.Append("="); - whereBuilder.Append(userId); - - if (entityIds.Any()) - { - whereBuilder.Append(" AND "); - - //where nodeId = @nodeId1 OR nodeId = @nodeId2, etc... - whereBuilder.Append("("); - for (var index = 0; index < entityIds.Length; index++) - { - var entityId = entityIds[index]; - whereBuilder.Append(_sqlSyntax.GetQuotedColumnName("nodeId")); - whereBuilder.Append("="); - whereBuilder.Append(entityId); - if (index < entityIds.Length - 1) - { - whereBuilder.Append(" OR "); - } - } - whereBuilder.Append(")"); - } - + { + var whereCriteria = GetPermissionsForEntitiesCriteria(groupId, entityIds); var sql = new Sql(); sql.Select("*") - .From() - .Where(whereBuilder.ToString()); - - //ToArray() to ensure it's all fetched from the db once. - var result = _unitOfWork.Database.Fetch(sql).ToArray(); + .From() + .Where(whereCriteria); + var result = _unitOfWork.Database.Fetch(sql).ToArray(); + // ToArray() to ensure it's all fetched from the db once return ConvertToPermissionList(result); - }, - //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. - new TimeSpan(0, 20, 0), - //Since this cache can be quite large (http://issues.umbraco.org/issue/U4-2161) we will make this priority below average - priority: CacheItemPriority.BelowNormal); + GetCacheTimeout(), + priority: GetCachePriority()); + } - } + 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()) + { + whereBuilder.Append(" AND "); + + //where nodeId = @nodeId1 OR nodeId = @nodeId2, etc... + whereBuilder.Append("("); + for (var index = 0; index < entityIds.Length; index++) + { + var entityId = entityIds[index]; + whereBuilder.Append(_sqlSyntax.GetQuotedColumnName("nodeId")); + whereBuilder.Append("="); + whereBuilder.Append(entityId); + if (index < entityIds.Length - 1) + { + whereBuilder.Append(" OR "); + } + } + + 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 ConvertToPermissionList(IEnumerable result) + { + var permissions = new List(); + var nodePermissions = result.GroupBy(x => x.NodeId); + foreach (var np in nodePermissions) + { + var userGroupPermissions = np.GroupBy(x => x.UserGroupId); + foreach (var permission in userGroupPermissions) + { + var perms = permission.Select(x => x.Permission).ToArray(); + permissions.Add(new UserGroupEntityPermission(permission.Key, permission.First().NodeId, perms)); + } + } + + return permissions; + } /// - /// Returns permissions for all users for a given entity + /// Returns permissions for all groups for a given entity /// /// /// - public IEnumerable GetPermissionsForEntity(int entityId) + public IEnumerable GetPermissionsForEntity(int entityId) { var sql = new Sql(); sql.Select("*") - .From() - .Where(dto => dto.NodeId == entityId) - .OrderBy(dto => dto.NodeId); + .From() + .Where(dto => dto.NodeId == entityId) + .OrderBy(dto => dto.NodeId); - //ToArray() to ensure it's all fetched from the db once. - var result = _unitOfWork.Database.Fetch(sql).ToArray(); + var result = _unitOfWork.Database.Fetch(sql).ToArray(); + // ToArray() to ensure it's all fetched from the db once return ConvertToPermissionList(result); } /// - /// Assigns the same permission set for a single user to any number of entities + /// Assigns the same permission set for a single group to any number of entities /// - /// + /// /// /// /// /// This will first clear the permissions for this user and entities and recreate them /// - public void ReplaceUserPermissions(int userId, IEnumerable permissions, params int[] entityIds) + public void ReplacePermissions(int groupId, IEnumerable permissions, params int[] entityIds) { 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)"; foreach (var idGroup in entityIds.InGroupsOf(2000)) { - db.Execute("DELETE FROM umbracoUser2NodePermission WHERE userId=@userId AND nodeId in (@nodeIds)", - new { userId = userId, nodeIds = idGroup }); + db.Execute(sql, new {groupId = groupId, nodeIds = idGroup}); } - var toInsert = new List(); + var toInsert = new List(); foreach (var p in permissions) { foreach (var e in entityIds) { - toInsert.Add(new User2NodePermissionDto + toInsert.Add(new UserGroup2NodePermissionDto { NodeId = e, Permission = p.ToString(CultureInfo.InvariantCulture), - UserId = userId + UserGroupId = groupId }); } } @@ -151,67 +196,81 @@ namespace Umbraco.Core.Persistence.Repositories _unitOfWork.Database.BulkInsertRecords(toInsert, _sqlSyntax); //Raise the event + //TODO: FIX THIS _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(toInsert), false)); + AssignedPermissions.RaiseEvent( + new SaveEventArgs(ConvertToPermissionList(toInsert), false), this) + } /// /// Assigns one permission for a user to many entities /// - /// + /// /// /// - public void AssignUserPermission(int userId, char permission, params int[] entityIds) + public void AssignPermission(int groupId, char permission, params int[] entityIds) { var db = _unitOfWork.Database; - db.Execute("DELETE FROM umbracoUser2NodePermission WHERE userId=@userId AND permission=@permission AND nodeId in (@entityIds)", + var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE userGroupId = @groupId AND permission=@permission AND nodeId in (@entityIds)"; + db.Execute(sql, new { - userId = userId, + groupId = groupId, permission = permission.ToString(CultureInfo.InvariantCulture), entityIds = entityIds }); - var actions = entityIds.Select(id => new User2NodePermissionDto + var actions = entityIds.Select(id => new UserGroup2NodePermissionDto { NodeId = id, Permission = permission.ToString(CultureInfo.InvariantCulture), - UserId = userId + UserGroupId = groupId }).ToArray(); _unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax); //Raise the event + //TODO: Fix this _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false)); - } + AssignedPermissions.RaiseEvent( + new SaveEventArgs(ConvertToPermissionList(actions), false), this) + + } /// - /// Assigns one permission to an entity for multiple users + /// Assigns one permission to an entity for multiple groups /// /// /// - /// - public void AssignEntityPermission(TEntity entity, char permission, IEnumerable userIds) + /// + public void AssignEntityPermission(TEntity entity, char permission, IEnumerable groupIds) { var db = _unitOfWork.Database; - db.Execute("DELETE FROM umbracoUser2NodePermission WHERE nodeId=@nodeId AND permission=@permission AND userId in (@userIds)", + var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @nodeId AND permission = @permission AND userGroupId in (@groupIds)"; + db.Execute(sql, new { nodeId = entity.Id, permission = permission.ToString(CultureInfo.InvariantCulture), - userIds = userIds + groupIds = groupIds }); - var actions = userIds.Select(id => new User2NodePermissionDto + var actions = groupIds.Select(id => new UserGroup2NodePermissionDto { NodeId = entity.Id, Permission = permission.ToString(CultureInfo.InvariantCulture), - UserId = id + UserGroupId = id }).ToArray(); _unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax); //Raise the event + //TODO: Fix this _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false)); + AssignedPermissions.RaiseEvent( + new SaveEventArgs(ConvertToPermissionList(actions), false), this) + } /// @@ -225,37 +284,27 @@ namespace Umbraco.Core.Persistence.Repositories public void ReplaceEntityPermissions(EntityPermissionSet permissionSet) { var db = _unitOfWork.Database; - db.Execute("DELETE FROM umbracoUser2NodePermission WHERE nodeId=@nodeId", new { nodeId = permissionSet.EntityId }); + var sql = "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @nodeId"; + db.Execute(sql, new {nodeId = permissionSet.EntityId}); - var actions = permissionSet.UserPermissionsSet.Select(p => new User2NodePermissionDto + var actions = permissionSet.PermissionsSet.Select(p => new UserGroup2NodePermissionDto { NodeId = permissionSet.EntityId, Permission = p.Permission, - UserId = p.UserId + UserGroupId = p.UserGroupId }).ToArray(); _unitOfWork.Database.BulkInsertRecords(actions, _sqlSyntax); //Raise the event + //TODO: Fix this _unitOfWork.Events.Dispatch(AssignedPermissions, this, new SaveEventArgs(ConvertToPermissionList(actions), false)); - } + AssignedPermissions.RaiseEvent( + new SaveEventArgs(ConvertToPermissionList(actions), false), this) - private static IEnumerable ConvertToPermissionList(IEnumerable result) - { - var permissions = new List(); - var nodePermissions = result.GroupBy(x => x.NodeId); - foreach (var np in nodePermissions) - { - var userPermissions = np.GroupBy(x => x.UserId); - foreach (var up in userPermissions) - { - var perms = up.Select(x => x.Permission).ToArray(); - permissions.Add(new EntityPermission(up.Key, up.First().NodeId, perms)); - } } - return permissions; } - public static event TypedEventHandler, SaveEventArgs> AssignedPermissions; + public static event TypedEventHandler, SaveEventArgs> AssignedPermissions; } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs b/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs index cb5f7c8810..b94bb47ff8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs @@ -43,7 +43,7 @@ namespace Umbraco.Core.Persistence.Repositories var deletes = new List { FormatDeleteStatement("umbracoUser2NodeNotify", "nodeId"), - FormatDeleteStatement("umbracoUser2NodePermission", "nodeId"), + FormatDeleteStatement("umbracoUserGroup2NodePermission", "nodeId"), @"DELETE FROM umbracoAccessRule WHERE umbracoAccessRule.accessId IN ( SELECT TB1.id FROM umbracoAccess as TB1 INNER JOIN umbracoNode as TB2 ON TB1.nodeId = TB2.id diff --git a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs index 7f265aceb7..2c49965d11 100644 --- a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs @@ -126,7 +126,7 @@ namespace Umbraco.Core.Persistence.Repositories var list = new List { "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE nodeId = @Id", "UPDATE cmsDocument SET templateId = NULL WHERE templateId = @Id", "DELETE FROM cmsDocumentType WHERE templateNodeId = @Id", "DELETE FROM cmsTemplate WHERE nodeId = @Id", diff --git a/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs new file mode 100644 index 0000000000..d214c0d555 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/UserGroupRepository.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.Factories; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.Relators; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Persistence.UnitOfWork; + +namespace Umbraco.Core.Persistence.Repositories +{ + /// + /// Represents the UserGroupRepository for doing CRUD operations for + /// + internal class UserGroupRepository : PetaPocoRepositoryBase, IUserGroupRepository + { + private readonly CacheHelper _cacheHelper; + + public UserGroupRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax) + : base(work, cacheHelper, logger, sqlSyntax) + { + _cacheHelper = cacheHelper; + } + + public IEnumerable GetGroupsAssignedToSection(string sectionAlias) + { + //Here we're building up a query that looks like this, a sub query is required because the resulting structure + // needs to still contain all of the section rows per user group. + + //SELECT * + //FROM [umbracoUserGroup] + //LEFT JOIN [umbracoUserGroup2App] + //ON [umbracoUserGroup].[id] = [umbracoUserGroup2App].[user] + //WHERE umbracoUserGroup.id IN (SELECT umbracoUserGroup.id + // FROM [umbracoUserGroup] + // LEFT JOIN [umbracoUserGroup2App] + // ON [umbracoUserGroup].[id] = [umbracoUserGroup2App].[user] + // WHERE umbracoUserGroup2App.app = 'content') + + var sql = GetBaseQuery(false); + var innerSql = GetBaseQuery("umbracoUserGroup.id"); + innerSql.Where("umbracoUserGroup2App.app = " + SqlSyntax.GetQuotedValue(sectionAlias)); + sql.Where(string.Format("umbracoUserGroup.id IN ({0})", innerSql.SQL)); + + return ConvertFromDtos(Database.Fetch(new UserGroupSectionRelator().Map, sql)); + } + + /// + /// Removes all users from a group + /// + /// Id of group + public void RemoveAllUsersFromGroup(int groupId) + { + Database.Delete("WHERE userGroupId = @GroupId", new { GroupId = groupId }); + } + + /// + /// Adds a set of users to a group + /// + /// Id of group + /// Ids of users + public void AddUsersToGroup(int groupId, int[] userIds) + { + foreach (var userId in userIds) + { + var dto = new User2UserGroupDto + { + UserGroupId = groupId, + UserId = userId, + }; + Database.Insert(dto); + } + } + + /// + /// Gets the group permissions for the specified entities + /// + /// Id of group + /// Array of entity Ids + public IEnumerable GetPermissionsForEntities(int groupId, params int[] entityIds) + { + var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); + return repo.GetPermissionsForEntities(groupId, entityIds); + } + + /// + /// Replaces the same permission set for a single group to any number of entities + /// + /// Id of group + /// Permissions as enumerable list of + /// Specify the nodes to replace permissions for. If nothing is specified all permissions are removed. + public void ReplaceGroupPermissions(int groupId, IEnumerable permissions, params int[] entityIds) + { + var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); + repo.ReplacePermissions(groupId, permissions, entityIds); + } + + /// + /// Assigns the same permission set for a single group to any number of entities + /// + /// Id of group + /// Permissions as enumerable list of + /// Specify the nodes to replace permissions for + public void AssignGroupPermission(int groupId, char permission, params int[] entityIds) + { + var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); + repo.AssignPermission(groupId, permission, entityIds); + } + + #region Overrides of RepositoryBase + + protected override IUserGroup PerformGet(int id) + { + var sql = GetBaseQuery(false); + sql.Where(GetBaseWhereClause(), new { Id = id }); + + var dto = Database.Fetch(new UserGroupSectionRelator().Map, sql).FirstOrDefault(); + + if (dto == null) + return null; + + var userGroupFactory = new UserGroupFactory(); + var userGroup = userGroupFactory.BuildEntity(dto); + return userGroup; + } + + protected override IEnumerable PerformGetAll(params int[] ids) + { + var sql = GetBaseQuery(false); + + if (ids.Any()) + { + sql.Where("umbracoUserGroup.id in (@ids)", new { ids = ids }); + } + else + { + sql.Where(x => x.Id >= 0); + } + + var dtos = Database.Fetch(new UserGroupSectionRelator().Map, sql); + return ConvertFromDtos(dtos); + } + + protected override IEnumerable PerformGetByQuery(IQuery query) + { + var userGroupFactory = new UserGroupFactory(); + var sqlClause = GetBaseQuery(false); + var translator = new SqlTranslator(sqlClause, query); + var sql = translator.Translate(); + + var dtos = Database.Fetch(new UserGroupSectionRelator().Map, sql); + return ConvertFromDtos(dtos); + } + + #endregion + + #region Overrides of PetaPocoRepositoryBase + + protected override Sql GetBaseQuery(bool isCount) + { + var sql = new Sql(); + if (isCount) + { + sql.Select("COUNT(*)").From(); + } + else + { + return GetBaseQuery("*"); + } + return sql; + } + + protected Sql GetBaseQuery(string columns) + { + var sql = new Sql(); + sql.Select(columns) + .From() + .LeftJoin() + .On(left => left.Id, right => right.UserGroupId); + + return sql; + } + + protected override string GetBaseWhereClause() + { + return "umbracoUserGroup.id = @Id"; + } + + protected override IEnumerable GetDeleteClauses() + { + var list = new List + { + "DELETE FROM umbracoUser2UserGroup WHERE userGroupId = @Id", + "DELETE FROM umbracoUserGroup2App WHERE userGroupId = @Id", + "DELETE FROM umbracoUserGroup2NodePermission WHERE userGroupId = @Id", + "DELETE FROM umbracoUserGroup WHERE id = @Id" + }; + return list; + } + + protected override Guid NodeObjectTypeId + { + get { throw new NotImplementedException(); } + } + + protected override void PersistNewItem(IUserGroup entity) + { + var userGroupFactory = new UserGroupFactory(); + var userGroupDto = userGroupFactory.BuildDto(entity); + + var id = Convert.ToInt32(Database.Insert(userGroupDto)); + entity.Id = id; + + PersistAllowedSections(entity); + } + + protected override void PersistUpdatedItem(IUserGroup entity) + { + var userGroupFactory = new UserGroupFactory(); + var userGroupDto = userGroupFactory.BuildDto(entity); + + Database.Update(userGroupDto); + + PersistAllowedSections(entity); + } + + private void PersistAllowedSections(IUserGroup entity) + { + var userGroup = (UserGroup)entity; + + // First delete all + Database.Delete("WHERE UserGroupId = @UserGroupId", + new { UserGroupId = userGroup.Id }); + + // Then re-add any associated with the group + foreach (var app in userGroup.AllowedSections) + { + var dto = new UserGroup2AppDto + { + UserGroupId = userGroup.Id, + AppAlias = app + }; + Database.Insert(dto); + } + } + + #endregion + + private IEnumerable ConvertFromDtos(IEnumerable dtos) + { + return dtos.Select(dto => + { + var userGroupFactory = new UserGroupFactory(); + return userGroupFactory.BuildEntity(dto); + }); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs index 10758be578..994c07d13e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs @@ -2,13 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using Umbraco.Core; using Umbraco.Core.Logging; -using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; - using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Querying; @@ -23,13 +20,11 @@ namespace Umbraco.Core.Persistence.Repositories /// internal class UserRepository : PetaPocoRepositoryBase, IUserRepository { - private readonly IUserTypeRepository _userTypeRepository; private readonly CacheHelper _cacheHelper; - public UserRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax, IUserTypeRepository userTypeRepository) + public UserRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax) : base(work, cacheHelper, logger, sqlSyntax) { - _userTypeRepository = userTypeRepository; _cacheHelper = cacheHelper; } @@ -42,18 +37,30 @@ namespace Umbraco.Core.Persistence.Repositories //must be sorted this way for the relator to work sql.OrderBy(x => x.Id, SqlSyntax); - var dto = Database.Fetch(new UserSectionRelator().Map, sql).FirstOrDefault(); + var dto = Database.Fetch(sql).FirstOrDefault(); if (dto == null) return null; - var userType = _userTypeRepository.Get(dto.Type); - var userFactory = new UserFactory(userType); + var userFactory = new UserFactory(); var user = userFactory.BuildEntity(dto); - + AssociateGroupsWithUser(user); return user; } + private void AssociateGroupsWithUser(IUser user) + { + if (user != null) + { + foreach (var group in GetGroupsForUser(user.Id)) + { + user.AddGroup(group); + } + + user.SetGroupsLoaded(); + } + } + protected override IEnumerable PerformGetAll(params int[] ids) { var sql = GetBaseQuery(false); @@ -66,8 +73,15 @@ namespace Umbraco.Core.Persistence.Repositories //must be sorted this way for the relator to work sql.OrderBy(x => x.Id, SqlSyntax); - return ConvertFromDtos(Database.Fetch(new UserSectionRelator().Map, sql)) - .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. + var users = ConvertFromDtos(Database.Fetch(sql)) + .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. + + foreach (var user in users) + { + AssociateGroupsWithUser(user); + } + + return users; } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -79,11 +93,18 @@ namespace Umbraco.Core.Persistence.Repositories //must be sorted this way for the relator to work sql.OrderBy(x => x.Id, SqlSyntax); - var dtos = Database.Fetch(new UserSectionRelator().Map, sql) + var dtos = Database.Fetch(sql) .DistinctBy(x => x.Id); - return ConvertFromDtos(dtos) - .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. + var users = ConvertFromDtos(dtos) + .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. + + foreach (var user in users) + { + AssociateGroupsWithUser(user); + } + + return users; } #endregion @@ -108,9 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories { var sql = new Sql(); sql.Select(columns) - .From() - .LeftJoin() - .On(left => left.Id, right => right.UserId); + .From(); return sql; } @@ -126,9 +145,8 @@ namespace Umbraco.Core.Persistence.Repositories { "DELETE FROM cmsTask WHERE userId = @Id", "DELETE FROM cmsTask WHERE parentUserId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE userId = @Id", + "DELETE FROM umbracoUser2UserGroup WHERE userId = @Id", "DELETE FROM umbracoUser2NodeNotify WHERE userId = @Id", - "DELETE FROM umbracoUser2app WHERE " + SqlSyntax.GetQuotedColumnName("user") + "=@Id", "DELETE FROM umbracoUser WHERE id = @Id", "DELETE FROM umbracoExternalLogin WHERE id = @Id" }; @@ -142,7 +160,7 @@ namespace Umbraco.Core.Persistence.Repositories protected override void PersistNewItem(IUser entity) { - var userFactory = new UserFactory(entity.UserType); + var userFactory = new UserFactory(); //ensure security stamp if non if (entity.SecurityStamp.IsNullOrWhiteSpace()) @@ -155,19 +173,12 @@ namespace Umbraco.Core.Persistence.Repositories var id = Convert.ToInt32(Database.Insert(userDto)); entity.Id = id; - foreach (var sectionDto in userDto.User2AppDtos) - { - //need to set the id explicitly here - sectionDto.UserId = id; - Database.Insert(sectionDto); - } - entity.ResetDirtyProperties(); } protected override void PersistUpdatedItem(IUser entity) { - var userFactory = new UserFactory(entity.UserType); + var userFactory = new UserFactory(); //ensure security stamp if non if (entity.SecurityStamp.IsNullOrWhiteSpace()) @@ -225,38 +236,23 @@ namespace Umbraco.Core.Persistence.Repositories { Database.Update(userDto, changedCols); } - - //update the sections if they've changed + + //update the groups var user = (User)entity; - if (user.IsPropertyDirty("AllowedSections")) + + //first delete all + Database.Delete("WHERE UserId = @UserId", + new { UserId = user.Id }); + + //then re-add any associated with the user + foreach (var group in user.Groups) { - //now we need to delete any applications that have been removed - foreach (var section in user.RemovedSections) + var dto = new User2UserGroupDto { - //we need to manually delete thsi record because it has a composite key - Database.Delete("WHERE app=@Section AND " + SqlSyntax.GetQuotedColumnName("user") + "=@UserId", - new { Section = section, UserId = (int)user.Id }); - } - - //for any that exist on the object, we need to determine if we need to update or insert - //NOTE: the User2AppDtos collection wil always be equal to the User.AllowedSections - foreach (var sectionDto in userDto.User2AppDtos) - { - //if something has been added then insert it - if (user.AddedSections.Contains(sectionDto.AppAlias)) - { - //we need to insert since this was added - Database.Insert(sectionDto); - } - else - { - //we need to manually update this record because it has a composite key - Database.Update("SET app=@Section WHERE app=@Section AND " + SqlSyntax.GetQuotedColumnName("user") + "=@UserId", - new { Section = sectionDto.AppAlias, UserId = sectionDto.UserId }); - } - } - - + UserGroupId = group.Id, + UserId = user.Id + }; + Database.Insert(dto); } entity.ResetDirtyProperties(); @@ -289,29 +285,70 @@ namespace Umbraco.Core.Persistence.Repositories return Database.ExecuteScalar(sql) > 0; } - public IEnumerable GetUsersAssignedToSection(string sectionAlias) + /// + /// Gets all groups for a given user + /// + /// Id of user + /// An enumerable list of + public IEnumerable GetGroupsForUser(int userId) { - //Here we're building up a query that looks like this, a sub query is required because the resulting structure - // needs to still contain all of the section rows per user. + var tables = SqlSyntax.GetTablesInSchema(ApplicationContext.Current.DatabaseContext.Database).ToArray(); + if (tables.InvariantContains("umbracoUserGroup") == false) + return new List(); - //SELECT * - //FROM [umbracoUser] - //LEFT JOIN [umbracoUser2app] - //ON [umbracoUser].[id] = [umbracoUser2app].[user] - //WHERE umbracoUser.id IN (SELECT umbracoUser.id - // FROM [umbracoUser] - // LEFT JOIN [umbracoUser2app] - // ON [umbracoUser].[id] = [umbracoUser2app].[user] - // WHERE umbracoUser2app.app = 'content') + var sql = new Sql(); + sql.Select("*") + .From() + .LeftJoin() + .On(left => left.Id, right => right.UserGroupId); - var sql = GetBaseQuery(false); - var innerSql = GetBaseQuery("umbracoUser.id"); - innerSql.Where("umbracoUser2app.app = " + SqlSyntax.GetQuotedValue(sectionAlias)); - sql.Where(string.Format("umbracoUser.id IN ({0})", innerSql.SQL)); - //must be sorted this way for the relator to work - sql.OrderBy(x => x.Id, SqlSyntax); + var innerSql = new Sql(); + innerSql.Select("umbracoUserGroup.id") + .From() + .LeftJoin() + .On(left => left.Id, right => right.UserGroupId) + .Where("umbracoUser2UserGroup.userId = " + userId); - return ConvertFromDtos(Database.Fetch(new UserSectionRelator().Map, sql)); + sql.Where(string.Format("umbracoUserGroup.id IN ({0})", innerSql.SQL)); + var dtos = Database.Fetch(new UserGroupSectionRelator().Map, sql); + return ConvertFromDtos(dtos); + } + + /// + /// Gets a list of objects associated with a given group + /// + /// Id of group + public IEnumerable GetAllInGroup(int groupId) + { + return GetAllInOrNotInGroup(groupId, true); + } + + /// + /// Gets a list of objects not associated with a given group + /// + /// Id of group + public IEnumerable GetAllNotInGroup(int groupId) + { + return GetAllInOrNotInGroup(groupId, false); + } + + private IEnumerable GetAllInOrNotInGroup(int groupId, bool include) + { + var sql = new Sql(); + sql.Select("*") + .From(); + + var innerSql = new Sql(); + innerSql.Select("umbracoUser.id") + .From() + .LeftJoin() + .On(left => left.Id, right => right.UserId) + .Where("umbracoUser2UserGroup.userGroupId = " + groupId); + + sql.Where(string.Format("umbracoUser.id {0} ({1})", + include ? "IN" : "NOT IN", + innerSql.SQL)); + return ConvertFromDtos(Database.Fetch(sql)); } /// @@ -375,68 +412,24 @@ namespace Umbraco.Core.Persistence.Repositories return ids.Length == 0 ? Enumerable.Empty() : GetAll(ids).OrderBy(x => x.Id); } - /// - /// Returns permissions for a given user for any number of nodes - /// - /// - /// - /// - public IEnumerable GetUserPermissionsForEntities(int userId, params int[] entityIds) - { - var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); - return repo.GetUserPermissionsForEntities(userId, entityIds); - } - - /// - /// Replaces the same permission set for a single user to any number of entities - /// - /// - /// - /// - public void ReplaceUserPermissions(int userId, IEnumerable permissions, params int[] entityIds) - { - var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); - repo.ReplaceUserPermissions(userId, permissions, entityIds); - } - - /// - /// Assigns the same permission set for a single user to any number of entities - /// - /// - /// - /// - public void AssignUserPermission(int userId, char permission, params int[] entityIds) - { - var repo = new PermissionRepository(UnitOfWork, _cacheHelper, SqlSyntax); - repo.AssignUserPermission(userId, permission, entityIds); - } - #endregion private IEnumerable ConvertFromDtos(IEnumerable dtos) { - var userTypeIds = dtos.Select(x => Convert.ToInt32(x.Type)).ToArray(); - - var allUserTypes = userTypeIds.Length == 0 ? Enumerable.Empty() : _userTypeRepository.GetAll(userTypeIds); - return dtos.Select(dto => { - var userType = allUserTypes.Single(x => x.Id == dto.Type); - - var userFactory = new UserFactory(userType); + var userFactory = new UserFactory(); return userFactory.BuildEntity(dto); }); } - /// - /// Dispose disposable properties - /// - /// - /// Ensure the unit of work is disposed - /// - protected override void DisposeResources() + private IEnumerable ConvertFromDtos(IEnumerable dtos) { - _userTypeRepository.Dispose(); + return dtos.Select(dto => + { + var userGroupFactory = new UserGroupFactory(); + return userGroupFactory.BuildEntity(dto); + }); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs deleted file mode 100644 index 81e3a5765e..0000000000 --- a/src/Umbraco.Core/Persistence/Repositories/UserTypeRepository.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Models.Rdbms; - -using Umbraco.Core.Persistence.Factories; -using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Core.Persistence.UnitOfWork; - -namespace Umbraco.Core.Persistence.Repositories -{ - /// - /// Represents the UserTypeRepository for doing CRUD operations for - /// - internal class UserTypeRepository : PetaPocoRepositoryBase, IUserTypeRepository - { - public UserTypeRepository(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax) - : base(work, cache, logger, sqlSyntax) - { - } - - #region Overrides of RepositoryBase - - protected override IUserType PerformGet(int id) - { - return GetAll(new[] {id}).FirstOrDefault(); - } - - protected override IEnumerable PerformGetAll(params int[] ids) - { - var userTypeFactory = new UserTypeFactory(); - - var sql = GetBaseQuery(false); - - if (ids.Any()) - { - sql.Where("umbracoUserType.id in (@ids)", new { ids = ids }); - } - else - { - sql.Where(x => x.Id >= 0); - } - - var dtos = Database.Fetch(sql); - return dtos.Select(userTypeFactory.BuildEntity).ToArray(); - } - - protected override IEnumerable PerformGetByQuery(IQuery query) - { - var userTypeFactory = new UserTypeFactory(); - var sqlClause = GetBaseQuery(false); - var translator = new SqlTranslator(sqlClause, query); - var sql = translator.Translate(); - - var dtos = Database.Fetch(sql); - - return dtos.Select(userTypeFactory.BuildEntity).ToArray(); - } - - #endregion - - #region Overrides of PetaPocoRepositoryBase - - protected override Sql GetBaseQuery(bool isCount) - { - var sql = new Sql(); - sql.Select(isCount ? "COUNT(*)" : "*") - .From(); - return sql; - } - - protected override string GetBaseWhereClause() - { - return "umbracoUserType.id = @Id"; - } - - protected override IEnumerable GetDeleteClauses() - { - var list = new List - { - "DELETE FROM umbracoUser WHERE userType = @Id", - "DELETE FROM umbracoUserType WHERE id = @Id" - }; - return list; - } - - protected override Guid NodeObjectTypeId - { - get { throw new NotImplementedException(); } - } - - protected override void PersistNewItem(IUserType entity) - { - var userTypeFactory = new UserTypeFactory(); - var userTypeDto = userTypeFactory.BuildDto(entity); - - var id = Convert.ToInt32(Database.Insert(userTypeDto)); - entity.Id = id; - } - - protected override void PersistUpdatedItem(IUserType entity) - { - var userTypeFactory = new UserTypeFactory(); - var userTypeDto = userTypeFactory.BuildDto(entity); - - Database.Update(userTypeDto); - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index afb93f620f..8b532811e1 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -275,11 +275,10 @@ namespace Umbraco.Core.Persistence _logger, _sqlSyntax); } - public virtual IUserTypeRepository CreateUserTypeRepository(IScopeUnitOfWork uow) + public virtual IUserGroupRepository CreateUserGroupRepository(IScopeUnitOfWork uow) { - return new UserTypeRepository( + return new UserGroupRepository( uow, - //There's not many user types but we query on users all the time so the result needs to be cached _cacheHelper, _logger, _sqlSyntax); } @@ -290,8 +289,7 @@ namespace Umbraco.Core.Persistence uow, //Need to cache users - we look up user information more than anything in the back office! _cacheHelper, - _logger, _sqlSyntax, - CreateUserTypeRepository(uow)); + _logger, _sqlSyntax); } internal virtual IMacroRepository CreateMacroRepository(IScopeUnitOfWork uow) diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs index 889c7004d7..1f73998526 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs @@ -68,10 +68,7 @@ namespace Umbraco.Core.Security ThrowIfDisposed(); if (user == null) throw new ArgumentNullException("user"); - var userType = _userService.GetUserTypeByAlias( - user.UserTypeAlias.IsNullOrWhiteSpace() ? _userService.GetDefaultMemberType() : user.UserTypeAlias); - - var member = new User(userType) + var member = new User { DefaultToLiveEditing = false, Email = user.Email, @@ -389,7 +386,7 @@ namespace Umbraco.Core.Security /// - /// Adds a user to a role (section) + /// Adds a user to a role (user group) /// /// /// @@ -406,18 +403,19 @@ namespace Umbraco.Core.Security throw new InvalidOperationException("The user id must be an integer to work with the Umbraco"); } - var found = _userService.GetUserById(asInt.Result); + var foundUser = _userService.GetUserById(asInt.Result); + var foundGroup = _userService.GetUserGroupByName(roleName); - if (found != null) + if (foundUser != null && foundGroup != null) { - found.AddAllowedSection(roleName); + foundUser.AddGroup(foundGroup); } return Task.FromResult(0); } /// - /// Removes the role (allowed section) for the user + /// Removes the role (user group) for the user /// /// /// @@ -434,18 +432,19 @@ namespace Umbraco.Core.Security throw new InvalidOperationException("The user id must be an integer to work with the Umbraco"); } - var found = _userService.GetUserById(asInt.Result); + var foundUser = _userService.GetUserById(asInt.Result); + var foundGroup = _userService.GetUserGroupByName(roleName); - if (found != null) + if (foundUser != null && foundGroup != null) { - found.RemoveAllowedSection(roleName); + foundUser.RemoveGroup(foundGroup); } return Task.FromResult(0); } /// - /// Returns the roles for this user + /// Returns the roles (user groups) for this user /// /// /// @@ -453,7 +452,7 @@ namespace Umbraco.Core.Security { ThrowIfDisposed(); if (user == null) throw new ArgumentNullException("user"); - return Task.FromResult((IList)user.AllowedSections.ToList()); + return Task.FromResult((IList)user.Groups.ToList()); } /// @@ -465,7 +464,7 @@ namespace Umbraco.Core.Security { ThrowIfDisposed(); if (user == null) throw new ArgumentNullException("user"); - return Task.FromResult(user.AllowedSections.InvariantContains(roleName)); + return Task.FromResult(user.Groups.InvariantContains(roleName)); } /// @@ -690,17 +689,21 @@ namespace Umbraco.Core.Security user.SecurityStamp = identityUser.SecurityStamp; } - if (user.AllowedSections.ContainsAll(identityUser.AllowedSections) == false - || identityUser.AllowedSections.ContainsAll(user.AllowedSections) == false) + if (user.Groups.Select(x => x.Name).ContainsAll(identityUser.Groups) == false + || identityUser.Groups.ContainsAll(user.Groups.Select(x => x.Name)) == false) { anythingChanged = true; - foreach (var allowedSection in user.AllowedSections) + foreach (var group in user.Groups) { - user.RemoveAllowedSection(allowedSection); + user.RemoveGroup(group); } - foreach (var allowedApplication in identityUser.AllowedSections) + foreach (var group in identityUser.Groups) { - user.AddAllowedSection(allowedApplication); + var foundGroup = _userService.GetUserGroupByName(group); + if (foundGroup != null) + { + user.AddGroup(foundGroup); + } } } diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index c00b226d3e..282b5d097f 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -115,13 +115,13 @@ namespace Umbraco.Core.Services /// /// /// - /// - public void AssignContentPermission(IContent entity, char permission, IEnumerable userIds) + /// + public void AssignContentPermission(IContent entity, char permission, IEnumerable groupIds) { using (var uow = UowProvider.GetUnitOfWork()) { var repository = RepositoryFactory.CreateContentRepository(uow); - repository.AssignEntityPermission(entity, permission, userIds); + repository.AssignEntityPermission(entity, permission, groupIds); uow.Commit(); } } @@ -131,7 +131,7 @@ namespace Umbraco.Core.Services /// /// /// - public IEnumerable GetPermissionsForEntity(IContent content) + public IEnumerable GetPermissionsForEntity(IContent content) { using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { diff --git a/src/Umbraco.Core/Services/ContentServiceExtensions.cs b/src/Umbraco.Core/Services/ContentServiceExtensions.cs index d2ce1de2f8..95fe79f9ac 100644 --- a/src/Umbraco.Core/Services/ContentServiceExtensions.cs +++ b/src/Umbraco.Core/Services/ContentServiceExtensions.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Services /// public static void RemoveContentPermissions(this IContentService contentService, int contentId) { - contentService.ReplaceContentPermissions(new EntityPermissionSet(contentId, Enumerable.Empty())); + contentService.ReplaceContentPermissions(new EntityPermissionSet(contentId, Enumerable.Empty())); } /// diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 4af87d2b58..03b8c0e9e2 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -137,19 +137,19 @@ namespace Umbraco.Core.Services void ReplaceContentPermissions(EntityPermissionSet permissionSet); /// - /// Assigns a single permission to the current content item for the specified user ids + /// Assigns a single permission to the current content item for the specified user group ids /// /// /// - /// - void AssignContentPermission(IContent entity, char permission, IEnumerable userIds); + /// + void AssignContentPermission(IContent entity, char permission, IEnumerable groupIds); /// /// Gets the list of permissions for the content item /// /// /// - IEnumerable GetPermissionsForEntity(IContent content); + IEnumerable GetPermissionsForEntity(IContent content); bool SendToPublication(IContent content, int userId = 0); diff --git a/src/Umbraco.Core/Services/IMembershipMemberService.cs b/src/Umbraco.Core/Services/IMembershipMemberService.cs index 801f88d9ac..640b90b431 100644 --- a/src/Umbraco.Core/Services/IMembershipMemberService.cs +++ b/src/Umbraco.Core/Services/IMembershipMemberService.cs @@ -46,14 +46,6 @@ namespace Umbraco.Core.Services /// with number of Members or Users for passed in type int GetCount(MemberCountType countType); - /// - /// Gets the default MemberType alias - /// - /// By default we'll return the 'writer', but we need to check it exists. If it doesn't we'll - /// return the first type that is not an admin, otherwise if there's only one we will return that one. - /// Alias of the default MemberType - string GetDefaultMemberType(); - /// /// Checks if a Member with the username exists /// @@ -121,6 +113,14 @@ namespace Umbraco.Core.Services /// Default is True otherwise set to False to not raise events void Save(IEnumerable entities, bool raiseEvents = true); + /// + /// Gets the default MemberType alias + /// + /// By default we'll return the 'writer', but we need to check it exists. If it doesn't we'll + /// return the first type that is not an admin, otherwise if there's only one we will return that one. + /// Alias of the default MemberType + string GetDefaultMemberType(); + /// /// Finds a list of objects by a partial email string /// diff --git a/src/Umbraco.Core/Services/IMembershipUserService.cs b/src/Umbraco.Core/Services/IMembershipUserService.cs index 182d08f9bd..4143a871bf 100644 --- a/src/Umbraco.Core/Services/IMembershipUserService.cs +++ b/src/Umbraco.Core/Services/IMembershipUserService.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Umbraco.Core.Models.Membership; namespace Umbraco.Core.Services @@ -18,8 +19,7 @@ namespace Umbraco.Core.Services /// Id of the user once its been created. /// Username of the User to create /// Email of the User to create - /// which the User should be based on /// - IUser CreateUserWithIdentity(string username, string email, IUserType userType); + IUser CreateUserWithIdentity(string username, string email); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ISectionService.cs b/src/Umbraco.Core/Services/ISectionService.cs index df5c89d4bf..d726179224 100644 --- a/src/Umbraco.Core/Services/ISectionService.cs +++ b/src/Umbraco.Core/Services/ISectionService.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Services IEnumerable
GetSections(); /// - /// Get the user's allowed sections + /// Get the user group's allowed sections /// /// /// diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs index 7353f44cb8..dafe746fc8 100644 --- a/src/Umbraco.Core/Services/IUserService.cs +++ b/src/Umbraco.Core/Services/IUserService.cs @@ -48,19 +48,19 @@ namespace Umbraco.Core.Services IUser GetUserById(int id); /// - /// Removes a specific section from all users + /// Removes a specific section from all user groups /// /// This is useful when an entire section is removed from config /// Alias of the section to remove - void DeleteSectionFromAllUsers(string sectionAlias); - + void DeleteSectionFromAllUserGroups(string sectionAlias); + /// - /// Add a specific section to all users or those specified as parameters + /// Add a specific section to all user groups or those specified as parameters /// - /// This is useful when a new section is created to allow specific users accessing it + /// This is useful when a new section is created to allow specific user groups to access it /// Alias of the section to add - /// Specifiying nothing will add the section to all user - void AddSectionToAllUsers(string sectionAlias, params int[] userIds); + /// Specifiying nothing will add the section to all user + void AddSectionToAllUserGroups(string sectionAlias, params int[] groupIds); /// /// Get permissions set for a user and optional node ids @@ -72,68 +72,123 @@ namespace Umbraco.Core.Services IEnumerable GetPermissions(IUser user, params int[] nodeIds); /// - /// Replaces the same permission set for a single user to any number of entities + /// Get permissions set for a group and optional node Ids + /// + /// Group to retrieve permissions for + /// + /// Flag indicating if we want to get just the permissions directly assigned for the group and path, + /// or fall back to the group's default permissions when nothing is directly assigned + /// + /// Specifiying nothing will return all permissions for all nodes + /// An enumerable list of + IEnumerable GetPermissions(IUserGroup group, bool directlyAssignedOnly, params int[] nodeIds); + + /// + /// Gets the permissions for the provided user and path + /// + /// User to check permissions for + /// Path to check permissions for + /// String indicating permissions for provided user and path + string GetPermissionsForPath(IUser user, string path); + + /// + /// Gets the permissions for the provided group and path + /// + /// User to check permissions for + /// Path to check permissions for + /// + /// Flag indicating if we want to get just the permissions directly assigned for the group and path, + /// or fall back to the group's default permissions when nothing is directly assigned + /// + /// String indicating permissions for provided user and path + string GetPermissionsForPath(IUserGroup group, string path, bool directlyAssignedOnly = true); + + /// + /// Replaces the same permission set for a single group to any number of entities /// - /// Id of the user + /// Id of the group /// /// Permissions as enumerable list of , - /// if no permissions are specified then all permissions for this node are removed for this user + /// if no permissions are specified then all permissions for this node are removed for this group /// /// Specify the nodes to replace permissions for. If nothing is specified all permissions are removed. - /// If no 'entityIds' are specified all permissions will be removed for the specified user. - void ReplaceUserPermissions(int userId, IEnumerable permissions, params int[] entityIds); + /// If no 'entityIds' are specified all permissions will be removed for the specified group. + void ReplaceUserGroupPermissions(int groupId, IEnumerable permissions, params int[] entityIds); /// - /// Assigns the same permission set for a single user to any number of entities + /// Assigns the same permission set for a single user group to any number of entities /// - /// Id of the user + /// Id of the group /// /// Specify the nodes to replace permissions for - void AssignUserPermission(int userId, char permission, params int[] entityIds); - - #region User types + void AssignUserGroupPermission(int groupId, char permission, params int[] entityIds); /// - /// Gets all UserTypes or thosed specified as parameters + /// Gets a list of objects associated with a given group /// - /// Optional Ids of UserTypes to retrieve - /// An enumerable list of - IEnumerable GetAllUserTypes(params int[] ids); - - /// - /// Gets a UserType by its Alias - /// - /// Alias of the UserType to retrieve - /// - IUserType GetUserTypeByAlias(string alias); + /// Id of group + /// + IEnumerable GetAllInGroup(int groupId); /// - /// Gets a UserType by its Id + /// Gets a list of objects not associated with a given group /// - /// Id of the UserType to retrieve - /// - IUserType GetUserTypeById(int id); + /// Id of group + /// + IEnumerable GetAllNotInGroup(int groupId); + + #region User groups /// - /// Gets a UserType by its Name + /// Gets all UserGroups or those specified as parameters /// - /// Name of the UserType to retrieve - /// - IUserType GetUserTypeByName(string name); + /// Optional Ids of UserGroups to retrieve + /// An enumerable list of + IEnumerable GetAllUserGroups(params int[] ids); /// - /// Saves a UserType + /// Gets all UserGroups for a given user /// - /// UserType to save + /// Id of user + /// An enumerable list of + IEnumerable GetGroupsForUser(int userId); + + /// + /// Gets a UserGroup by its Alias + /// + /// Alias of the UserGroup to retrieve + /// + IUserGroup GetUserGroupByAlias(string alias); + + /// + /// Gets a UserGroup by its Id + /// + /// Id of the UserGroup to retrieve + /// + IUserGroup GetUserGroupById(int id); + + /// + /// Gets a UserGroup by its Name + /// + /// Name of the UserGroup to retrieve + /// + IUserGroup GetUserGroupByName(string name); + + /// + /// Saves a UserGroup + /// + /// UserGroup to save + /// Flag for whether to update the list of users in the group + /// List of user Ids /// Optional parameter to raise events. /// Default is True otherwise set to False to not raise events - void SaveUserType(IUserType userType, bool raiseEvents = true); + void SaveUserGroup(IUserGroup userGroup, bool updateUsers = false, int[] userIds = null, bool raiseEvents = true); /// - /// Deletes a UserType + /// Deletes a UserGroup /// - /// UserType to delete - void DeleteUserType(IUserType userType); + /// UserGroup to delete + void DeleteUserGroup(IUserGroup userGroup); #endregion } diff --git a/src/Umbraco.Core/Services/SectionService.cs b/src/Umbraco.Core/Services/SectionService.cs index 9cf540374e..b99181376c 100644 --- a/src/Umbraco.Core/Services/SectionService.cs +++ b/src/Umbraco.Core/Services/SectionService.cs @@ -182,7 +182,6 @@ namespace Umbraco.Core.Services /// public IEnumerable
GetAllowedSections(int userId) { - var user = _userService.GetUserById(userId); if (user == null) { @@ -210,7 +209,9 @@ namespace Umbraco.Core.Services /// The application icon, which has to be located in umbraco/images/tray folder. public void MakeNew(string name, string alias, string icon) { - MakeNew(name, alias, icon, GetSections().Max(x => x.SortOrder) + 1); + var sections = GetSections(); + var nextSortOrder = sections.Any() ? sections.Max(x => x.SortOrder) + 1 : 1; + MakeNew(name, alias, icon, nextSortOrder); } /// @@ -250,7 +251,7 @@ namespace Umbraco.Core.Services using (var uow = _uowProvider.GetUnitOfWork()) { uow.Database.Execute( - "delete from umbracoUser2App where app = @appAlias", + "delete from umbracoUserGroup2App where app = @appAlias", new { appAlias = section.Alias }); uow.Commit(); } diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index dd9892e47c..066823ca76 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -33,40 +33,6 @@ namespace Umbraco.Core.Services #region Implementation of IMembershipUserService - /// - /// Gets the default MemberType alias - /// - /// By default we'll return the 'writer', but we need to check it exists. If it doesn't we'll - /// return the first type that is not an admin, otherwise if there's only one we will return that one. - /// Alias of the default MemberType - public string GetDefaultMemberType() - { - using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) - { - var repository = RepositoryFactory.CreateUserTypeRepository(uow); - - var types = repository.GetAll().Select(x => x.Alias).ToArray(); - - if (types.Any() == false) - { - throw new EntityNotFoundException("No member types could be resolved"); - } - - if (types.InvariantContains("writer")) - { - return types.First(x => x.InvariantEquals("writer")); - } - - //first that is not admin - if (types.Length == 1) - { - return types.First(); - } - //first that is not admin - return types.First(x => x.InvariantEquals("admin") == false); - } - } - /// /// Checks if a User with the username exists /// @@ -87,11 +53,10 @@ namespace Umbraco.Core.Services /// The user will be saved in the database and returned with an Id /// Username of the user to create /// Email of the user to create - /// which the User should be based on /// - public IUser CreateUserWithIdentity(string username, string email, IUserType userType) + public IUser CreateUserWithIdentity(string username, string email) { - return CreateUserWithIdentity(username, email, "", userType); + return CreateUserWithIdentity(username, email, string.Empty); } /// @@ -100,17 +65,11 @@ namespace Umbraco.Core.Services /// Username of the to create /// Email of the to create /// This value should be the encoded/encrypted/hashed value for the password that will be stored in the database - /// Alias of the Type + /// Not used for users /// IUser IMembershipMemberService.CreateWithIdentity(string username, string email, string passwordValue, string memberTypeAlias) { - var userType = GetUserTypeByAlias(memberTypeAlias); - if (userType == null) - { - throw new EntityNotFoundException("The user type " + memberTypeAlias + " could not be resolved"); - } - - return CreateUserWithIdentity(username, email, passwordValue, userType); + return CreateUserWithIdentity(username, email, passwordValue); } /// @@ -121,12 +80,9 @@ namespace Umbraco.Core.Services /// Username of the Member to create /// Email of the Member to create /// This value should be the encoded/encrypted/hashed value for the password that will be stored in the database - /// MemberType the Member should be based on /// - private IUser CreateUserWithIdentity(string username, string email, string passwordValue, IUserType userType) + private IUser CreateUserWithIdentity(string username, string email, string passwordValue) { - if (userType == null) throw new ArgumentNullException("userType"); - if (string.IsNullOrWhiteSpace(username)) { throw new ArgumentException("Cannot create user with empty username."); @@ -141,7 +97,7 @@ namespace Umbraco.Core.Services if (loginExists) throw new ArgumentException("Login already exists"); - var user = new User(userType) + var user = new User { DefaultToLiveEditing = false, Email = email, @@ -154,9 +110,6 @@ namespace Umbraco.Core.Services IsLockedOut = false, IsApproved = true }; - //adding default sections content and media - user.AddAllowedSection("content"); - user.AddAllowedSection("media"); if (uow.Events.DispatchCancelable(SavingUser, this, new SaveEventArgs(user))) { @@ -402,6 +355,12 @@ namespace Umbraco.Core.Services } + public string GetDefaultMemberType() + { + // User types now being removed, there is no default user type to return + return "None"; + } + /// /// Finds a list of objects by a partial email string /// @@ -558,6 +517,34 @@ namespace Umbraco.Core.Services } } + /// + /// Gets a list of objects associated with a given group + /// + /// Id of group + /// + public IEnumerable GetAllInGroup(int groupId) + { + var uow = UowProvider.GetUnitOfWork(); + using (var repository = RepositoryFactory.CreateUserRepository(uow)) + { + return repository.GetAllInGroup(groupId); + } + } + + /// + /// Gets a list of objects not associated with a given group + /// + /// Id of group + /// + public IEnumerable GetAllNotInGroup(int groupId) + { + var uow = UowProvider.GetUnitOfWork(); + using (var repository = RepositoryFactory.CreateUserRepository(uow)) + { + return repository.GetAllNotInGroup(groupId); + } + } + #endregion #region Implementation of IUserService @@ -599,137 +586,159 @@ namespace Umbraco.Core.Services } /// - /// Replaces the same permission set for a single user to any number of entities + /// Replaces the same permission set for a single group to any number of entities /// - /// If no 'entityIds' are specified all permissions will be removed for the specified user. - /// Id of the user + /// If no 'entityIds' are specified all permissions will be removed for the specified group. + /// Id of the group /// Permissions as enumerable list of /// Specify the nodes to replace permissions for. If nothing is specified all permissions are removed. - public void ReplaceUserPermissions(int userId, IEnumerable permissions, params int[] entityIds) + public void ReplaceUserGroupPermissions(int groupId, IEnumerable permissions, params int[] entityIds) { using (var uow = UowProvider.GetUnitOfWork()) { - var repository = RepositoryFactory.CreateUserRepository(uow); - repository.ReplaceUserPermissions(userId, permissions, entityIds); + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + repository.ReplaceGroupPermissions(groupId, permissions, entityIds); uow.Commit(); } } /// - /// Assigns the same permission set for a single user to any number of entities + /// Assigns the same permission set for a single user group to any number of entities /// - /// Id of the user + /// Id of the user group /// /// Specify the nodes to replace permissions for - public void AssignUserPermission(int userId, char permission, params int[] entityIds) + public void AssignUserGroupPermission(int groupId, char permission, params int[] entityIds) { using (var uow = UowProvider.GetUnitOfWork()) { - var repository = RepositoryFactory.CreateUserRepository(uow); - repository.AssignUserPermission(userId, permission, entityIds); + var repository = RepositoryFactory.CreateUserGroupRepository(uow) + repository.AssignGroupPermission(groupId, permission, entityIds); uow.Commit(); } } - + /// - /// Gets all UserTypes or thosed specified as parameters + /// Gets all UserGroups or those specified as parameters /// - /// Optional Ids of UserTypes to retrieve - /// An enumerable list of - public IEnumerable GetAllUserTypes(params int[] ids) + /// Optional Ids of UserGroups to retrieve + /// An enumerable list of + public IEnumerable GetAllUserGroups(params int[] ids) { using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { - var repository = RepositoryFactory.CreateUserTypeRepository(uow); - return repository.GetAll(ids); + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + return repository.GetAll(ids).OrderBy(x => x.Name); } } /// - /// Gets a UserType by its Alias + /// Gets all UserGroups for a given user /// - /// Alias of the UserType to retrieve - /// - public IUserType GetUserTypeByAlias(string alias) + /// Id of user + /// An enumerable list of + public IEnumerable GetGroupsForUser(int userId) { using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { - var repository = RepositoryFactory.CreateUserTypeRepository(uow); - var query = Query.Builder.Where(x => x.Alias == alias); - return repository.GetByQuery(query).SingleOrDefault(); + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + return repository.GetGroupsForUser(userId); } } /// - /// Gets a UserType by its Id + /// Gets a UserGroup by its Alias /// - /// Id of the UserType to retrieve - /// - public IUserType GetUserTypeById(int id) + /// Alias of the UserGroup to retrieve + /// + public IUserGroup GetUserGroupByAlias(string alias) + { + using (var repository = RepositoryFactory.CreateUserGroupRepository(UowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Alias == alias); + } + } + + /// + /// Gets a UserGroup by its Id + /// + /// Id of the UserGroup to retrieve + /// + public IUserGroup GetUserGroupById(int id) { using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { - var repository = RepositoryFactory.CreateUserTypeRepository(uow); + var repository = RepositoryFactory.CreateUserGroupRepository(uow); return repository.Get(id); } } /// - /// Gets a UserType by its Name + /// Gets a UserGroup by its Name /// - /// Name of the UserType to retrieve - /// - public IUserType GetUserTypeByName(string name) + /// Name of the UserGroup to retrieve + /// + public IUserGroup GetUserGroupByName(string name) { using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { - var repository = RepositoryFactory.CreateUserTypeRepository(uow); - var query = Query.Builder.Where(x => x.Name == name); + var repository = RepositoryFactory.CreateUserGroupRepository(uow) + var query = Query.Builder.Where(x => x.Name == name); return repository.GetByQuery(query).SingleOrDefault(); } } /// - /// Saves a UserType + /// Saves a UserGroup /// - /// UserType to save + /// UserGroup to save + /// Flag for whether to update the list of users in the group + /// List of user Ids /// Optional parameter to raise events. /// Default is True otherwise set to False to not raise events - public void SaveUserType(IUserType userType, bool raiseEvents = true) + public void SaveUserGroup(IUserGroup userGroup, bool updateUsers = false, int[] userIds = null, bool raiseEvents = true) { using (var uow = UowProvider.GetUnitOfWork()) { - if (raiseEvents && uow.Events.DispatchCancelable(SavingUserType, this, new SaveEventArgs(userType))) + if (raiseEvents && uow.Events.DispatchCancelable(SavingUserGroup, this, new SaveEventArgs(userGroup))) { uow.Commit(); return; } - var repository = RepositoryFactory.CreateUserTypeRepository(uow); - repository.AddOrUpdate(userType); + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + repository.AddOrUpdate(userGroup); + + + if (updateUsers) + { + repository.RemoveAllUsersFromGroup(userGroup.Id); + repository.AddUsersToGroup(userGroup.Id, userIds); + } uow.Commit(); + if (raiseEvents) - uow.Events.Dispatch(SavedUserType, this, new SaveEventArgs(userType, false)); + uow.Events.Dispatch(SavedUserGroup, this, new SaveEventArgs(userGroup, false)); } } /// - /// Deletes a UserType + /// Deletes a UserGroup /// - /// UserType to delete - public void DeleteUserType(IUserType userType) + /// UserGroup to delete + public void DeleteUserGroup(IUserGroup userGroup) { using (var uow = UowProvider.GetUnitOfWork()) { - if (uow.Events.DispatchCancelable(DeletingUserType, this, new DeleteEventArgs(userType))) + if (uow.Events.DispatchCancelable(DeletingUserGroup, this, new DeleteEventArgs(userGroup))) { uow.Commit(); return; } - var repository = RepositoryFactory.CreateUserTypeRepository(uow); - repository.Delete(userType); + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + repository.Delete(userGroup); uow.Commit(); - uow.Events.Dispatch(DeletedUserType, this, new DeleteEventArgs(userType, false)); + uow.Events.Dispatch(DeletedUserGroup, this, new DeleteEventArgs(userGroup, false)); } } @@ -738,80 +747,254 @@ namespace Umbraco.Core.Services /// /// This is useful when an entire section is removed from config /// Alias of the section to remove - public void DeleteSectionFromAllUsers(string sectionAlias) + public void DeleteSectionFromAllUserGroups(string sectionAlias) { using (var uow = UowProvider.GetUnitOfWork()) { - var repository = RepositoryFactory.CreateUserRepository(uow); - var assignedUsers = repository.GetUsersAssignedToSection(sectionAlias); - foreach (var user in assignedUsers) + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + var assignedGroups = repository.GetGroupsAssignedToSection(sectionAlias); + foreach (var group in assignedGroups) { //now remove the section for each user and commit - user.RemoveAllowedSection(sectionAlias); - repository.AddOrUpdate(user); + group.RemoveAllowedSection(sectionAlias); + repository.AddOrUpdate(group); } + uow.Commit(); //TODO: Events? } } /// - /// Add a specific section to all users or those specified as parameters + /// Add a specific section to all user groups or those specified as parameters /// - /// This is useful when a new section is created to allow specific users accessing it + /// This is useful when a new section is created to allow specific user groups to access it /// Alias of the section to add - /// Specifiying nothing will add the section to all user - public void AddSectionToAllUsers(string sectionAlias, params int[] userIds) + /// Specifiying nothing will add the section to all user + public void AddSectionToAllUserGroups(string sectionAlias, params int[] groupIds) { using (var uow = UowProvider.GetUnitOfWork()) { - var repository = RepositoryFactory.CreateUserRepository(uow); - IEnumerable users; - if (userIds.Any()) + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + IEnumerable groups; + if (groupIds.Any()) { - users = repository.GetAll(userIds); + groups = repository.GetAll(groupIds); } else { - users = repository.GetAll(); + groups = repository.GetAll(); } - foreach (var user in users.Where(u => u.AllowedSections.InvariantContains(sectionAlias) == false)) + foreach (var group in groups.Where(g => g.AllowedSections.InvariantContains(sectionAlias) == false)) { - //now add the section for each user and commit - user.AddAllowedSection(sectionAlias); - repository.AddOrUpdate(user); + //now add the section for each group and commit + group.AddAllowedSection(sectionAlias); + repository.AddOrUpdate(group); } + uow.Commit(); //TODO: Events? } } /// - /// Get permissions set for a user and optional node ids + /// Get permissions set for a user and node Id /// - /// If no permissions are found for a particular entity then the user's default permissions will be applied /// User to retrieve permissions for - /// Specifiying nothing will return all user permissions for all nodes + /// Specifiying nothing will return all permissions for all nodes /// An enumerable list of public IEnumerable GetPermissions(IUser user, params int[] nodeIds) { - using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) + if (user.GroupsLoaded == false) { - var repository = RepositoryFactory.CreateUserRepository(uow); - var explicitPermissions = repository.GetUserPermissionsForEntities(user.Id, nodeIds); + throw new InvalidOperationException("Cannot determine permissions for user as their associated groups are not loaded"); + } - //if no permissions are assigned to a particular node then we will fill in those permissions with the user's defaults - var result = new List(explicitPermissions); - var missingIds = nodeIds.Except(result.Select(x => x.EntityId)); - foreach (var id in missingIds) + var result = new List(); + foreach (var group in user.Groups) + { + foreach (var permission in GetPermissions(group, false, nodeIds)) { - result.Add(new EntityPermission(user.Id, id, user.DefaultPermissions.ToArray())); + AddOrAmendPermissionList(result, permission); + } + } + + return result; + } + + /// + /// Get permissions set for a group and node Id + /// + /// Group to retrieve permissions for + /// + /// Flag indicating if we want to get just the permissions directly assigned for the group and path, + /// or fall back to the group's default permissions when nothing is directly assigned + /// + /// Specifiying nothing will return all permissions for all nodes + /// An enumerable list of + public IEnumerable GetPermissions(IUserGroup group, bool directlyAssignedOnly, params int[] nodeIds) + { + + using (var uow = UowProvider.GetUnitOfWork();) + { + var repository = RepositoryFactory.CreateUserGroupRepository(uow); + var explicitPermissions = repository.GetPermissionsForEntities(group.Id, nodeIds); + var result = new List(explicitPermissions); + + // If requested, and no permissions are assigned to a particular node, then we will fill in those permissions with the group's defaults + if (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; } } + /// + /// For an existing list of , takes a new 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. + /// + /// List of already found permissions + /// New permission to aggregate + private void AddOrAmendPermissionList(IList permissions, EntityPermission groupPermission) + { + var existingPermission = permissions + .SingleOrDefault(x => x.EntityId == groupPermission.EntityId); + if (existingPermission != null) + { + existingPermission.AddAdditionalPermissions(groupPermission.AssignedPermissions); + } + else + { + permissions.Add(groupPermission); + } + } + + /// + /// Gets the permissions for the provided user and path + /// + /// User to check permissions for + /// Path to check permissions for + /// String indicating permissions for provided user and path + public string GetPermissionsForPath(IUser user, string path) + { + if (user.GroupsLoaded == false) + { + throw new InvalidOperationException("Cannot determine permissions for user as their associated groups are not loaded"); + } + + var assignedPermissions = GetPermissionsForGroupsAndPath(user.Groups, path); + return GetAggregatePermissions(assignedPermissions); + } + + /// + /// Retrieves the permissions assigned to each group for a given path + /// + /// List of groups associated with the user + /// Path to check permissions for + /// List of strings indicating permissions for each groups + private IEnumerable GetPermissionsForGroupsAndPath(IEnumerable groups, string path) + { + return groups + .Select(g => GetPermissionsForPath(g, path, directlyAssignedOnly: false)) + .ToList(); + } + + /// + /// Aggregates a set of permissions strings to return a unique permissions string containing the most permissive set + /// + /// List of permission strings + /// Single permission string + private static string GetAggregatePermissions(IEnumerable assignedPermissions) + { + return string.Join(string.Empty, assignedPermissions + .SelectMany(s => s.ToCharArray()) + .Distinct()); + } + + /// + /// Gets the permissions for the provided group and path + /// + /// User to check permissions for + /// Path to check permissions for + /// + /// Flag indicating if we want to get just the permissions directly assigned for the group and path, + /// or fall back to the group's default permissions when nothing is directly assigned + /// + /// String indicating permissions for provided user and path + public string GetPermissionsForPath(IUserGroup group, string path, bool directlyAssignedOnly = true) + { + var nodeId = GetNodeIdFromPath(path); + var permission = GetPermissions(group, directlyAssignedOnly, nodeId) + .SingleOrDefault(); + return permission != null + ? string.Join(string.Empty, permission.AssignedPermissions) + : string.Empty; + } + + /// + /// Parses a path to find the lowermost node id + /// + /// Path as string + /// Node id + private static int GetNodeIdFromPath(string path) + { + return path.Contains(",") + ? int.Parse(path.Substring(path.LastIndexOf(",", StringComparison.Ordinal) + 1)) + : int.Parse(path); + } + + private static bool IsNotNullActionPermission(EntityPermission x) + { + const string NullActionChar = "-"; + return string.Join(string.Empty, x.AssignedPermissions) != NullActionChar; + } + + /// + /// Checks in a set of permissions associated with a user for those related to a given nodeId + /// + /// The set of permissions + /// The node Id + /// The permissions to return + /// True if permissions for the given path are found + public static bool TryGetAssignedPermissionsForNode(IList permissions, + int nodeId, + out string assignedPermissions) + { + if (permissions.Any(x => x.EntityId == nodeId)) + { + var found = permissions.First(x => x.EntityId == nodeId); + var assignedPermissionsArray = found.AssignedPermissions.ToList(); + + // Working with permissions assigned directly to a user AND to their groups, so maybe several per node + // and we need to get the most permissive set + foreach (var permission in permissions.Where(x => x.EntityId == nodeId).Skip(1)) + { + AddAdditionalPermissions(assignedPermissionsArray, permission.AssignedPermissions); + } + + assignedPermissions = string.Join("", assignedPermissionsArray); + return true; + } + + assignedPermissions = string.Empty; + return false; + } + + private static void AddAdditionalPermissions(List assignedPermissions, string[] additionalPermissions) + { + var permissionsToAdd = additionalPermissions + .Where(x => assignedPermissions.Contains(x) == false); + assignedPermissions.AddRange(permissionsToAdd); + } + #endregion /// @@ -837,21 +1020,21 @@ namespace Umbraco.Core.Services /// /// Occurs before Save /// - public static event TypedEventHandler> SavingUserType; + public static event TypedEventHandler> SavingUserGroup; /// /// Occurs after Save /// - public static event TypedEventHandler> SavedUserType; + public static event TypedEventHandler> SavedUserGroup; /// /// Occurs before Delete /// - public static event TypedEventHandler> DeletingUserType; + public static event TypedEventHandler> DeletingUserGroup; /// /// Occurs after Delete /// - public static event TypedEventHandler> DeletedUserType; + public static event TypedEventHandler> DeletedUserGroup; } } diff --git a/src/Umbraco.Core/Services/UserServiceExtensions.cs b/src/Umbraco.Core/Services/UserServiceExtensions.cs index afb679afa1..6130077771 100644 --- a/src/Umbraco.Core/Services/UserServiceExtensions.cs +++ b/src/Umbraco.Core/Services/UserServiceExtensions.cs @@ -10,21 +10,21 @@ namespace Umbraco.Core.Services /// Remove all permissions for this user for all nodes specified /// /// - /// + /// /// - public static void RemoveUserPermissions(this IUserService userService, int userId, params int[] entityIds) + public static void RemoveUserGroupPermissions(this IUserService userService, int groupId, params int[] entityIds) { - userService.ReplaceUserPermissions(userId, new char[] {}, entityIds); + userService.ReplaceUserGroupPermissions(groupId, new char[] {}, entityIds); } /// /// Remove all permissions for this user for all nodes /// /// - /// - public static void RemoveUserPermissions(this IUserService userService, int userId) + /// + public static void RemoveUserGroupPermissions(this IUserService userService, int groupId) { - userService.ReplaceUserPermissions(userId, new char[] { }); + userService.ReplaceUserGroupPermissions(groupId, new char[] { }); } /// @@ -51,18 +51,11 @@ namespace Umbraco.Core.Services if (found == null) { - var writer = userService.GetUserTypeByAlias("writer"); - if (writer == null) - { - throw new InvalidOperationException("Could not map the custom user to an Umbraco user, no 'writer' user type could be found"); - } var user = new User( member.UserName, member.Email ?? Guid.NewGuid().ToString("N") + "@example.com", //email cannot be empty member.ProviderUserKey == null ? member.UserName : member.ProviderUserKey.ToString(), - Guid.NewGuid().ToString("N"), //pass cannot be empty - writer); - user.AddAllowedSection(Constants.Applications.Content); + Guid.NewGuid().ToString("N")); //pass cannot be empty userService.Save(user); return user; } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index a8d1cc55bd..c6ccd8495e 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -448,6 +448,8 @@ + + @@ -478,6 +480,11 @@ + + + + + @@ -492,11 +499,13 @@ + + @@ -512,6 +521,7 @@ + @@ -561,6 +571,7 @@ + @@ -578,12 +589,14 @@ + + @@ -856,10 +869,8 @@ - - @@ -891,7 +902,6 @@ - @@ -968,7 +978,6 @@ - @@ -990,7 +999,6 @@ - @@ -1138,7 +1146,6 @@ - @@ -1166,7 +1173,6 @@ - @@ -1185,7 +1191,6 @@ - @@ -1308,11 +1313,8 @@ - - - diff --git a/src/Umbraco.Tests/Models/UserTests.cs b/src/Umbraco.Tests/Models/UserTests.cs index 189a4a17a8..5bdc842cc1 100644 --- a/src/Umbraco.Tests/Models/UserTests.cs +++ b/src/Umbraco.Tests/Models/UserTests.cs @@ -13,7 +13,7 @@ namespace Umbraco.Tests.Models [Test] public void Can_Deep_Clone() { - var item = new User(new UserType(){Id = 3}) + var item = new User() { Id = 3, Key = Guid.NewGuid(), @@ -21,7 +21,6 @@ namespace Umbraco.Tests.Models CreateDate = DateTime.Now, Name = "Test", Comments = "comments", - DefaultPermissions = new[]{"a","b","c"}, DefaultToLiveEditing = false, Email = "test@test.com", Language = "en", @@ -41,37 +40,19 @@ namespace Umbraco.Tests.Models Username = "username" }; - item.AddAllowedSection("test"); - var clone = (User)item.DeepClone(); Assert.AreNotSame(clone, item); Assert.AreEqual(clone, item); - Assert.AreNotSame(clone.UserType, item.UserType); - Assert.AreEqual(clone.UserType, item.UserType); Assert.AreEqual(clone.AllowedSections.Count(), item.AllowedSections.Count()); - Assert.AreNotSame(clone.DefaultPermissions, item.DefaultPermissions); - Assert.AreEqual(clone.DefaultPermissions.Count(), item.DefaultPermissions.Count()); - //Verify normal properties with reflection var allProps = clone.GetType().GetProperties(); foreach (var propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); } - - //ensure internal collections are differet - Assert.AreNotSame(item.AddedSections, clone.AddedSections); - Assert.AreNotSame(item.RemovedSections, clone.RemovedSections); - - //ensure event handlers are still wired on clone - clone.AddAllowedSection("blah"); - Assert.AreEqual(1, clone.AddedSections.Count()); - clone.RemoveAllowedSection("blah"); - Assert.AreEqual(1, clone.RemovedSections.Count()); - } [Test] @@ -79,7 +60,7 @@ namespace Umbraco.Tests.Models { var ss = new SerializationService(new JsonNetSerializer()); - var item = new User(new UserType() { Id = 3 }) + var item = new User { Id = 3, Key = Guid.NewGuid(), @@ -87,7 +68,6 @@ namespace Umbraco.Tests.Models CreateDate = DateTime.Now, Name = "Test", Comments = "comments", - DefaultPermissions = new[] { "a", "b", "c" }, DefaultToLiveEditing = false, Email = "test@test.com", Language = "en", diff --git a/src/Umbraco.Tests/Models/UserTypeTests.cs b/src/Umbraco.Tests/Models/UserTypeTests.cs deleted file mode 100644 index 72aa0b2efc..0000000000 --- a/src/Umbraco.Tests/Models/UserTypeTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using NUnit.Framework; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Serialization; - -namespace Umbraco.Tests.Models -{ - [TestFixture] - public class UserTypeTests - { - [Test] - public void Can_Deep_Clone() - { - var item = new UserType() - { - Id = 3, - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now, - CreateDate = DateTime.Now, - Name = "Test", - Alias = "test", - Permissions = new[] {"a", "b", "c"} - }; - - var clone = (UserType)item.DeepClone(); - - Assert.AreNotSame(clone, item); - Assert.AreEqual(clone, item); - - //Verify normal properties with reflection - var allProps = clone.GetType().GetProperties(); - foreach (var propertyInfo in allProps) - { - Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); - } - } - - [Test] - public void Can_Serialize_Without_Error() - { - var ss = new SerializationService(new JsonNetSerializer()); - - var item = new UserType() - { - Id = 3, - Key = Guid.NewGuid(), - UpdateDate = DateTime.Now, - CreateDate = DateTime.Now, - Name = "Test", - Alias = "test", - Permissions = new[] { "a", "b", "c" } - }; - - var result = ss.ToStream(item); - var json = result.ResultStream.ToJsonString(); - Debug.Print(json); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/BaseTableByTableTest.cs b/src/Umbraco.Tests/Persistence/BaseTableByTableTest.cs index 0978c73c44..66314b158c 100644 --- a/src/Umbraco.Tests/Persistence/BaseTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/BaseTableByTableTest.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Persistence private DatabaseSchemaHelper _schemaHelper; public abstract Database Database { get; } - + protected abstract ISqlSyntaxProvider SqlSyntaxProvider { get; } protected DatabaseSchemaHelper DatabaseSchemaHelper @@ -41,7 +41,7 @@ namespace Umbraco.Tests.Persistence public virtual void Initialize() { _logger = new Logger(new FileInfo(TestHelper.MapPathForTest("~/unit-test-log4net.config"))); - + TestHelper.InitializeContentDirectories(); string path = TestHelper.CurrentAssemblyDirectory; @@ -66,9 +66,9 @@ namespace Umbraco.Tests.Persistence new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(scopeProvider), cacheHelper, _logger, evtMsgs), cacheHelper, new ProfilingLogger(_logger, Mock.Of())) - { - IsReady = true - }; + { + IsReady = true + }; Resolution.Freeze(); } @@ -85,7 +85,7 @@ namespace Umbraco.Tests.Persistence //RepositoryResolver.Reset(); } - + [Test] public void Can_Create_umbracoNode_Table() @@ -137,7 +137,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoAppTree_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -149,7 +149,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsContentType2ContentType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -162,7 +162,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsContentTypeAllowedContentType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -176,7 +176,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsContentType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -189,7 +189,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsContentVersion_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -204,7 +204,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsContentXml_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -219,7 +219,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsDataType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -232,7 +232,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsDataTypePreValues_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -246,7 +246,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsDictionary_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -258,7 +258,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsLanguageText_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -272,7 +272,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsTemplate_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -285,7 +285,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsDocument_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -301,7 +301,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsDocumentType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -316,7 +316,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoDomains_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -329,7 +329,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoLanguage_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -341,7 +341,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoLog_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -353,7 +353,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsMacro_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -361,11 +361,11 @@ namespace Umbraco.Tests.Persistence //transaction.Complete(); } } - + [Test] public void Can_Create_cmsMember_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -380,7 +380,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsMember2MemberGroup_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -396,7 +396,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsMemberType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -410,7 +410,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsPreviewXml_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -426,7 +426,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsPropertyData_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -443,7 +443,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsPropertyType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -459,7 +459,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsPropertyTypeGroup_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -473,7 +473,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoRelation_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -487,7 +487,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoRelationType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -499,7 +499,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsStylesheet_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -512,7 +512,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsStylesheetProperty_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -525,7 +525,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsTags_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -537,7 +537,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsTagRelationship_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -557,11 +557,10 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsTask_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); DatabaseSchemaHelper.CreateTable(); DatabaseSchemaHelper.CreateTable(); DatabaseSchemaHelper.CreateTable(); @@ -573,7 +572,7 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_cmsTaskType_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); @@ -585,10 +584,9 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoUser_Table() { - + using (Transaction transaction = Database.GetTransaction()) { - DatabaseSchemaHelper.CreateTable(); DatabaseSchemaHelper.CreateTable(); //transaction.Complete(); @@ -596,26 +594,11 @@ namespace Umbraco.Tests.Persistence } [Test] - public void Can_Create_umbracoUserType_Table() + public void Can_Create_umbracoUserGroup_Table() { - using (Transaction transaction = Database.GetTransaction()) { - DatabaseSchemaHelper.CreateTable(); - - //transaction.Complete(); - } - } - - [Test] - public void Can_Create_umbracoUser2app_Table() - { - - using (Transaction transaction = Database.GetTransaction()) - { - DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); + DatabaseSchemaHelper.CreateTable(); //transaction.Complete(); } @@ -624,11 +607,10 @@ namespace Umbraco.Tests.Persistence [Test] public void Can_Create_umbracoUser2NodeNotify_Table() { - + using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); DatabaseSchemaHelper.CreateTable(); DatabaseSchemaHelper.CreateTable(); @@ -636,16 +618,27 @@ namespace Umbraco.Tests.Persistence } } - [Test] - public void Can_Create_umbracoUser2NodePermission_Table() + public void Can_Create_umbracoGroupUser2app_Table() { - using (Transaction transaction = Database.GetTransaction()) { DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); - DatabaseSchemaHelper.CreateTable(); + DatabaseSchemaHelper.CreateTable(); + DatabaseSchemaHelper.CreateTable(); + + //transaction.Complete(); + } + } + + [Test] + public void Can_Create_umbracoUserGroup2NodePermission_Table() + { + + using (Transaction transaction = Database.GetTransaction()) + { + DatabaseSchemaHelper.CreateTable(); + DatabaseSchemaHelper.CreateTable(); + DatabaseSchemaHelper.CreateTable(); //transaction.Complete(); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index 6cb97feec1..f8ff391c32 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -2,26 +2,19 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text.RegularExpressions; using System.Xml.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; -using Umbraco.Core.Persistence; - -using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; -using umbraco.editorControls.tinyMCE3; -using umbraco.interfaces; using Umbraco.Core.Persistence.DatabaseModelDefinitions; namespace Umbraco.Tests.Persistence.Repositories @@ -71,6 +64,11 @@ namespace Umbraco.Tests.Persistence.Repositories return repository; } + private UserGroupRepository CreateUserGroupRepository(IDatabaseUnitOfWork unitOfWork) + { + return new UserGroupRepository(unitOfWork, CacheHelper, Logger, SqlSyntax); + } + [Test] public void Get_Always_Returns_Latest_Version() { @@ -544,7 +542,14 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - ContentTypeRepository contentTypeRepository; + 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"); @@ -558,7 +563,7 @@ namespace Umbraco.Tests.Persistence.Repositories unitOfWork.Commit(); // Act - repository.AssignEntityPermission(parentPage, 'A', new int[] { 0 }); + repository.AssignEntityPermission(parentPage, 'A', new [] { 1 }); var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage); repository.AddOrUpdate(childPage); unitOfWork.Commit(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/NotificationsRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/NotificationsRepositoryTest.cs index f2aa367ffd..79340d71b3 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/NotificationsRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/NotificationsRepositoryTest.cs @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); using (var repo = new NotificationsRepository(unitOfWork)) { - var userDto = new UserDto { ContentStartId = -1, Email = "test", Login = "test", MediaStartId = -1, Password = "test", Type = 1, UserName = "test", UserLanguage = "en" }; + var userDto = new UserDto { ContentStartId = -1, Email = "test" , Login = "test" , MediaStartId = -1, Password = "test" , UserName = "test" , UserLanguage = "en" }; unitOfWork.Database.Insert(userDto); var userNew = Mock.Of(e => e.Id == userDto.Id); @@ -81,7 +81,7 @@ namespace Umbraco.Tests.Persistence.Repositories for (var i = 0; i < 10; i++) { - var userDto = new UserDto { ContentStartId = -1, Email = "test" + i, Login = "test" + i, MediaStartId = -1, Password = "test", Type = 1, UserName = "test" + i, UserLanguage = "en" }; + var userDto = new UserDto { ContentStartId = -1, Email = "test" + i, Login = "test" + i, MediaStartId = -1, Password = "test", UserName = "test" + i, UserLanguage = "en" }; unitOfWork.Database.Insert(userDto); var userNew = Mock.Of(e => e.Id == userDto.Id); var notification = repo.CreateNotification(userNew, (i % 2 == 0) ? entity1 : entity2, i.ToString(CultureInfo.InvariantCulture)); @@ -109,7 +109,7 @@ namespace Umbraco.Tests.Persistence.Repositories for (var i = 0; i < 10; i++) { - var userDto = new UserDto { ContentStartId = -1, Email = "test" + i, Login = "test" + i, MediaStartId = -1, Password = "test", Type = 1, UserName = "test" + i, UserLanguage = "en" }; + var userDto = new UserDto { ContentStartId = -1, Email = "test" + i, Login = "test" + i, MediaStartId = -1, Password = "test", UserName = "test" + i, UserLanguage = "en" }; unitOfWork.Database.Insert(userDto); var userNew = Mock.Of(e => e.Id == userDto.Id); var notification = repo.CreateNotification(userNew, (i % 2 == 0) ? entity1 : entity2, i.ToString(CultureInfo.InvariantCulture)); @@ -128,7 +128,7 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); using (var repo = new NotificationsRepository(unitOfWork)) { - var userDto = new UserDto { ContentStartId = -1, Email = "test", Login = "test", MediaStartId = -1, Password = "test", Type = 1, UserName = "test", UserLanguage = "en" }; + var userDto = new UserDto { ContentStartId = -1, Email = "test", Login = "test", MediaStartId = -1, Password = "test", UserName = "test", UserLanguage = "en" }; unitOfWork.Database.Insert(userDto); var userNew = Mock.Of(e => e.Id == userDto.Id); diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs new file mode 100644 index 0000000000..6a2412bc63 --- /dev/null +++ b/src/Umbraco.Tests/Persistence/Repositories/UserGroupRepositoryTest.cs @@ -0,0 +1,427 @@ +using System.Linq; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Persistence; + +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.UnitOfWork; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; + +namespace Umbraco.Tests.Persistence.Repositories +{ + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] + [TestFixture] + public class UserGroupRepositoryTest : BaseDatabaseFactoryTest + { + [SetUp] + public override void Initialize() + { + base.Initialize(); + } + + [TearDown] + public override void TearDown() + { + base.TearDown(); + } + + private UserGroupRepository CreateRepository(IDatabaseUnitOfWork unitOfWork) + { + return new UserGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); + } + + [Test] + public void Can_Perform_Add_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + + var userType = MockedUserGroup.CreateUserGroup(); + + // Act + repository.AddOrUpdate(userType); + unitOfWork.Commit(); + + // Assert + Assert.That(userType.HasIdentity, Is.True); + } + } + + [Test] + public void Can_Perform_Multiple_Adds_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + + var userType1 = MockedUserGroup.CreateUserGroup("1"); + var userType2 = MockedUserGroup.CreateUserGroup("2"); + + // Act + repository.AddOrUpdate(userType1); + unitOfWork.Commit(); + repository.AddOrUpdate(userType2); + unitOfWork.Commit(); + + // Assert + Assert.That(userType1.HasIdentity, Is.True); + Assert.That(userType2.HasIdentity, Is.True); + } + } + + [Test] + public void Can_Verify_Fresh_Entity_Is_Not_Dirty() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var userType = MockedUserGroup.CreateUserGroup(); + repository.AddOrUpdate(userType); + unitOfWork.Commit(); + + // Act + var resolved = repository.Get(userType.Id); + bool dirty = ((UserGroup) resolved).IsDirty(); + + // Assert + Assert.That(dirty, Is.False); + } + } + + [Test] + public void Can_Perform_Update_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var userType = MockedUserGroup.CreateUserGroup(); + repository.AddOrUpdate(userType); + unitOfWork.Commit(); + + // Act + var resolved = repository.Get(userType.Id); + resolved.Name = "New Name"; + resolved.Permissions = new[]{"Z", "Y", "X"}; + repository.AddOrUpdate(resolved); + unitOfWork.Commit(); + var updatedItem = repository.Get(userType.Id); + + // Assert + Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id)); + Assert.That(updatedItem.Name, Is.EqualTo(resolved.Name)); + Assert.That(updatedItem.Permissions, Is.EqualTo(resolved.Permissions)); + } + } + + [Test] + public void Can_Perform_Delete_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + + var userType = MockedUserGroup.CreateUserGroup(); + + // Act + repository.AddOrUpdate(userType); + unitOfWork.Commit(); + var id = userType.Id; + + using (var repository2 = new UserGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax)) + { + repository2.Delete(userType); + unitOfWork.Commit(); + + var resolved = repository2.Get(id); + + // Assert + Assert.That(resolved, Is.Null); + } + + } + } + + [Test] + public void Can_Perform_Get_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var userType = MockedUserGroup.CreateUserGroup(); + repository.AddOrUpdate(userType); + unitOfWork.Commit(); + + // Act + var resolved = repository.Get(userType.Id); + + // Assert + Assert.That(resolved.Id, Is.EqualTo(userType.Id)); + //Assert.That(resolved.CreateDate, Is.GreaterThan(DateTime.MinValue)); + //Assert.That(resolved.UpdateDate, Is.GreaterThan(DateTime.MinValue)); + Assert.That(resolved.Name, Is.EqualTo(userType.Name)); + Assert.That(resolved.Alias, Is.EqualTo(userType.Alias)); + Assert.That(resolved.Permissions, Is.EqualTo(userType.Permissions)); + } + } + + [Test] + public void Can_Perform_GetByQuery_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + var query = Query.Builder.Where(x => x.Alias == "testUserGroup1"); + var result = repository.GetByQuery(query); + + // Assert + Assert.That(result.Count(), Is.GreaterThanOrEqualTo(1)); + } + } + + [Test] + public void Can_Perform_GetAll_By_Param_Ids_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var userTypes = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + var result = repository.GetAll(userTypes[0].Id, userTypes[1].Id); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Any(), Is.True); + Assert.That(result.Count(), Is.EqualTo(2)); + } + } + + [Test] + public void Can_Perform_GetAll_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + var result = repository.GetAll(); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Any(), Is.True); + Assert.That(result.Count(), Is.GreaterThanOrEqualTo(3)); + } + } + + [Test] + public void Can_Perform_Exists_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var userTypes = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + var exists = repository.Exists(userTypes[0].Id); + + // Assert + Assert.That(exists, Is.True); + } + } + + [Test] + public void Can_Perform_Count_On_UserGroupRepository() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var userTypes = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + var query = Query.Builder.Where(x => x.Alias == "testUserGroup1" || x.Alias == "testUserGroup2"); + var result = repository.Count(query); + + // Assert + Assert.That(result, Is.GreaterThanOrEqualTo(2)); + } + } + + [Test] + public void Can_Remove_Section_For_Group() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var groups = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + + //add and remove a few times, this tests the internal collection + groups[0].RemoveAllowedSection("content"); + groups[0].RemoveAllowedSection("content"); + groups[0].AddAllowedSection("content"); + groups[0].RemoveAllowedSection("content"); + + groups[1].RemoveAllowedSection("media"); + groups[1].RemoveAllowedSection("media"); + + repository.AddOrUpdate(groups[0]); + repository.AddOrUpdate(groups[1]); + unitOfWork.Commit(); + + // Assert + var result = repository.GetAll((int)groups[0].Id, (int)groups[1].Id).ToArray(); + Assert.AreEqual(1, result[0].AllowedSections.Count()); + Assert.AreEqual("media", result[0].AllowedSections.First()); + Assert.AreEqual(1, result[1].AllowedSections.Count()); + Assert.AreEqual("content", result[1].AllowedSections.First()); + } + } + + [Test] + public void Can_Add_Section_ForGroup() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var groups = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + + //add and remove a few times, this tests the internal collection + groups[0].ClearAllowedSections(); + groups[0].AddAllowedSection("content"); + groups[0].AddAllowedSection("media"); + groups[0].RemoveAllowedSection("content"); + groups[0].AddAllowedSection("content"); + groups[0].AddAllowedSection("settings"); + + //add the same even though it's already there + groups[0].AddAllowedSection("content"); + + groups[1].ClearAllowedSections(); + groups[1].AddAllowedSection("developer"); + + groups[2].ClearAllowedSections(); + + repository.AddOrUpdate(groups[0]); + repository.AddOrUpdate(groups[1]); + repository.AddOrUpdate(groups[2]); + unitOfWork.Commit(); + + // Assert + var result = repository.GetAll((int)groups[0].Id, (int)groups[1].Id, (int)groups[2].Id).ToArray(); + Assert.AreEqual(3, result[0].AllowedSections.Count()); + Assert.IsTrue(result[0].AllowedSections.Contains("content")); + Assert.IsTrue(result[0].AllowedSections.Contains("media")); + Assert.IsTrue(result[0].AllowedSections.Contains("settings")); + Assert.AreEqual(1, result[1].AllowedSections.Count()); + Assert.IsTrue(result[1].AllowedSections.Contains("developer")); + Assert.AreEqual(0, result[2].AllowedSections.Count()); + } + } + + [Test] + public void Can_Update_Section_For_Group() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var groups = CreateAndCommitMultipleUserGroups(repository, unitOfWork); + + // Act + + groups[0].RemoveAllowedSection("content"); + groups[0].AddAllowedSection("settings"); + + repository.AddOrUpdate(groups[0]); + unitOfWork.Commit(); + + // Assert + var result = repository.Get((int)groups[0].Id); + Assert.AreEqual(2, result.AllowedSections.Count()); + Assert.IsTrue(result.AllowedSections.Contains("settings")); + Assert.IsTrue(result.AllowedSections.Contains("media")); + } + } + + + [Test] + public void Get_Groups_Assigned_To_Section() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(Logger); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var user1 = MockedUserGroup.CreateUserGroup("1", allowedSections: new[] { "test1" }); + var user2 = MockedUserGroup.CreateUserGroup("2", allowedSections: new[] { "test2" }); + var user3 = MockedUserGroup.CreateUserGroup("3", allowedSections: new[] { "test1" }); + repository.AddOrUpdate(user1); + repository.AddOrUpdate(user2); + repository.AddOrUpdate(user3); + unitOfWork.Commit(); + + // Act + var groups = repository.GetGroupsAssignedToSection("test1"); + + // Assert + Assert.AreEqual(2, groups.Count()); + var names = groups.Select(x => x.Name).ToArray(); + Assert.IsTrue(names.Contains("TestUserGroup1")); + Assert.IsFalse(names.Contains("TestUserGroup2")); + Assert.IsTrue(names.Contains("TestUserGroup3")); + } + } + + private IUserGroup[] CreateAndCommitMultipleUserGroups(IUserGroupRepository repository, IUnitOfWork unitOfWork) + { + var userGroup1 = MockedUserGroup.CreateUserGroup("1"); + var userGroup2 = MockedUserGroup.CreateUserGroup("2"); + var userGroup3 = MockedUserGroup.CreateUserGroup("3"); + repository.AddOrUpdate(userGroup1); + repository.AddOrUpdate(userGroup2); + repository.AddOrUpdate(userGroup3); + unitOfWork.Commit(); + return new IUserGroup[] { userGroup1, userGroup2, userGroup3 }; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 0aae63d995..f13175f563 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models.Membership; -using Umbraco.Core.Persistence; - using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.UnitOfWork; @@ -39,6 +35,10 @@ namespace Umbraco.Tests.Persistence.Repositories return repository; } + private UserGroupRepository CreateUserGroupRepository(IDatabaseUnitOfWork unitOfWork) + { + return new UserGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); + } [Test] public void Can_Perform_Add_On_UserRepository() @@ -46,11 +46,9 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { - - var user = MockedUser.CreateUser(CreateAndCommitUserType()); + var user = MockedUser.CreateUser(); // Act repository.AddOrUpdate(user); @@ -67,12 +65,10 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { - - var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1"); - var use2 = MockedUser.CreateUser(CreateAndCommitUserType(), "2"); + var user1 = MockedUser.CreateUser("1"); + var use2 = MockedUser.CreateUser("2"); // Act repository.AddOrUpdate(user1); @@ -92,10 +88,9 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { - var user = MockedUser.CreateUser(CreateAndCommitUserType()); + var user = MockedUser.CreateUser(); repository.AddOrUpdate(user); unitOfWork.Commit(); @@ -114,19 +109,15 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) + using (var userGroupRepository = CreateUserGroupRepository(unitOfWork)) { - var user = MockedUser.CreateUser(CreateAndCommitUserType()); - repository.AddOrUpdate(user); - unitOfWork.Commit(); + var user = CreateAndCommitUserWithGroup(repository, userGroupRepository, unitOfWork); // Act var resolved = (User)repository.Get((int)user.Id); resolved.Name = "New Name"; - //the db column is not used, default permissions are taken from the user type's permissions, this is a getter only - //resolved.DefaultPermissions = "ZYX"; resolved.Language = "fr"; resolved.IsApproved = false; resolved.RawPasswordValue = "new"; @@ -135,7 +126,6 @@ namespace Umbraco.Tests.Persistence.Repositories resolved.StartMediaId = 11; resolved.Email = "new@new.com"; resolved.Username = "newName"; - resolved.RemoveAllowedSection("content"); repository.AddOrUpdate(resolved); unitOfWork.Commit(); @@ -144,7 +134,6 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id)); Assert.That(updatedItem.Name, Is.EqualTo(resolved.Name)); - //Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(resolved.DefaultPermissions)); Assert.That(updatedItem.Language, Is.EqualTo(resolved.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(resolved.IsApproved)); Assert.That(updatedItem.RawPasswordValue, Is.EqualTo(resolved.RawPasswordValue)); @@ -153,7 +142,8 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(updatedItem.StartMediaId, Is.EqualTo(resolved.StartMediaId)); Assert.That(updatedItem.Email, Is.EqualTo(resolved.Email)); Assert.That(updatedItem.Username, Is.EqualTo(resolved.Username)); - Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(1)); + Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(2)); + Assert.IsTrue(updatedItem.AllowedSections.Contains("content")); Assert.IsTrue(updatedItem.AllowedSections.Contains("media")); } } @@ -164,19 +154,17 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { - var user = MockedUser.CreateUser(CreateAndCommitUserType()); + var user = MockedUser.CreateUser(); // Act repository.AddOrUpdate(user); unitOfWork.Commit(); var id = user.Id; - using (var utRepo = new UserTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax)) - using (var repository2 = new UserRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax, utRepo)) + using (var repository2 = new UserRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax)) { repository2.Delete(user); unitOfWork.Commit(); @@ -195,8 +183,7 @@ namespace Umbraco.Tests.Persistence.Repositories // // Arrange // var provider = new PetaPocoUnitOfWorkProvider(Logger); // var unitOfWork = provider.GetUnitOfWork(); - // UserTypeRepository userTypeRepository; - //using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + //using (var repository = CreateRepository(unitOfWork)) //{ // var user = MockedUser.CreateUser(CreateAndCommitUserType()); @@ -225,15 +212,13 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) + using (var userGroupRepository = CreateUserGroupRepository(unitOfWork)) { - var user = MockedUser.CreateUser(CreateAndCommitUserType()); - repository.AddOrUpdate(user); - unitOfWork.Commit(); + var user = CreateAndCommitUserWithGroup(repository, userGroupRepository, unitOfWork); // Act - var updatedItem = repository.Get((int) user.Id); + var updatedItem = repository.Get((int)user.Id); // Assert AssertPropertyValues(updatedItem, user); @@ -246,8 +231,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { CreateAndCommitMultipleUsers(repository, unitOfWork); @@ -266,8 +250,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { var users = CreateAndCommitMultipleUsers(repository, unitOfWork); @@ -287,8 +270,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { CreateAndCommitMultipleUsers(repository, unitOfWork); @@ -308,8 +290,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { var users = CreateAndCommitMultipleUsers(repository, unitOfWork); @@ -327,8 +308,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) + using (var repository = CreateRepository(unitOfWork)) { var users = CreateAndCommitMultipleUsers(repository, unitOfWork); @@ -341,170 +321,10 @@ namespace Umbraco.Tests.Persistence.Repositories } } - [Test] - public void Can_Remove_Section_For_User() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) - { - var users = CreateAndCommitMultipleUsers(repository, unitOfWork); - - // Act - - //add and remove a few times, this tests the internal collection - users[0].RemoveAllowedSection("content"); - users[0].RemoveAllowedSection("content"); - users[0].AddAllowedSection("content"); - users[0].RemoveAllowedSection("content"); - - users[1].RemoveAllowedSection("media"); - users[1].RemoveAllowedSection("media"); - - repository.AddOrUpdate(users[0]); - repository.AddOrUpdate(users[1]); - unitOfWork.Commit(); - - // Assert - var result = repository.GetAll((int) users[0].Id, (int) users[1].Id).ToArray(); - Assert.AreEqual(1, result[0].AllowedSections.Count()); - Assert.AreEqual("media", result[0].AllowedSections.First()); - Assert.AreEqual(1, result[1].AllowedSections.Count()); - Assert.AreEqual("content", result[1].AllowedSections.First()); - } - } - - [Test] - public void Can_Add_Section_For_User() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) - { - var users = CreateAndCommitMultipleUsers(repository, unitOfWork); - - // Act - - //add and remove a few times, this tests the internal collection - users[0].AddAllowedSection("settings"); - users[0].AddAllowedSection("settings"); - users[0].RemoveAllowedSection("settings"); - users[0].AddAllowedSection("settings"); - - users[1].AddAllowedSection("developer"); - - //add the same even though it's already there - users[2].AddAllowedSection("content"); - - repository.AddOrUpdate(users[0]); - repository.AddOrUpdate(users[1]); - unitOfWork.Commit(); - - // Assert - var result = repository.GetAll((int) users[0].Id, (int) users[1].Id, (int) users[2].Id).ToArray(); - Assert.AreEqual(3, result[0].AllowedSections.Count()); - Assert.IsTrue(result[0].AllowedSections.Contains("content")); - Assert.IsTrue(result[0].AllowedSections.Contains("media")); - Assert.IsTrue(result[0].AllowedSections.Contains("settings")); - Assert.AreEqual(3, result[1].AllowedSections.Count()); - Assert.IsTrue(result[1].AllowedSections.Contains("content")); - Assert.IsTrue(result[1].AllowedSections.Contains("media")); - Assert.IsTrue(result[1].AllowedSections.Contains("developer")); - Assert.AreEqual(2, result[2].AllowedSections.Count()); - Assert.IsTrue(result[1].AllowedSections.Contains("content")); - Assert.IsTrue(result[1].AllowedSections.Contains("media")); - } - } - - [Test] - public void Can_Update_Section_For_User() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) - { - var users = CreateAndCommitMultipleUsers(repository, unitOfWork); - - // Act - - users[0].RemoveAllowedSection("content"); - users[0].AddAllowedSection("settings"); - - repository.AddOrUpdate(users[0]); - unitOfWork.Commit(); - - // Assert - var result = repository.Get((int) users[0].Id); - Assert.AreEqual(2, result.AllowedSections.Count()); - Assert.IsTrue(result.AllowedSections.Contains("settings")); - Assert.IsTrue(result.AllowedSections.Contains("media")); - } - } - - - [Test] - public void Get_Users_Assigned_To_Section() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - UserTypeRepository userTypeRepository; - using (var repository = CreateRepository(unitOfWork, out userTypeRepository)) - { - var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1", "test", "media"); - var user2 = MockedUser.CreateUser(CreateAndCommitUserType(), "2", "media", "settings"); - var user3 = MockedUser.CreateUser(CreateAndCommitUserType(), "3", "test", "settings"); - repository.AddOrUpdate(user1); - repository.AddOrUpdate(user2); - repository.AddOrUpdate(user3); - unitOfWork.Commit(); - - // Act - - var users = repository.GetUsersAssignedToSection("test"); - - // Assert - Assert.AreEqual(2, users.Count()); - var names = users.Select(x => x.Username).ToArray(); - Assert.IsTrue(names.Contains("TestUser1")); - Assert.IsTrue(names.Contains("TestUser3")); - } - } - - [Test] - public void Default_User_Permissions_Based_On_User_Type() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var utRepo = new UserTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax)) - using (var repository = new UserRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax, utRepo)) - { - - // Act - var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1", "test", "media"); - repository.AddOrUpdate(user1); - unitOfWork.Commit(); - - // Assert - Assert.AreEqual(3, user1.DefaultPermissions.Count()); - Assert.AreEqual("A", user1.DefaultPermissions.ElementAt(0)); - Assert.AreEqual("B", user1.DefaultPermissions.ElementAt(1)); - Assert.AreEqual("C", user1.DefaultPermissions.ElementAt(2)); - } - } - private void AssertPropertyValues(IUser updatedItem, IUser originalUser) { Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id)); Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name)); - Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(originalUser.DefaultPermissions)); Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); Assert.That(updatedItem.RawPasswordValue, Is.EqualTo(originalUser.RawPasswordValue)); @@ -518,29 +338,31 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.IsTrue(updatedItem.AllowedSections.Contains("content")); } + private static User CreateAndCommitUserWithGroup(IUserRepository repository, IUserGroupRepository userGroupRepository, IDatabaseUnitOfWork unitOfWork) + { + var group = MockedUserGroup.CreateUserGroup(); + userGroupRepository.AddOrUpdate(@group); + unitOfWork.Commit(); + + var user = MockedUser.CreateUser(); + repository.AddOrUpdate(user); + unitOfWork.Commit(); + + userGroupRepository.AddUsersToGroup(@group.Id, new[] { user.Id }); + unitOfWork.Commit(); + return user; + } + private IUser[] CreateAndCommitMultipleUsers(IUserRepository repository, IUnitOfWork unitOfWork) { - var user1 = MockedUser.CreateUser(CreateAndCommitUserType(), "1"); - var user2 = MockedUser.CreateUser(CreateAndCommitUserType(), "2"); - var user3 = MockedUser.CreateUser(CreateAndCommitUserType(), "3"); + var user1 = MockedUser.CreateUser("1"); + var user2 = MockedUser.CreateUser("2"); + var user3 = MockedUser.CreateUser("3"); repository.AddOrUpdate(user1); repository.AddOrUpdate(user2); repository.AddOrUpdate(user3); unitOfWork.Commit(); return new IUser[] { user1, user2, user3 }; } - - private IUserType CreateAndCommitUserType() - { - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new UserTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax)) - { - var userType = MockedUserType.CreateUserType(); - repository.AddOrUpdate(userType); - unitOfWork.Commit(); - return userType; - } - } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs deleted file mode 100644 index 963f9eb6aa..0000000000 --- a/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs +++ /dev/null @@ -1,293 +0,0 @@ -using System.Linq; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Persistence; - -using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.Repositories; -using Umbraco.Core.Persistence.UnitOfWork; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; - -namespace Umbraco.Tests.Persistence.Repositories -{ - [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] - [TestFixture] - public class UserTypeRepositoryTest : BaseDatabaseFactoryTest - { - [SetUp] - public override void Initialize() - { - base.Initialize(); - } - - [TearDown] - public override void TearDown() - { - base.TearDown(); - } - - private UserTypeRepository CreateRepository(IScopeUnitOfWork unitOfWork) - { - return new UserTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); - } - - [Test] - public void Can_Perform_Add_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - - var userType = MockedUserType.CreateUserType(); - - // Act - repository.AddOrUpdate(userType); - unitOfWork.Commit(); - - // Assert - Assert.That(userType.HasIdentity, Is.True); - } - } - - [Test] - public void Can_Perform_Multiple_Adds_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - - var userType1 = MockedUserType.CreateUserType("1"); - var userType2 = MockedUserType.CreateUserType("2"); - - // Act - repository.AddOrUpdate(userType1); - unitOfWork.Commit(); - repository.AddOrUpdate(userType2); - unitOfWork.Commit(); - - // Assert - Assert.That(userType1.HasIdentity, Is.True); - Assert.That(userType2.HasIdentity, Is.True); - } - } - - [Test] - public void Can_Verify_Fresh_Entity_Is_Not_Dirty() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - var userType = MockedUserType.CreateUserType(); - repository.AddOrUpdate(userType); - unitOfWork.Commit(); - - // Act - var resolved = repository.Get(userType.Id); - bool dirty = ((UserType) resolved).IsDirty(); - - // Assert - Assert.That(dirty, Is.False); - } - } - - [Test] - public void Can_Perform_Update_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - var userType = MockedUserType.CreateUserType(); - repository.AddOrUpdate(userType); - unitOfWork.Commit(); - - // Act - var resolved = repository.Get(userType.Id); - resolved.Name = "New Name"; - resolved.Permissions = new[]{"Z", "Y", "X"}; - repository.AddOrUpdate(resolved); - unitOfWork.Commit(); - var updatedItem = repository.Get(userType.Id); - - // Assert - Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id)); - Assert.That(updatedItem.Name, Is.EqualTo(resolved.Name)); - Assert.That(updatedItem.Permissions, Is.EqualTo(resolved.Permissions)); - } - } - - [Test] - public void Can_Perform_Delete_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - - var userType = MockedUserType.CreateUserType(); - - // Act - repository.AddOrUpdate(userType); - unitOfWork.Commit(); - var id = userType.Id; - - using (var repository2 = new UserTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, SqlSyntax)) - { - repository2.Delete(userType); - unitOfWork.Commit(); - - var resolved = repository2.Get(id); - - // Assert - Assert.That(resolved, Is.Null); - } - - } - } - - [Test] - public void Can_Perform_Get_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - var userType = MockedUserType.CreateUserType(); - repository.AddOrUpdate(userType); - unitOfWork.Commit(); - - // Act - var resolved = repository.Get(userType.Id); - - // Assert - Assert.That(resolved.Id, Is.EqualTo(userType.Id)); - //Assert.That(resolved.CreateDate, Is.GreaterThan(DateTime.MinValue)); - //Assert.That(resolved.UpdateDate, Is.GreaterThan(DateTime.MinValue)); - Assert.That(resolved.Name, Is.EqualTo(userType.Name)); - Assert.That(resolved.Alias, Is.EqualTo(userType.Alias)); - Assert.That(resolved.Permissions, Is.EqualTo(userType.Permissions)); - } - } - - [Test] - public void Can_Perform_GetByQuery_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - CreateAndCommitMultipleUserTypes(repository, unitOfWork); - - // Act - var query = Query.Builder.Where(x => x.Alias == "testUserType1"); - var result = repository.GetByQuery(query); - - // Assert - Assert.That(result.Count(), Is.GreaterThanOrEqualTo(1)); - } - } - - [Test] - public void Can_Perform_GetAll_By_Param_Ids_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - var userTypes = CreateAndCommitMultipleUserTypes(repository, unitOfWork); - - // Act - var result = repository.GetAll(userTypes[0].Id, userTypes[1].Id); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Any(), Is.True); - Assert.That(result.Count(), Is.EqualTo(2)); - } - } - - [Test] - public void Can_Perform_GetAll_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - CreateAndCommitMultipleUserTypes(repository, unitOfWork); - - // Act - var result = repository.GetAll(); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Any(), Is.True); - Assert.That(result.Count(), Is.GreaterThanOrEqualTo(3)); - } - } - - [Test] - public void Can_Perform_Exists_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - var userTypes = CreateAndCommitMultipleUserTypes(repository, unitOfWork); - - // Act - var exists = repository.Exists(userTypes[0].Id); - - // Assert - Assert.That(exists, Is.True); - } - } - - [Test] - public void Can_Perform_Count_On_UserTypeRepository() - { - // Arrange - var provider = new PetaPocoUnitOfWorkProvider(Logger); - var unitOfWork = provider.GetUnitOfWork(); - using (var repository = CreateRepository(unitOfWork)) - { - var userTypes = CreateAndCommitMultipleUserTypes(repository, unitOfWork); - - // Act - var query = Query.Builder.Where(x => x.Alias == "testUserType1" || x.Alias == "testUserType2"); - var result = repository.Count(query); - - // Assert - Assert.That(result, Is.GreaterThanOrEqualTo(2)); - } - } - - private IUserType[] CreateAndCommitMultipleUserTypes(IUserTypeRepository repository, IUnitOfWork unitOfWork) - { - var userType1 = MockedUserType.CreateUserType("1"); - var userType2 = MockedUserType.CreateUserType("2"); - var userType3 = MockedUserType.CreateUserType("3"); - repository.AddOrUpdate(userType1); - repository.AddOrUpdate(userType2); - repository.AddOrUpdate(userType3); - unitOfWork.Commit(); - return new IUserType[] {userType1, userType2, userType3}; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index c598b272d7..a6fb9d64ca 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -644,7 +644,7 @@ namespace Umbraco.Tests.Services [Test] public void Can_Save_New_Content_With_Explicit_User() { - var user = new User(ServiceContext.UserService.GetUserTypeByAlias("admin")) + var user = new User() { Name = "Test", Email = "test@test.com", diff --git a/src/Umbraco.Tests/Services/SectionServiceTests.cs b/src/Umbraco.Tests/Services/SectionServiceTests.cs new file mode 100644 index 0000000000..556203bb61 --- /dev/null +++ b/src/Umbraco.Tests/Services/SectionServiceTests.cs @@ -0,0 +1,77 @@ +using NUnit.Framework; +using Umbraco.Core.Services; +using Umbraco.Tests.TestHelpers; +using System; +using System.Linq; +using Umbraco.Core.Models.Membership; + +namespace Umbraco.Tests.Services +{ + /// + /// Tests covering the SectionService + /// + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] + [TestFixture, RequiresSTA] + public class SectionServiceTests : BaseServiceTest + { + [SetUp] + public override void Initialize() + { + base.Initialize(); + } + + public override void CreateTestData() + { + base.CreateTestData(); + + ServiceContext.SectionService.MakeNew("Content", "content", "icon-content"); + ServiceContext.SectionService.MakeNew("Media", "media", "icon-media"); + ServiceContext.SectionService.MakeNew("Settings", "settings", "icon-settings"); + ServiceContext.SectionService.MakeNew("Developer", "developer", "icon-developer"); + } + + [Test] + public void SectionService_Can_Get_Allowed_Sections_For_User() + { + // Arrange + var user = CreateTestUser(); + + // Act + var result = ServiceContext.SectionService.GetAllowedSections(user.Id).ToList(); + + // Assert + Assert.AreEqual(3, result.Count); + } + + private IUser CreateTestUser() + { + var user = new User + { + Name = "Test user", + Username = "testUser", + Email = "testuser@test.com", + }; + ServiceContext.UserService.Save(user, false); + + var userGroupA = new UserGroup + { + Alias = "GroupA", + Name = "Group A" + }; + userGroupA.AddAllowedSection("media"); + userGroupA.AddAllowedSection("settings"); + ServiceContext.UserService.SaveUserGroup(userGroupA, true, new[] { user.Id }, false); + + var userGroupB = new UserGroup + { + Alias = "GroupB", + Name = "Group B" + }; + userGroupB.AddAllowedSection("settings"); + userGroupB.AddAllowedSection("developer"); + ServiceContext.UserService.SaveUserGroup(userGroupB, true, new[] { user.Id }, false); + + return ServiceContext.UserService.GetUserById(user.Id); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs index 833ed1771b..e05b9e6225 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests/Services/UserServiceTests.cs @@ -39,8 +39,8 @@ namespace Umbraco.Tests.Services { // Arrange var userService = ServiceContext.UserService; - var userType = userService.GetUserTypeByAlias("admin"); - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); + var user = CreateTestUser(); + var contentType = MockedContentTypes.CreateSimpleContentType(); ServiceContext.ContentTypeService.Save(contentType); var content = new[] @@ -66,8 +66,8 @@ namespace Umbraco.Tests.Services { // Arrange var userService = ServiceContext.UserService; - var userType = userService.GetUserTypeByAlias("admin"); - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); + var user = CreateTestUser(); + var contentType = MockedContentTypes.CreateSimpleContentType(); ServiceContext.ContentTypeService.Save(contentType); var content = new[] @@ -77,14 +77,12 @@ namespace Umbraco.Tests.Services MockedContent.CreateSimpleContent(contentType) }; ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionBrowse.Instance.Letter, new int[] { user.Id }); - ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionDelete.Instance.Letter, new int[] { user.Id }); - ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionMove.Instance.Letter, new int[] { user.Id }); - - ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionBrowse.Instance.Letter, new int[] { user.Id }); - ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { user.Id }); - - ServiceContext.ContentService.AssignContentPermission(content.ElementAt(2), ActionBrowse.Instance.Letter, new int[] { user.Id }); + ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionBrowse.Instance.Letter, new int[] { 1 }); + ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionDelete.Instance.Letter, new int[] { 1 }); + ServiceContext.ContentService.AssignContentPermission(content.ElementAt(0), ActionMove.Instance.Letter, new int[] { 1 }); + ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionBrowse.Instance.Letter, new int[] { 1 }); + ServiceContext.ContentService.AssignContentPermission(content.ElementAt(1), ActionDelete.Instance.Letter, new int[] { 1 }); + ServiceContext.ContentService.AssignContentPermission(content.ElementAt(2), ActionBrowse.Instance.Letter, new int[] { 1 }); // Act var permissions = userService.GetPermissions(user, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id); @@ -95,13 +93,76 @@ namespace Umbraco.Tests.Services Assert.AreEqual(2, permissions.ElementAt(1).AssignedPermissions.Count()); Assert.AreEqual(1, permissions.ElementAt(2).AssignedPermissions.Count()); } - + + [Test] + public void UserService_Get_UserGroup_Assigned_Permissions() + { + // 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.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 }); + + // Act + var permissions = userService.GetPermissions(userGroup, true, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id); + + //assert + Assert.AreEqual(3, permissions.Count()); + Assert.AreEqual(3, permissions.ElementAt(0).AssignedPermissions.Count()); + Assert.AreEqual(2, permissions.ElementAt(1).AssignedPermissions.Count()); + Assert.AreEqual(1, permissions.ElementAt(2).AssignedPermissions.Count()); + } + + [Test] + public void UserService_Get_UserGroup_Assigned_And_Default_Permissions() + { + // 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.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 }); + + // Act + var permissions = userService.GetPermissions(userGroup, false, content.ElementAt(0).Id, content.ElementAt(1).Id, content.ElementAt(2).Id); + + //assert + Assert.AreEqual(3, permissions.Count()); + Assert.AreEqual(3, permissions.ElementAt(0).AssignedPermissions.Count()); + Assert.AreEqual(2, permissions.ElementAt(1).AssignedPermissions.Count()); + Assert.AreEqual(17, permissions.ElementAt(2).AssignedPermissions.Count()); + } + [Test] public void Can_Delete_User() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); ServiceContext.UserService.Delete(user, true); var deleted = ServiceContext.UserService.GetUserById(user.Id); @@ -113,9 +174,7 @@ namespace Umbraco.Tests.Services [Test] public void Disables_User_Instead_Of_Deleting_If_Flag_Not_Set() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); ServiceContext.UserService.Delete(user); var deleted = ServiceContext.UserService.GetUserById(user.Id); @@ -127,10 +186,8 @@ namespace Umbraco.Tests.Services [Test] public void Exists_By_Username() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); - var user2 = ServiceContext.UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user2 = ServiceContext.UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io"); Assert.IsTrue(ServiceContext.UserService.Exists("JohnDoe")); Assert.IsFalse(ServiceContext.UserService.Exists("notFound")); Assert.IsTrue(ServiceContext.UserService.Exists("john2@umbraco.io")); @@ -139,9 +196,7 @@ namespace Umbraco.Tests.Services [Test] public void Get_By_Email() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); Assert.IsNotNull(ServiceContext.UserService.GetByEmail(user.Email)); Assert.IsNull(ServiceContext.UserService.GetByEmail("do@not.find")); @@ -150,9 +205,7 @@ namespace Umbraco.Tests.Services [Test] public void Get_By_Username() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); @@ -161,9 +214,7 @@ namespace Umbraco.Tests.Services [Test] public void Get_By_Username_With_Backslash() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("mydomain\\JohnDoe", "john@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("mydomain\\JohnDoe", "john@umbraco.io"); Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); @@ -172,9 +223,7 @@ namespace Umbraco.Tests.Services [Test] public void Get_By_Object_Id() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); Assert.IsNotNull(ServiceContext.UserService.GetUserById(user.Id)); Assert.IsNull(ServiceContext.UserService.GetUserById(9876)); @@ -183,12 +232,10 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Starts_With() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10); + var users = MockedUser.CreateMulipleUsers(10); ServiceContext.UserService.Save(users); //don't find this - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); customUser.Email = "hello@hello.com"; ServiceContext.UserService.Save(customUser); @@ -201,12 +248,10 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Ends_With() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10); + var users = MockedUser.CreateMulipleUsers(10); ServiceContext.UserService.Save(users); //include this - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); customUser.Email = "hello@test.com"; ServiceContext.UserService.Save(customUser); @@ -219,12 +264,10 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Contains() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10); + var users = MockedUser.CreateMulipleUsers(10); ServiceContext.UserService.Save(users); //include this - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); customUser.Email = "hello@test.com"; ServiceContext.UserService.Save(customUser); @@ -237,12 +280,10 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Exact() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10); + var users = MockedUser.CreateMulipleUsers(10); ServiceContext.UserService.Save(users); //include this - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); customUser.Email = "hello@test.com"; ServiceContext.UserService.Save(customUser); @@ -255,9 +296,7 @@ namespace Umbraco.Tests.Services [Test] public void Get_All_Paged_Users() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10); + var users = MockedUser.CreateMulipleUsers(10); ServiceContext.UserService.Save(users); int totalRecs; @@ -273,11 +312,9 @@ namespace Umbraco.Tests.Services [Test] public void Count_All_Users() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10); + var users = MockedUser.CreateMulipleUsers(10); ServiceContext.UserService.Save(users); - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); ServiceContext.UserService.Save(customUser); var found = ServiceContext.UserService.GetCount(MemberCountType.All); @@ -290,24 +327,20 @@ namespace Umbraco.Tests.Services [Test] public void Count_All_Online_Users() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10, (i, member) => member.LastLoginDate = DateTime.Now.AddMinutes(i * -2)); + var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.LastLoginDate = DateTime.Now.AddMinutes(i * -2)); ServiceContext.UserService.Save(users); - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); throw new NotImplementedException(); } [Test] public void Count_All_Locked_Users() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10, (i, member) => member.IsLockedOut = i % 2 == 0); + var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.IsLockedOut = i % 2 == 0); ServiceContext.UserService.Save(users); - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); customUser.IsLockedOut = true; ServiceContext.UserService.Save(customUser); @@ -319,12 +352,10 @@ namespace Umbraco.Tests.Services [Test] public void Count_All_Approved_Users() { - var userType = MockedUserType.CreateUserType(); - ServiceContext.UserService.SaveUserType(userType); - var users = MockedUser.CreateUser(userType, 10, (i, member) => member.IsApproved = i % 2 == 0); + var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.IsApproved = i % 2 == 0); ServiceContext.UserService.Save(users); - var customUser = MockedUser.CreateUser(userType); + var customUser = MockedUser.CreateUser(); customUser.IsApproved = false; ServiceContext.UserService.Save(customUser); @@ -334,36 +365,20 @@ namespace Umbraco.Tests.Services Assert.AreEqual(6, found); } - [Test] - public void Can_Persist_New_User_Type() - { - // Arrange - var userService = ServiceContext.UserService; - var userType = MockedUserType.CreateUserType(); - - // Act - userService.SaveUserType(userType); - - // Assert - Assert.That(userType.HasIdentity, Is.True); - } - [Test] public void Can_Persist_New_User() { // Arrange var userService = ServiceContext.UserService; - var userType = userService.GetUserTypeByAlias("admin"); // Act - var membershipUser = userService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io", userType); + var membershipUser = userService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); // Assert Assert.That(membershipUser.HasIdentity, Is.True); Assert.That(membershipUser.Id, Is.GreaterThan(0)); IUser user = membershipUser as User; Assert.That(user, Is.Not.Null); - Assert.That(user.DefaultPermissions, Is.EqualTo(userType.Permissions)); } [Test] @@ -371,7 +386,6 @@ namespace Umbraco.Tests.Services { // Arrange var userService = ServiceContext.UserService; - var userType = userService.GetUserTypeByAlias("admin"); // Act // NOTE: Normally the hash'ing would be handled in the membership provider, so the service just saves the password @@ -379,7 +393,7 @@ namespace Umbraco.Tests.Services var hash = new HMACSHA1(); hash.Key = Encoding.Unicode.GetBytes(password); var encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password))); - var membershipUser = new User("JohnDoe", "john@umbraco.io", encodedPassword, encodedPassword, userType); + var membershipUser = new User("JohnDoe", "john@umbraco.io", encodedPassword, encodedPassword); userService.Save(membershipUser); // Assert @@ -388,106 +402,133 @@ namespace Umbraco.Tests.Services Assert.That(membershipUser.RawPasswordValue, Is.EqualTo(encodedPassword)); IUser user = membershipUser as User; Assert.That(user, Is.Not.Null); - Assert.That(user.DefaultPermissions, Is.EqualTo(userType.Permissions)); } [Test] - public void Can_Add_And_Remove_Sections_From_User() + public void Can_Add_And_Remove_Sections_From_UserGroup() { - var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); + var userGroup = new UserGroup + { + Id = 1, + Alias = "Group1", + Name = "Group 1" + }; + userGroup.AddAllowedSection("content"); + userGroup.AddAllowedSection("mediat"); + ServiceContext.UserService.SaveUserGroup(userGroup); - var user1 = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); + var result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); - var result1 = ServiceContext.UserService.GetUserById((int)user1.Id); - //expect 2 sections by default Assert.AreEqual(2, result1.AllowedSections.Count()); //adds some allowed sections - user1.AddAllowedSection("test1"); - user1.AddAllowedSection("test2"); - user1.AddAllowedSection("test3"); - user1.AddAllowedSection("test4"); - ServiceContext.UserService.Save(user1); + userGroup.AddAllowedSection("test1"); + userGroup.AddAllowedSection("test2"); + userGroup.AddAllowedSection("test3"); + userGroup.AddAllowedSection("test4"); + ServiceContext.UserService.SaveUserGroup(userGroup); + + result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); - result1 = ServiceContext.UserService.GetUserById((int)user1.Id); - //expect 6 sections including the two default sections Assert.AreEqual(6, result1.AllowedSections.Count()); //simulate clearing the sections - foreach (var s in user1.AllowedSections) + foreach (var s in userGroup.AllowedSections) { result1.RemoveAllowedSection(s); } + //now just re-add a couple result1.AddAllowedSection("test3"); result1.AddAllowedSection("test4"); - ServiceContext.UserService.Save(result1); + ServiceContext.UserService.SaveUserGroup(result1); //assert //re-get - result1 = ServiceContext.UserService.GetUserById((int)user1.Id); + result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(2, result1.AllowedSections.Count()); } [Test] - public void Can_Remove_Section_From_All_Assigned_Users() - { - var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); + public void Can_Remove_Section_From_All_Assigned_UserGroups() + { + var userGroup1 = new UserGroup + { + Id = 1, + Alias = "Group1", + Name = "Group 2" + }; + var userGroup2 = new UserGroup + { + Id = 2, + Alias = "Group2", + Name = "Group 2" + }; + ServiceContext.UserService.SaveUserGroup(userGroup1); + ServiceContext.UserService.SaveUserGroup(userGroup2); - var user1 = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); - var user2 = ServiceContext.UserService.CreateUserWithIdentity("test2", "test2@test.com", userType); - //adds some allowed sections - user1.AddAllowedSection("test"); - user2.AddAllowedSection("test"); - ServiceContext.UserService.Save(user1); - ServiceContext.UserService.Save(user2); + userGroup1.AddAllowedSection("test"); + userGroup2.AddAllowedSection("test"); + ServiceContext.UserService.SaveUserGroup(userGroup1); + ServiceContext.UserService.SaveUserGroup(userGroup2); //now clear the section from all users - ServiceContext.UserService.DeleteSectionFromAllUsers("test"); + ServiceContext.UserService.DeleteSectionFromAllUserGroups("test"); //assert - var result1 = ServiceContext.UserService.GetUserById((int)user1.Id); - var result2 = ServiceContext.UserService.GetUserById((int)user2.Id); + var result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); + var result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); Assert.IsFalse(result1.AllowedSections.Contains("test")); Assert.IsFalse(result2.AllowedSections.Contains("test")); } [Test] - public void Can_Add_Section_To_All_Users() + public void Can_Add_Section_To_All_UserGroups() { - var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); + var userGroup1 = new UserGroup + { + Id = 1, + Alias = "Group1", + Name = "Group 1" + }; + var userGroup2 = new UserGroup + { + Id = 2, + Alias = "Group2", + Name = "Group 2" + }; + var userGroup3 = new UserGroup + { + Id = 3, + Alias = "Group3", + Name = "Group 3" + }; + ServiceContext.UserService.SaveUserGroup(userGroup1); + ServiceContext.UserService.SaveUserGroup(userGroup2); + ServiceContext.UserService.SaveUserGroup(userGroup3); - var user1 = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); - var user2 = ServiceContext.UserService.CreateUserWithIdentity("test2", "test2@test.com", userType); - var user3 = ServiceContext.UserService.CreateUserWithIdentity("test3", "test3@test.com", userType); - var user4 = ServiceContext.UserService.CreateUserWithIdentity("test4", "test4@test.com", userType); - - //now add the section to specific users - ServiceContext.UserService.AddSectionToAllUsers("test", (int)user1.Id, (int)user2.Id); + //now add the section to specific groups + ServiceContext.UserService.AddSectionToAllUserGroups("test", userGroup1.Id, userGroup2.Id); //assert - var result1 = ServiceContext.UserService.GetUserById((int)user1.Id); - var result2 = ServiceContext.UserService.GetUserById((int)user2.Id); - var result3 = ServiceContext.UserService.GetUserById((int)user3.Id); - var result4 = ServiceContext.UserService.GetUserById((int)user4.Id); + var result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); + var result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); + var result3 = ServiceContext.UserService.GetUserGroupById(userGroup3.Id); Assert.IsTrue(result1.AllowedSections.Contains("test")); Assert.IsTrue(result2.AllowedSections.Contains("test")); Assert.IsFalse(result3.AllowedSections.Contains("test")); - Assert.IsFalse(result4.AllowedSections.Contains("test")); - //now add the section to all users - ServiceContext.UserService.AddSectionToAllUsers("test"); + //now add the section to all groups + ServiceContext.UserService.AddSectionToAllUserGroups("test"); //assert - result1 = ServiceContext.UserService.GetUserById((int)user1.Id); - result2 = ServiceContext.UserService.GetUserById((int)user2.Id); - result3 = ServiceContext.UserService.GetUserById((int)user3.Id); - result4 = ServiceContext.UserService.GetUserById((int)user4.Id); + result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); + result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); + result3 = ServiceContext.UserService.GetUserGroupById(userGroup3.Id); Assert.IsTrue(result1.AllowedSections.Contains("test")); Assert.IsTrue(result2.AllowedSections.Contains("test")); Assert.IsTrue(result3.AllowedSections.Contains("test")); - Assert.IsTrue(result4.AllowedSections.Contains("test")); } [Test] @@ -531,8 +572,7 @@ namespace Umbraco.Tests.Services public void Get_By_Profile_Username() { // Arrange - var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); + var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); // Act @@ -548,8 +588,7 @@ namespace Umbraco.Tests.Services public void Get_By_Profile_Id() { // Arrange - var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - var user = (IUser)ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); + var user = (IUser)ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); // Act @@ -565,8 +604,7 @@ namespace Umbraco.Tests.Services public void Get_User_By_Username() { // Arrange - var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - var originalUser = (User)ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com", userType); + var originalUser = CreateTestUser(); // Act @@ -576,7 +614,6 @@ namespace Umbraco.Tests.Services Assert.IsNotNull(updatedItem); Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id)); Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name)); - Assert.That(updatedItem.DefaultPermissions, Is.EqualTo(originalUser.DefaultPermissions)); Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); Assert.That(updatedItem.RawPasswordValue, Is.EqualTo(originalUser.RawPasswordValue)); @@ -587,5 +624,31 @@ namespace Umbraco.Tests.Services Assert.That(updatedItem.Username, Is.EqualTo(originalUser.Username)); Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(2)); } + + private IUser CreateTestUser() + { + var userGroup = CreateTestUserGroup(); + + var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + user.AddGroup(userGroup); + user.SetGroupsLoaded(); + ServiceContext.UserService.Save(user); + return user; + } + + private UserGroup CreateTestUserGroup() + { + var userGroup = new UserGroup + { + Id = 1, + Alias = "testGroup", + Name = "Test Group", + Permissions = "ABCDEFGHIJ1234567".ToCharArray().Select(x => x.ToString()) + }; + ServiceContext.UserService.SaveUserGroup(userGroup); + ServiceContext.UserService.AddSectionToAllUserGroups("content", 1); + ServiceContext.UserService.AddSectionToAllUserGroups("media", 1); + return userGroup; + } } } diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs index 15d1ab76fd..53b53e634f 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs @@ -1,58 +1,37 @@ using System; using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; namespace Umbraco.Tests.TestHelpers.Entities { public class MockedUser { - internal static User CreateUser(IUserType userType = null, string suffix = "", params string[] allowedSections) + internal static User CreateUser(string suffix = "") { - if (userType == null) - { - userType = MockedUserType.CreateUserType(); - } - - var user = new User(userType) + var user = new User { Language = "en", IsApproved = true, Name = "TestUser" + suffix, RawPasswordValue = "testing", IsLockedOut = false, - DefaultPermissions = new[]{"A", "B", "C"}, StartContentId = -1, StartMediaId = -1, Email = "test" + suffix + "@test.com", Username = "TestUser" + suffix }; - if (allowedSections.Any()) - { - foreach (var s in allowedSections) - { - user.AddAllowedSection(s); - } - } - else - { - user.AddAllowedSection("content"); - user.AddAllowedSection("media"); - } - return user; } - internal static IEnumerable CreateUser(IUserType userType, int amount, Action onCreating = null) + internal static IEnumerable CreateMulipleUsers(int amount, Action onCreating = null) { var list = new List(); for (int i = 0; i < amount; i++) { var name = "Member No-" + i; - var user = new User(name, "test" + i + "@test.com", "test" + i, "test" + i, userType); + var user = new User(name, "test" + i + "@test.com", "test" + i, "test" + i); if (onCreating != null) { diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs new file mode 100644 index 0000000000..920c84f3c3 --- /dev/null +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs @@ -0,0 +1,32 @@ +using Umbraco.Core.Models.Membership; + +namespace Umbraco.Tests.TestHelpers.Entities +{ + public class MockedUserGroup + { + internal static UserGroup CreateUserGroup(string suffix = "", string[] permissions = null, string[] allowedSections = null) + { + var group = new UserGroup + { + Alias = "testUserGroup" + suffix, + Name = "TestUserGroup" + suffix, + Permissions = permissions ?? new[] { "A", "B", "C" } + }; + + if (allowedSections == null) + { + group.AddAllowedSection("content"); + group.AddAllowedSection("media"); + } + else + { + foreach (var allowedSection in allowedSections) + { + group.AddAllowedSection(allowedSection); + } + } + + return group; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs deleted file mode 100644 index 153ec40b20..0000000000 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Umbraco.Core.Models.Membership; - -namespace Umbraco.Tests.TestHelpers.Entities -{ - public class MockedUserType - { - internal static UserType CreateUserType(string suffix = "") - { - return new UserType() - { - Alias = "testUserType" + suffix, - Name = "TestUserType" + suffix, - Permissions = new[]{"A", "B", "C"} - }; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Tests/TreesAndSections/SectionTests.cs b/src/Umbraco.Tests/TreesAndSections/SectionTests.cs index 67ef50af38..1edd10aec7 100644 --- a/src/Umbraco.Tests/TreesAndSections/SectionTests.cs +++ b/src/Umbraco.Tests/TreesAndSections/SectionTests.cs @@ -70,64 +70,6 @@ namespace Umbraco.Tests.TreesAndSections Assert.IsNull(ApplicationContext.Current.Services.SectionService.GetByAlias(name)); } - /// - /// Creates a new user, assigns the user to existing application, - /// then deletes the user - /// - [Test()] - public void Application_Create_New_User_Assign_Application_And_Delete_User() - { - var name = Guid.NewGuid().ToString("N"); - - //new user - var ut = UserType.GetAllUserTypes().First(); - var user = User.MakeNew(name, name, name, ut); - - //get application - //var app = Application.getAll().First(); - - //assign the app - user.addApplication(Constants.Applications.Content); - //ensure it's added - Assert.AreEqual(1, user.Applications.Count(x => x.alias == Constants.Applications.Content)); - - //delete the user - user.delete(); - - //make sure the assigned applications are gone - Assert.AreEqual(0, user.Applications.Count(x => x.alias == name)); - } - - /// - /// create a new application and assigne an new user and deletes the application making sure the assignments are removed - /// - [Test()] - public void Application_Make_New_Assign_User_And_Delete() - { - var name = Guid.NewGuid().ToString("N"); - - //new user - var ut = UserType.GetAllUserTypes().First(); - var user = User.MakeNew(name, name, name, ut); - - ApplicationContext.Current.Services.SectionService.MakeNew(name, name, "icon.jpg"); - - //check if it exists - var app = ApplicationContext.Current.Services.SectionService.GetByAlias(name); - Assert.IsNotNull(app); - - //assign the app - user.addApplication(app.Alias); - //ensure it's added - Assert.AreEqual(1, user.Applications.Count(x => x.alias == app.Alias)); - - //delete the app - ApplicationContext.Current.Services.SectionService.DeleteSection(app); - - //make sure the assigned applications are gone - Assert.AreEqual(0, user.Applications.Count(x => x.alias == name)); - } - #region Tests to write diff --git a/src/Umbraco.Tests/UI/LegacyDialogTests.cs b/src/Umbraco.Tests/UI/LegacyDialogTests.cs index 0b1514d8a5..a4a0b98a1f 100644 --- a/src/Umbraco.Tests/UI/LegacyDialogTests.cs +++ b/src/Umbraco.Tests/UI/LegacyDialogTests.cs @@ -27,7 +27,6 @@ namespace Umbraco.Tests.UI } } - [TestCase(typeof(UserTypeTasks), DefaultApps.users)] [TestCase(typeof(XsltTasks), DefaultApps.developer)] [TestCase(typeof(userTasks), DefaultApps.users)] [TestCase(typeof(templateTasks), DefaultApps.settings)] diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index eb57d210fc..498bc35c86 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -180,6 +180,8 @@ + + @@ -190,6 +192,7 @@ + @@ -259,7 +262,6 @@ - @@ -360,7 +362,6 @@ - @@ -490,7 +491,6 @@ - diff --git a/src/Umbraco.Tests/Web/Controllers/WebApiEditors/ContentControllerUnitTests.cs b/src/Umbraco.Tests/Web/Controllers/WebApiEditors/ContentControllerUnitTests.cs index 4b78df671d..9634bb164a 100644 --- a/src/Umbraco.Tests/Web/Controllers/WebApiEditors/ContentControllerUnitTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/WebApiEditors/ContentControllerUnitTests.cs @@ -100,7 +100,7 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors var userServiceMock = new Mock(); var permissions = new List { - new EntityPermission(9, 1234, new string[]{ "A", "B", "C" }) + new EntityPermission(1234, new string[]{ "A", "B", "C" }) }; userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions); var userService = userServiceMock.Object; @@ -129,7 +129,7 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors var userServiceMock = new Mock(); var permissions = new List { - new EntityPermission(9, 1234, new string[]{ "A", "F", "C" }) + new EntityPermission(1234, new string[]{ "A", "F", "C" }) }; userServiceMock.Setup(x => x.GetPermissions(user, 1234)).Returns(permissions); var userService = userServiceMock.Object; @@ -217,7 +217,7 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors var userServiceMock = new Mock(); var permissions = new List { - new EntityPermission(9, 1234, new string[]{ "A" }) + new EntityPermission(1234, new string[]{ "A" }) }; userServiceMock.Setup(x => x.GetPermissions(user, -1)).Returns(permissions); var userService = userServiceMock.Object; @@ -241,7 +241,7 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors var userServiceMock = new Mock(); var permissions = new List { - new EntityPermission(9, 1234, new string[]{ "A" }) + new EntityPermission(1234, new string[]{ "A" }) }; userServiceMock.Setup(x => x.GetPermissions(user, -1)).Returns(permissions); var userService = userServiceMock.Object; @@ -265,7 +265,7 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors var userServiceMock = new Mock(); var permissions = new List { - new EntityPermission(9, 1234, new string[]{ "A" }) + new EntityPermission(1234, new string[]{ "A" }) }; userServiceMock.Setup(x => x.GetPermissions(user, -20)).Returns(permissions); var userService = userServiceMock.Object; @@ -289,7 +289,7 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors var userServiceMock = new Mock(); var permissions = new List { - new EntityPermission(9, 1234, new string[]{ "A" }) + new EntityPermission(1234, new string[]{ "A" }) }; userServiceMock.Setup(x => x.GetPermissions(user, -20)).Returns(permissions); var userService = userServiceMock.Object; diff --git a/src/Umbraco.Tests/Web/Controllers/WebApiEditors/FilterAllowedOutgoingContentAttributeTests.cs b/src/Umbraco.Tests/Web/Controllers/WebApiEditors/FilterAllowedOutgoingContentAttributeTests.cs index 1ebe2fc748..c776924af7 100644 --- a/src/Umbraco.Tests/Web/Controllers/WebApiEditors/FilterAllowedOutgoingContentAttributeTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/WebApiEditors/FilterAllowedOutgoingContentAttributeTests.cs @@ -112,10 +112,10 @@ namespace Umbraco.Tests.Web.Controllers.WebApiEditors //we're only assigning 3 nodes browse permissions so that is what we expect as a result var permissions = new List { - new EntityPermission(9, 1, new string[]{ "F" }), - new EntityPermission(9, 2, new string[]{ "F" }), - new EntityPermission(9, 3, new string[]{ "F" }), - new EntityPermission(9, 4, new string[]{ "A" }) + new EntityPermission(1, new string[]{ "F" }), + new EntityPermission(2, new string[]{ "F" }), + new EntityPermission(3, new string[]{ "F" }), + new EntityPermission(4, new string[]{ "A" }) }; userServiceMock.Setup(x => x.GetPermissions(user, ids)).Returns(permissions); var userService = userServiceMock.Object; diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 869d0b7740..afbe9cdd5b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -819,3 +819,8 @@ legend + .control-group { } } + +/* User/group selector */ +.group-selector .group-selector-list { float: left; } +.group-selector .group-selector-list div { height: 24px; } +.group-selector .group-selector-buttons { float: left; margin: 24px 16px; } diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 1b3a44644b..dd1c53c34b 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -571,6 +571,7 @@ + @@ -2218,7 +2219,6 @@ - diff --git a/src/Umbraco.Web.UI/config/trees.Release.config b/src/Umbraco.Web.UI/config/trees.Release.config index dc29fe6417..236e3772bd 100644 --- a/src/Umbraco.Web.UI/config/trees.Release.config +++ b/src/Umbraco.Web.UI/config/trees.Release.config @@ -29,9 +29,9 @@ - - - + + + diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config index 13da9246b7..a1010e8544 100644 --- a/src/Umbraco.Web.UI/config/trees.config +++ b/src/Umbraco.Web.UI/config/trees.config @@ -25,8 +25,8 @@ - - + + @@ -41,4 +41,5 @@ + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/config/create/UI.Release.xml b/src/Umbraco.Web.UI/umbraco/config/create/UI.Release.xml index 9fca6d082a..7af0512ed7 100644 --- a/src/Umbraco.Web.UI/umbraco/config/create/UI.Release.xml +++ b/src/Umbraco.Web.UI/umbraco/config/create/UI.Release.xml @@ -1,5 +1,5 @@ - +
Template
/create/simple.ascx @@ -57,7 +57,7 @@ -
+
membergroup
/create/simple.ascx @@ -78,7 +78,7 @@ -
+
member
/create/member.ascx @@ -92,14 +92,14 @@ -
+
membergroup
/create/simple.ascx -
+
Stylesheet editor egenskab
/create/simple.ascx @@ -235,9 +235,17 @@
+ +
User Groups
+ /create/simple.ascx + + + + +
Macro
- /Create/PartialView.ascx + /Create/PartialView.ascx diff --git a/src/Umbraco.Web.UI/umbraco/config/create/UI.xml b/src/Umbraco.Web.UI/umbraco/config/create/UI.xml index f6859c6423..3edb5fcedc 100644 --- a/src/Umbraco.Web.UI/umbraco/config/create/UI.xml +++ b/src/Umbraco.Web.UI/umbraco/config/create/UI.xml @@ -213,12 +213,12 @@
- -
User Types
+ +
User Groups
/create/simple.ascx - - + +
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index ecea653650..219a0a695d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -973,8 +973,8 @@ To manage your website, simply open the Umbraco back office and start adding con
Do not close this window during sorting]]>
- Validation - Validation errors must be fixed before the item can be saved + Validation + Validation errors must be fixed before the item can be saved Failed Insufficient user permissions, could not complete the operation Cancelled @@ -1009,6 +1009,7 @@ To manage your website, simply open the Umbraco back office and start adding con Error saving user (check log) User Saved User type saved + User group saved File not saved file could not be saved. Please check file permissions File saved @@ -1413,8 +1414,11 @@ To manage your website, simply open the Umbraco back office and start adding con Start Node in Content Name User permissions + User group permissions User type User types + User group + User groups Writer Translator Change diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index 63fc12101f..6855e963a0 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -1003,6 +1003,7 @@ To manage your website, simply open the Umbraco back office and start adding con Error saving user (check log) User Saved User type saved + User group saved File not saved file could not be saved. Please check file permissions File saved @@ -1410,8 +1411,11 @@ To manage your website, simply open the Umbraco back office and start adding con Start Node in Content Name User permissions + User group permissions User type User types + User group + User groups Writer Translator Change diff --git a/src/Umbraco.Web.UI/umbraco/users/EditUserGroup.aspx b/src/Umbraco.Web.UI/umbraco/users/EditUserGroup.aspx new file mode 100644 index 0000000000..6626f33eb1 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/users/EditUserGroup.aspx @@ -0,0 +1,52 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="EditUserGroup.aspx.cs" MasterPageFile="../masterpages/umbracoPage.Master" + Inherits="umbraco.cms.presentation.user.EditUserGroup" %> + +<%@ Register TagPrefix="cc2" Namespace="umbraco.uicontrols" Assembly="controls" %> + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Users not in group:
+ +
+
+ + +
+
+
Users in group:
+ +
+
+
+
+
+
+ +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/users/EditUserType.aspx b/src/Umbraco.Web.UI/umbraco/users/EditUserType.aspx deleted file mode 100644 index d8671f0596..0000000000 --- a/src/Umbraco.Web.UI/umbraco/users/EditUserType.aspx +++ /dev/null @@ -1,27 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="EditUserType.aspx.cs" MasterPageFile="../masterpages/umbracoPage.Master" - Inherits="umbraco.cms.presentation.user.EditUserType" %> - -<%@ Register TagPrefix="cc2" Namespace="umbraco.uicontrols" Assembly="controls" %> - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web.UI/umbraco/users/PermissionEditor.aspx b/src/Umbraco.Web.UI/umbraco/users/PermissionEditor.aspx index 75b5d6e66a..f94c72fbdc 100644 --- a/src/Umbraco.Web.UI/umbraco/users/PermissionEditor.aspx +++ b/src/Umbraco.Web.UI/umbraco/users/PermissionEditor.aspx @@ -27,7 +27,8 @@ + \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroup.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroup.aspx.cs new file mode 100644 index 0000000000..9b929bd931 --- /dev/null +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroup.aspx.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Web.UI.WebControls; +using umbraco.BasePages; +using umbraco.BusinessLogic; +using umbraco.cms.presentation.Trees; +using umbraco.interfaces; +using Umbraco.Core; + +namespace umbraco.cms.presentation.user +{ + public partial class EditUserGroup : EditUserGroupsBase + { + public EditUserGroup() + { + CurrentApp = BusinessLogic.DefaultApps.users.ToString(); + } + + protected void Page_Load(object sender, EventArgs e) + { + pnlUmbraco.Text = umbraco.ui.Text("usergroup", base.getUser()); + + var save = pnlUmbraco.Menu.NewButton(); + save.Click += save_Click; + save.ID = "save"; + save.ToolTip = ui.Text("save"); + save.Text = ui.Text("save"); + + pp_alias.Text = umbraco.ui.Text("alias", base.getUser()); + pp_name.Text = umbraco.ui.Text("name", base.getUser()); + + pp_rights.Text = umbraco.ui.Text("default", base.getUser()) + " " + umbraco.ui.Text("rights", base.getUser()); + pp_sections.Text = umbraco.ui.Text("sections", base.getUser()); + + pp_users.Text = umbraco.ui.Text("users", base.getUser()); + + //ensure we have a query string + if (string.IsNullOrEmpty(Request.QueryString["id"])) + return; + //ensure it is an integer + if (!int.TryParse(Request.QueryString["id"], out m_userGroupID)) + return; + + if (!IsPostBack) + { + BindDetails(); + BindActions(); + BindSections(); + BindUsers(); + ClientTools + .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) + .SyncTree(m_userGroupID.ToString(), false); + } + } + + void save_Click(object sender, EventArgs e) + { + var userGroup = CurrentUserGroup; + userGroup.Name = txtUserGroupName.Text; + string actions = ""; + + foreach (ListItem li in cbl_rights.Items) + { + if (li.Selected) + actions += li.Value; + } + + userGroup.DefaultPermissions = actions; + + var userIds = new List(); + foreach (ListItem li in lstUsersInGroup.Items) + { + userIds.Add(int.Parse(li.Value)); + } + + userGroup.ClearApplications(); + foreach (ListItem li in cbl_sections.Items) + { + if (li.Selected) userGroup.AddApplication(li.Value); + } + + userGroup.SaveWithUsers(userIds.ToArray()); + + ClientTools.ShowSpeechBubble(speechBubbleIcon.save, ui.Text("speechBubbles", "editUserGroupSaved", base.getUser()), ""); + } + + protected List CurrentUserGroupActions + { + get + { + if (m_userGroupActions == null) + m_userGroupActions = umbraco.BusinessLogic.Actions.Action.FromString(CurrentUserGroup.DefaultPermissions); + return m_userGroupActions; + } + } + + protected UserGroup CurrentUserGroup + { + get + { + if (m_userGroup == null) + m_userGroup = UserGroup.GetUserGroup(m_userGroupID); + return m_userGroup; + } + } + + private UserGroup m_userGroup; + private List m_userGroupActions; + private int m_userGroupID; + + private void BindDetails() + { + lblUserGroupAlias.Text = CurrentUserGroup.Alias; + txtUserGroupName.Text = CurrentUserGroup.Name; + hidUserGroupID.Value = CurrentUserGroup.Id.ToString(); + } + + private void BindActions() + { + foreach (IAction ai in global::umbraco.BusinessLogic.Actions.Action.GetPermissionAssignable()) + { + + ListItem li = new ListItem(umbraco.ui.Text(ai.Alias, base.getUser()), ai.Letter.ToString()); + + if (CurrentUserGroupActions.Contains(ai)) + li.Selected = true; + + cbl_rights.Items.Add(li); + } + } + + private void BindSections() + { + string currentUserApps = ";"; + foreach (Application a in CurrentUser.Applications) + currentUserApps += a.alias + ";"; + + Application[] gapps = CurrentUserGroup.Applications; + foreach (Application app in BusinessLogic.Application.getAll()) + { + if (CurrentUser.IsAdmin() || currentUserApps.Contains(";" + app.alias + ";")) + { + ListItem li = new ListItem(ui.Text("sections", app.alias), app.alias); + foreach (Application tmp in gapps) if (app.alias == tmp.alias) li.Selected = true; + cbl_sections.Items.Add(li); + } + } + } + + private void BindUsers() + { + var userService = ApplicationContext.Current.Services.UserService; + + lstUsersInGroup.DataSource = userService.GetAllInGroup(CurrentUserGroup.Id); + lstUsersInGroup.DataValueField = "Id"; + lstUsersInGroup.DataTextField = "Name"; + lstUsersInGroup.DataBind(); + + lstUsersNotInGroup.DataSource = userService.GetAllNotInGroup(CurrentUserGroup.Id); + lstUsersNotInGroup.DataValueField = "Id"; + lstUsersNotInGroup.DataTextField = "Name"; + lstUsersNotInGroup.DataBind(); + } + + protected void btnAddToGroup_Click(object sender, EventArgs e) + { + MoveItems(lstUsersNotInGroup, lstUsersInGroup); + } + + protected void btnRemoveFromGroup_Click(object sender, EventArgs e) + { + MoveItems(lstUsersInGroup, lstUsersNotInGroup); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroup.aspx.designer.cs similarity index 50% rename from src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx.designer.cs rename to src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroup.aspx.designer.cs index ac1fddb9ec..2de0f19ef0 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx.designer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroup.aspx.designer.cs @@ -1,105 +1,195 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace umbraco.cms.presentation.user { - - - public partial class EditUserType { - - /// - /// pnlUmbraco control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.UmbracoPanel pnlUmbraco; - - /// - /// pnl1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane pnl1; - - /// - /// hidUserTypeID control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.HiddenField hidUserTypeID; - - /// - /// pp_name control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_name; - - /// - /// txtUserTypeName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox txtUserTypeName; - - /// - /// pp_alias control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_alias; - - /// - /// lblUserTypeAlias control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Label lblUserTypeAlias; - - /// - /// pnl2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane pnl2; - - /// - /// pp_rights control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_rights; - - /// - /// cbl_rights control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList cbl_rights; - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace umbraco.cms.presentation.user { + + + public partial class EditUserGroup { + + /// + /// pnlUmbraco control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.UmbracoPanel pnlUmbraco; + + /// + /// pnl1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane pnl1; + + /// + /// hidUserGroupID control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.HiddenField hidUserGroupID; + + /// + /// pp_name control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_name; + + /// + /// txtUserGroupName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox txtUserGroupName; + + /// + /// pp_alias control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_alias; + + /// + /// lblUserGroupAlias control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label lblUserGroupAlias; + + /// + /// pnl2 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane pnl2; + + /// + /// pp_rights control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_rights; + + /// + /// cbl_rights control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBoxList cbl_rights; + + /// + /// pnl3 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane pnl3; + + /// + /// pp_sections control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_sections; + + /// + /// cbl_sections control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBoxList cbl_sections; + + /// + /// pnl4 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane pnl4; + + /// + /// pp_users control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_users; + + /// + /// pnlUsers control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.UpdatePanel pnlUsers; + + /// + /// lstUsersNotInGroup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ListBox lstUsersNotInGroup; + + /// + /// btnAddToGroup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnAddToGroup; + + /// + /// btnRemoveFromGroup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnRemoveFromGroup; + + /// + /// lstUsersInGroup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ListBox lstUsersInGroup; + } +} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroupsBase.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroupsBase.cs new file mode 100644 index 0000000000..d5710423cf --- /dev/null +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserGroupsBase.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web.UI.WebControls; +using umbraco.BasePages; + +namespace umbraco.cms.presentation.user +{ + /// + /// Base class provided common functionality to the web forms that allow for assignment of users to groups + /// + public abstract class EditUserGroupsBase : UmbracoEnsuredPage + { + protected void MoveItems(ListBox from, ListBox to) + { + for (var i = from.Items.Count - 1; i >= 0; i--) + { + if (from.Items[i].Selected) + { + to.Items.Add(from.Items[i]); + var li = from.Items[i]; + from.Items.Remove(li); + } + } + + from.SelectedIndex = -1; + to.SelectedIndex = -1; + SortItems(to); + } + + protected void SortItems(ListBox listBox) + { + // Hat-tip: http://stackoverflow.com/a/3396527 + var list = new List(listBox.Items.Cast()); + list = list.OrderBy(li => li.Text).ToList(); + listBox.Items.Clear(); + listBox.Items.AddRange(list.ToArray()); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx deleted file mode 100644 index d8671f0596..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx +++ /dev/null @@ -1,27 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="EditUserType.aspx.cs" MasterPageFile="../masterpages/umbracoPage.Master" - Inherits="umbraco.cms.presentation.user.EditUserType" %> - -<%@ Register TagPrefix="cc2" Namespace="umbraco.uicontrols" Assembly="controls" %> - - - - - - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx.cs deleted file mode 100644 index b6796e45fa..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUserType.aspx.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Data; -using System.Configuration; -using System.Collections; -using System.Web; -using System.Web.Security; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Web.UI.WebControls.WebParts; -using System.Web.UI.HtmlControls; -using umbraco.BasePages; -using System.Collections.Generic; -using umbraco.interfaces; -using umbraco.BusinessLogic.Actions; -using umbraco.BusinessLogic; -using umbraco.uicontrols; -using umbraco.cms.presentation.Trees; -using Umbraco.Core.IO; - -namespace umbraco.cms.presentation.user -{ - public partial class EditUserType : UmbracoEnsuredPage - { - public EditUserType() - { - CurrentApp = BusinessLogic.DefaultApps.users.ToString(); - } - protected void Page_Load(object sender, EventArgs e) - { - pnlUmbraco.Text = umbraco.ui.Text("usertype", base.getUser()); - - var save = pnlUmbraco.Menu.NewButton(); - save.Click += save_Click; - save.ID = "save"; - save.ToolTip = ui.Text("save"); - save.Text = ui.Text("save"); - - pp_alias.Text = umbraco.ui.Text("usertype", base.getUser()) + " " + umbraco.ui.Text("alias", base.getUser()); - pp_name.Text = umbraco.ui.Text("usertype", base.getUser()) + " " + umbraco.ui.Text("name", base.getUser()); - - pp_rights.Text = umbraco.ui.Text("default", base.getUser()) + " " + umbraco.ui.Text("rights", base.getUser()); - - //ensure we have a query string - if (string.IsNullOrEmpty(Request.QueryString["id"])) - return; - //ensuer it is an integer - if (!int.TryParse(Request.QueryString["id"], out m_userTypeID)) - return; - - if (!IsPostBack) - { - BindActions(); - - ClientTools - .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) - .SyncTree(m_userTypeID.ToString(), false); - } - - } - - void save_Click(object sender, EventArgs e) - { - UserType userType = CurrentUserType; - userType.Name = txtUserTypeName.Text; - string actions = ""; - - foreach (ListItem li in cbl_rights.Items) { - if (li.Selected) - actions += li.Value; - } - - userType.DefaultPermissions = actions; - userType.Save(); - - ClientTools.ShowSpeechBubble(speechBubbleIcon.save, ui.Text("speechBubbles", "editUserTypeSaved", base.getUser()), ""); - } - - protected List CurrentUserTypeActions - { - get - { - if (m_userTypeActions == null) - m_userTypeActions = umbraco.BusinessLogic.Actions.Action.FromString(CurrentUserType.DefaultPermissions); - return m_userTypeActions; - } - } - - protected UserType CurrentUserType - { - get - { - if (m_userType == null) - m_userType = UserType.GetUserType(m_userTypeID); - return m_userType; - } - } - private UserType m_userType; - private List m_userTypeActions; - private int m_userTypeID; - - private void BindActions() - { - lblUserTypeAlias.Text = CurrentUserType.Alias; - txtUserTypeName.Text = CurrentUserType.Name; - hidUserTypeID.Value = CurrentUserType.Id.ToString(); - - foreach (IAction ai in global::umbraco.BusinessLogic.Actions.Action.GetPermissionAssignable()) { - - ListItem li = new ListItem(umbraco.ui.Text(ai.Alias, base.getUser()), ai.Letter.ToString()); - - if(CurrentUserTypeActions.Contains(ai)) - li.Selected = true; - - cbl_rights.Items.Add(li); - } - } - - - - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/NodePermissions.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/users/NodePermissions.ascx.cs index 26a601a9ac..ddd465c699 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/NodePermissions.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/NodePermissions.ascx.cs @@ -1,55 +1,44 @@ using System; -using System.Data; -using System.Configuration; -using System.Collections; -using System.Web; -using System.Web.Security; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Web.UI.WebControls.WebParts; -using System.Web.UI.HtmlControls; -using umbraco.BusinessLogic.Actions; +using System.Linq; +using Umbraco.Core.Models.Membership; using System.Collections.Generic; +using umbraco.BusinessLogic.Actions; using umbraco.interfaces; -using System.Drawing; -using umbraco.BusinessLogic; -using umbraco.BasePages; +using Umbraco.Core; namespace umbraco.cms.presentation.user { + using Umbraco.Web; /// - /// An object to display the current permissions for a user and a node. + /// An object to display the current permissions for a user group and a node. /// public partial class NodePermissions : System.Web.UI.UserControl { - - protected override void OnInit(EventArgs e) { - base.OnInit(e); - } + private IUserGroup m_umbracoUserGroup; + private UserGroupPermissions m_userGroupPermissions; + private int[] m_nodeID = { -1 }; + private string m_clientItemChecked = "void(0);"; + private bool m_viewOnly = false; protected void Page_Load(object sender, EventArgs e) { DataBind(); } - private User m_umbracoUser; - private int[] m_nodeID = {-1}; - private UserPermissions m_userPermissions; - private string m_clientItemChecked = "void(0);"; - - public int UserID + public int UserGroupID { - get { return m_umbracoUser.Id; } + get { return m_umbracoUserGroup.Id; } set { - m_umbracoUser = BusinessLogic.User.GetUser(value); - m_userPermissions = new UserPermissions(m_umbracoUser); + var userService = ApplicationContext.Current.Services.UserService; + m_umbracoUserGroup = userService.GetUserGroupById(value); + m_userGroupPermissions = new UserGroupPermissions(m_umbracoUserGroup); } } - private bool m_viewOnly = false; - public bool ViewOnly { + public bool ViewOnly + { get { return m_viewOnly; } set { m_viewOnly = value; } } @@ -72,55 +61,55 @@ namespace umbraco.cms.presentation.user public override void DataBind() { base.DataBind(); - - - if (m_umbracoUser == null) - throw new ArgumentNullException("No User specified"); + + if (m_umbracoUserGroup == null) + throw new ArgumentNullException("No user group specified"); + + //lookup permissions for last node selected + var selectedNodeId = m_nodeID[m_nodeID.Length - 1]; //get the logged in user's permissions - UserPermissions currUserPermissions = new UserPermissions(UmbracoEnsuredPage.CurrentUser); - - //lookup permissions for last node selected - int selectedNodeId = m_nodeID[m_nodeID.Length - 1]; - - List lstCurrUserActions = currUserPermissions.GetExistingNodePermission(selectedNodeId); - List lstLookupUserActions = m_userPermissions.GetExistingNodePermission(selectedNodeId); - - List lstAllActions = umbraco.BusinessLogic.Actions.Action.GetPermissionAssignable(); + var userService = ApplicationContext.Current.Services.UserService; + var currUserPermissions = userService.GetPermissions(UmbracoContext.Current.Security.CurrentUser, selectedNodeId).Single(); + + var lstCurrUserActions = BusinessLogic.Actions.Action.FromString(string.Join(string.Empty, currUserPermissions.AssignedPermissions)); + var lstLookupGroupActions = m_userGroupPermissions.GetExistingNodePermission(selectedNodeId); + + var lstAllActions = BusinessLogic.Actions.Action.GetPermissionAssignable(); //no node is selected, disable the check boxes - if (m_nodeID[0] == -1) + if (NodeID[0] == -1) { ShowMessage("No node selected"); return; } //ensure the current user has access to assign permissions. - //if their actions list is null then it means that the node is not published. - if (lstCurrUserActions == null || lstCurrUserActions.Contains(ActionRights.Instance)) - BindExistingPermissions(lstAllActions, lstLookupUserActions); + if (lstCurrUserActions.Contains(ActionRights.Instance)) + BindExistingPermissions(lstAllActions, lstLookupGroupActions); else ShowMessage("You do not have access to assign permissions to this node"); - string names = ""; - foreach (int id in m_nodeID) { - if(id > 0) + var names = string.Empty; + foreach (int id in NodeID) + { + if (id > 0) + { names += new cms.businesslogic.web.Document(id).Text + ", "; + } } - lt_names.Text = names.Trim().Trim(','); + lt_names.Text = names.Trim().Trim(','); } - private void ShowMessage(string msg) + protected void ShowMessage(string msg) { lblMessage.Visible = true; lblMessage.Text = msg; - } - private void BindExistingPermissions(List allActions, List userActions) + protected void BindExistingPermissions(List allActions, List userActions) { - List assignedPermissions = new List(); foreach (umbraco.interfaces.IAction a in allActions) { @@ -129,17 +118,15 @@ namespace umbraco.cms.presentation.user p.HasPermission = (userActions != null ? userActions.Contains(a) : false); assignedPermissions.Add(p); } - + rptPermissionsList.DataSource = assignedPermissions; rptPermissionsList.DataBind(); - - } + } protected struct AssignedPermission { public IAction Permission; public bool HasPermission; } - } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/users/PermissionEditor.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/users/PermissionEditor.aspx index 815a420f88..fc9270e370 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/users/PermissionEditor.aspx +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/users/PermissionEditor.aspx @@ -27,7 +27,7 @@