From 85c85cd1ebf5cf45631a7769c5bbd17614618891 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 6 Jan 2014 11:04:26 +1100 Subject: [PATCH] Simplifies and streamlines the models used between IMember and IUser along with the services used for both of these entities. Updates the model used to store and retreive permissions, instead of a single string it is an Enumerable which gives us some flexibility in the future and since this was not public (yet) it's the perfect time to do this. Removes the base Profile classes from User since these are not required, since we cannot share base classes between Member and User, these weren't necessary. --- src/Umbraco.Core/Models/IMember.cs | 100 +--- src/Umbraco.Core/Models/Member.cs | 2 +- .../Models/Membership/IMembershipUser.cs | 22 +- .../Models/Membership/IMembershipUserId.cs | 7 - src/Umbraco.Core/Models/Membership/IUser.cs | 21 +- .../Models/Membership/IUserType.cs | 17 +- src/Umbraco.Core/Models/Membership/Profile.cs | 123 ----- src/Umbraco.Core/Models/Membership/User.cs | 472 ++++++++++++++++-- .../Models/Membership/UserProfile.cs | 188 ------- .../Models/Membership/UserType.cs | 9 +- .../Persistence/Factories/UserFactory.cs | 43 +- .../Persistence/Factories/UserTypeFactory.cs | 20 +- .../Persistence/Mappers/UserMapper.cs | 2 +- .../Repositories/ContentRepository.cs | 4 +- .../Repositories/PermissionRepository.cs | 50 +- .../Services/IMembershipMemberService.cs | 36 +- .../Services/IMembershipUserService.cs | 6 +- src/Umbraco.Core/Services/IUserService.cs | 5 +- src/Umbraco.Core/Services/MemberService.cs | 26 +- src/Umbraco.Core/Services/UserService.cs | 198 ++++++-- src/Umbraco.Core/Umbraco.Core.csproj | 3 - .../Persistence/Querying/PetaPocoSqlTests.cs | 4 +- .../Repositories/ContentRepositoryTest.cs | 2 +- .../Repositories/UserRepositoryTest.cs | 14 +- .../Repositories/UserTypeRepositoryTest.cs | 2 +- .../Services/UserServiceTests.cs | 20 +- .../TestHelpers/Entities/MockedUser.cs | 4 +- .../TestHelpers/Entities/MockedUserType.cs | 2 +- 28 files changed, 780 insertions(+), 622 deletions(-) delete mode 100644 src/Umbraco.Core/Models/Membership/IMembershipUserId.cs delete mode 100644 src/Umbraco.Core/Models/Membership/Profile.cs delete mode 100644 src/Umbraco.Core/Models/Membership/UserProfile.cs diff --git a/src/Umbraco.Core/Models/IMember.cs b/src/Umbraco.Core/Models/IMember.cs index 0b347a2515..27c32bbb63 100644 --- a/src/Umbraco.Core/Models/IMember.cs +++ b/src/Umbraco.Core/Models/IMember.cs @@ -1,106 +1,10 @@ using System; +using Umbraco.Core.Models.Membership; namespace Umbraco.Core.Models { - public interface IMember : IContentBase + public interface IMember : IContentBase, IMembershipUser { - /// - /// Gets or sets the Username - /// - string Username { get; set; } - - /// - /// Gets or sets the Email - /// - string Email { get; set; } - - /// - /// Gets or sets the Password - /// - string Password { get; set; } - - /// - /// Gets or sets the Password Question - /// - /// - /// Alias: umbracoPasswordRetrievalQuestionPropertyTypeAlias - /// Part of the standard properties collection. - /// - string PasswordQuestion { get; set; } - - /// - /// Gets or sets the Password Answer - /// - /// - /// Alias: umbracoPasswordRetrievalAnswerPropertyTypeAlias - /// Part of the standard properties collection. - /// - string PasswordAnswer { get; set; } - - /// - /// Gets or set the comments for the member - /// - /// - /// Alias: umbracoCommentPropertyTypeAlias - /// Part of the standard properties collection. - /// - string Comments { get; set; } - - /// - /// Gets or sets a boolean indicating whether the Member is approved - /// - /// - /// Alias: umbracoApprovePropertyTypeAlias - /// Part of the standard properties collection. - /// - bool IsApproved { get; set; } - - /// - /// Gets or sets a boolean indicating whether the Member is locked out - /// - /// - /// Alias: umbracoLockPropertyTypeAlias - /// Part of the standard properties collection. - /// - bool IsLockedOut { get; set; } - - /// - /// Gets or sets the date for last login - /// - /// - /// Alias: umbracoLastLoginPropertyTypeAlias - /// Part of the standard properties collection. - /// - DateTime LastLoginDate { get; set; } - - /// - /// Gest or sets the date for last password change - /// - /// - /// Alias: umbracoMemberLastPasswordChange - /// Part of the standard properties collection. - /// - DateTime LastPasswordChangeDate { get; set; } - - /// - /// Gets or sets the date for when Member was locked out - /// - /// - /// Alias: umbracoMemberLastLockout - /// Part of the standard properties collection. - /// - DateTime LastLockoutDate { get; set; } - - /// - /// Gets or sets the number of failed password attempts. - /// This is the number of times the password was entered incorrectly upon login. - /// - /// - /// Alias: umbracoFailedPasswordAttemptsPropertyTypeAlias - /// Part of the standard properties collection. - /// - int FailedPasswordAttempts { get; set; } - /// /// String alias of the default ContentType /// diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index 78be963eac..dee87d5616 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -378,7 +378,7 @@ namespace Umbraco.Core.Models /// membership provider. /// [DataMember] - internal virtual object ProviderUserKey + public virtual object ProviderUserKey { get { diff --git a/src/Umbraco.Core/Models/Membership/IMembershipUser.cs b/src/Umbraco.Core/Models/Membership/IMembershipUser.cs index 422b47da22..b88730f4cd 100644 --- a/src/Umbraco.Core/Models/Membership/IMembershipUser.cs +++ b/src/Umbraco.Core/Models/Membership/IMembershipUser.cs @@ -4,9 +4,9 @@ using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Models.Membership { - internal interface IMembershipUser : IMembershipUserId, IAggregateRoot - { - /*new object Id { get; set; }*/ + public interface IMembershipUser : IAggregateRoot + { + object ProviderUserKey { get; set; } string Username { get; set; } string Email { get; set; } string Password { get; set; } @@ -14,13 +14,23 @@ namespace Umbraco.Core.Models.Membership string PasswordAnswer { get; set; } string Comments { get; set; } bool IsApproved { get; set; } - bool IsOnline { get; set; } + //bool IsOnline { get; set; } bool IsLockedOut { get; set; } DateTime LastLoginDate { get; set; } DateTime LastPasswordChangeDate { get; set; } DateTime LastLockoutDate { get; set; } - object ProfileId { get; set; } - IEnumerable Groups { get; set; } + /// + /// Gets or sets the number of failed password attempts. + /// This is the number of times the password was entered incorrectly upon login. + /// + /// + /// Alias: umbracoFailedPasswordAttemptsPropertyTypeAlias + /// Part of the standard properties collection. + /// + int FailedPasswordAttempts { get; set; } + + //object ProfileId { get; set; } + //IEnumerable Groups { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/IMembershipUserId.cs b/src/Umbraco.Core/Models/Membership/IMembershipUserId.cs deleted file mode 100644 index 03508e1ec8..0000000000 --- a/src/Umbraco.Core/Models/Membership/IMembershipUserId.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Models.Membership -{ - internal interface IMembershipUserId - { - object ProviderUserKey { get; set; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index 97e7e4132f..f45f4ebea6 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -7,23 +7,28 @@ namespace Umbraco.Core.Models.Membership /// Defines the interface for a /// /// Will be left internal until a proper Membership implementation is part of the roadmap - internal interface IUser : IMembershipUser, IUserProfile + internal interface IUser : IMembershipUser, IProfile { new object Id { get; set; } - //string Name { get; set; } + int SessionTimeout { get; set; } int StartContentId { get; set; } int StartMediaId { get; set; } string Language { get; set; } - bool DefaultToLiveEditing { get; set; } + + //NOTE: I have removed this because it is obsolete in v7 and we are basically removing live editing for now + //bool DefaultToLiveEditing { get; set; } - bool NoConsole { get; set; } IUserType UserType { get; } - string DefaultPermissions { get; set; } - } - internal interface IUserProfile : IProfile - { + /// + /// The default permission set for the user + /// + /// + /// 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 AllowedSections { get; } void RemoveAllowedSection(string sectionAlias); void AddAllowedSection(string sectionAlias); diff --git a/src/Umbraco.Core/Models/Membership/IUserType.cs b/src/Umbraco.Core/Models/Membership/IUserType.cs index aa837bf890..aa2d882e4c 100644 --- a/src/Umbraco.Core/Models/Membership/IUserType.cs +++ b/src/Umbraco.Core/Models/Membership/IUserType.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Mappers; @@ -6,8 +7,22 @@ namespace Umbraco.Core.Models.Membership internal interface IUserType : IAggregateRoot { + /// + /// The user type alias + /// string Alias { get; set; } + + /// + /// The user type name + /// string Name { get; set; } - string Permissions { 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; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/Profile.cs b/src/Umbraco.Core/Models/Membership/Profile.cs deleted file mode 100644 index b3959bb9cd..0000000000 --- a/src/Umbraco.Core/Models/Membership/Profile.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.Serialization; -using Umbraco.Core.Models.EntityBase; - -namespace Umbraco.Core.Models.Membership -{ - /// - /// Represents a Profile which is shared between Members and Users - /// - [Serializable] - [DataContract(IsReference = true)] - internal class Profile : TracksChangesEntityBase, IProfile, IRememberBeingDirty - { - /// - /// Initializes a new instance of the class. - /// - protected Profile() - { - ProviderUserKeyType = typeof(int); - } - - public Profile(object id, string name) - { - ProviderUserKeyType = typeof(int); - Id = id; - Name = name; - } - - private object _id; - private string _name; - private object _providerUserKey; - private Type _userTypeKey; - - private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo(x => x.Id); - private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - private static readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ProviderUserKey); - private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ProviderUserKeyType); - - [DataMember] - public virtual object Id - { - get - { - return _id; - } - set - { - SetPropertyValueAndDetectChanges(o => - { - _id = value; - return _id; - }, _id, IdSelector); - } - } - - [DataMember] - public virtual string Name - { - get - { - return _name; - } - set - { - SetPropertyValueAndDetectChanges(o => - { - _name = value; - return _name; - }, _name, NameSelector); - } - } - - [IgnoreDataMember] - public virtual object ProviderUserKey - { - get - { - return _providerUserKey; - } - set - { - SetPropertyValueAndDetectChanges(o => - { - _providerUserKey = value; - return _id; - }, _providerUserKey, ProviderUserKeySelector); - } - } - - /// - /// Gets or sets the type of the provider user key. - /// - /// - /// The type of the provider user key. - /// - [IgnoreDataMember] - internal Type ProviderUserKeyType - { - get - { - return _userTypeKey; - } - private set - { - SetPropertyValueAndDetectChanges(o => - { - _userTypeKey = value; - return _userTypeKey; - }, _userTypeKey, UserTypeKeySelector); - } - } - - /// - /// Sets the type of the provider user key. - /// - /// The type. - internal void SetProviderUserKeyType(Type type) - { - ProviderUserKeyType = type; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index ddcc28cccb..9d06c5f8ea 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Linq; +using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Mappers; @@ -16,15 +19,59 @@ namespace Umbraco.Core.Models.Membership /// [Serializable] [DataContract(IsReference = true)] - internal class User : UserProfile, IUser + internal class User : TracksChangesEntityBase, IUser { - private bool _hasIdentity; - public User(IUserType userType) { - Groups = new List { userType }; + _userType = userType; + //Groups = new List { userType }; + SessionTimeout = 60; + _sectionCollection = new ObservableCollection(); + _addedSections = new List(); + _removedSections = new List(); + _sectionCollection.CollectionChanged += SectionCollectionChanged; } + private readonly IUserType _userType; + private bool _hasIdentity; + private object _id; + private string _name; + private Type _userTypeKey; + private readonly List _addedSections; + private readonly List _removedSections; + private readonly ObservableCollection _sectionCollection; + private int _sessionTimeout; + private int _startContentId; + private int _startMediaId; + + private string _username; + private string _email; + private string _password; + private object _providerUserKey; + private bool _isApproved; + private bool _isLockedOut; + private string _language; + private IEnumerable _defaultPermissions; + private bool _defaultToLiveEditing; + + private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo(x => x.SessionTimeout); + private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentId); + private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaId); + private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedSections); + private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo(x => x.Id); + private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); + private static readonly PropertyInfo ProviderUserKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ProviderUserKey); + private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ProviderUserKeyType); + + private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo(x => x.Username); + private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo(x => x.Email); + private static readonly PropertyInfo PasswordSelector = ExpressionHelper.GetPropertyInfo(x => x.Password); + private static readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo(x => x.IsLockedOut); + private static readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo(x => x.IsApproved); + private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language); + private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.DefaultPermissions); + private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultToLiveEditing); + #region Implementation of IEntity [IgnoreDataMember] @@ -35,11 +82,11 @@ namespace Umbraco.Core.Models.Membership { get { - return int.Parse(base.Id.ToString()); + return int.Parse(Id.ToString()); } set { - base.Id = value; + Id = value; _hasIdentity = true; } } @@ -50,64 +97,399 @@ namespace Umbraco.Core.Models.Membership #region Implementation of IMembershipUser - [DataMember] - public string Username { get; set; } - [DataMember] - public string Email { get; set; } - [DataMember] - public string Password { get; set; } - [DataMember] - public string PasswordQuestion { get; set; } - [DataMember] - public string PasswordAnswer { get; set; } - [DataMember] - public string Comments { get; set; } - [DataMember] - public bool IsApproved { get; set; } - [DataMember] - public bool IsOnline { get; set; } - [DataMember] - public bool IsLockedOut { get; set; } - [DataMember] - public DateTime CreateDate { get; set; } - [DataMember] - public DateTime UpdateDate { get; set; } - [DataMember] - public DateTime LastLoginDate { get; set; } - [DataMember] - public DateTime LastPasswordChangeDate { get; set; } - [DataMember] - public DateTime LastLockoutDate { get; set; } + [IgnoreDataMember] + public object ProviderUserKey + { + get + { + return _providerUserKey; + } + set + { + SetPropertyValueAndDetectChanges(o => + { + _providerUserKey = value; + return _id; + }, _providerUserKey, ProviderUserKeySelector); + } + } + + /// + /// Gets or sets the type of the provider user key. + /// + /// + /// The type of the provider user key. + /// + [IgnoreDataMember] + internal Type ProviderUserKeyType + { + get + { + return _userTypeKey; + } + private set + { + SetPropertyValueAndDetectChanges(o => + { + _userTypeKey = value; + return _userTypeKey; + }, _userTypeKey, UserTypeKeySelector); + } + } + + /// + /// Sets the type of the provider user key. + /// + /// The type. + internal void SetProviderUserKeyType(Type type) + { + ProviderUserKeyType = type; + } [DataMember] - public object ProfileId { get; set; } + public string Username + { + get { return _username; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _username = value; + return _username; + }, _username, UsernameSelector); + } + } [DataMember] - public IEnumerable Groups { get; set; } + public string Email + { + get { return _email; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _email = value; + return _email; + }, _email, EmailSelector); + } + } + [DataMember] + public string Password + { + get { return _password; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _password = value; + return _password; + }, _password, PasswordSelector); + } + } + + [DataMember] + public string PasswordQuestion + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public string PasswordAnswer + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public string Comments + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + [DataMember] + public bool IsApproved + { + get { return _isApproved; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _isApproved = value; + return _isApproved; + }, _isApproved, IsApprovedSelector); + } + } + + [DataMember] + public bool IsLockedOut + { + get { return _isLockedOut; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _isLockedOut = value; + return _isLockedOut; + }, _isLockedOut, IsLockedOutSelector); + } + } + + [DataMember] + public DateTime CreateDate + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public DateTime UpdateDate + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public DateTime LastLoginDate + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public DateTime LastPasswordChangeDate + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public DateTime LastLockoutDate + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + [DataMember] + public int FailedPasswordAttempts + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + #endregion + + #region Implementation of IProfile + + [DataMember] + public string Name + { + get { return _name; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _name = value; + return _name; + }, _name, NameSelector); + } + } #endregion #region Implementation of IUser + public IEnumerable AllowedSections + { + get { return _sectionCollection; } + } + + public void RemoveAllowedSection(string sectionAlias) + { + _sectionCollection.Remove(sectionAlias); + } + + public void AddAllowedSection(string sectionAlias) + { + if (_sectionCollection.Contains(sectionAlias) == false) + { + _sectionCollection.Add(sectionAlias); + } + } + + /// + /// 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. + /// + /// + /// The session timeout. + /// [DataMember] - public string Language { get; set; } + public int SessionTimeout + { + get { return _sessionTimeout; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _sessionTimeout = value; + return _sessionTimeout; + }, _sessionTimeout, SessionTimeoutSelector); + } + } + + /// + /// Gets or sets the start content id. + /// + /// + /// The start content id. + /// [DataMember] - public string DefaultPermissions { get; set; } + public int StartContentId + { + get { return _startContentId; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _startContentId = value; + return _startContentId; + }, _startContentId, StartContentIdSelector); + } + } + + /// + /// Gets or sets the start media id. + /// + /// + /// The start media id. + /// + [DataMember] + public int StartMediaId + { + get { return _startMediaId; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _startMediaId = value; + return _startMediaId; + }, _startMediaId, StartMediaIdSelector); + } + } [DataMember] - public bool DefaultToLiveEditing { get; set; } + public object Id + { + get { return _id; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _id = value; + return _id; + }, _id, IdSelector); + } + } + [DataMember] - public bool NoConsole { get; set; } + public string Language + { + get { return _language; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _language = value; + return _language; + }, _language, LanguageSelector); + } + } + + [DataMember] + public IEnumerable DefaultPermissions + { + get { return _defaultPermissions; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _defaultPermissions = value; + return _defaultPermissions; + }, _defaultPermissions, DefaultPermissionsSelector); + } + } + + [IgnoreDataMember] + internal bool DefaultToLiveEditing + { + get { return _defaultToLiveEditing; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _defaultToLiveEditing = value; + return _defaultToLiveEditing; + }, _defaultToLiveEditing, DefaultToLiveEditingSelector); + } + } [IgnoreDataMember] public IUserType UserType { - get - { - var type = Groups.FirstOrDefault(); - return type as IUserType; - } + get { return _userType; } } #endregion + + /// + /// Whenever resetting occurs, clear the remembered add/removed collections, even if + /// rememberPreviouslyChangedProperties is true, the AllowedSections property will still + /// be flagged as dirty. + /// + /// + internal 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(AllowedSectionsSelector); + + if (e.Action == NotifyCollectionChangedAction.Add) + { + //remove from the removed/added sections (since people could add/remove all they want in one request) + _removedSections.RemoveAll(s => s == e.NewItems.Cast().First()); + _addedSections.RemoveAll(s => s == e.NewItems.Cast().First()); + + //add to the added sections + _addedSections.Add(e.NewItems.Cast().First()); + } + else if (e.Action == NotifyCollectionChangedAction.Remove) + { + //remove from the removed/added sections (since people could add/remove all they want in one request) + _removedSections.RemoveAll(s => s == e.OldItems.Cast().First()); + _addedSections.RemoveAll(s => s == e.OldItems.Cast().First()); + + //add to the added sections + _removedSections.Add(e.OldItems.Cast().First()); + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/UserProfile.cs b/src/Umbraco.Core/Models/Membership/UserProfile.cs deleted file mode 100644 index 1e3ab541e7..0000000000 --- a/src/Umbraco.Core/Models/Membership/UserProfile.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; - -namespace Umbraco.Core.Models.Membership -{ - /// - /// Represents the Profile implementation for a backoffice User - /// - /// - /// Should be internal until a proper user/membership implementation - /// is part of the roadmap. - /// - [Serializable] - [DataContract(IsReference = true)] - internal class UserProfile : Profile, IUserProfile - { - public UserProfile() - { - SessionTimeout = 60; - _sectionCollection = new ObservableCollection(); - _addedSections = new List(); - _removedSections = new List(); - _sectionCollection.CollectionChanged += SectionCollectionChanged; - } - - private readonly List _addedSections; - private readonly List _removedSections; - private readonly ObservableCollection _sectionCollection; - private int _sessionTimeout; - private int _startContentId; - private int _startMediaId; - - private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo(x => x.SessionTimeout); - private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentId); - private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaId); - private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedSections); - - /// - /// Gets or sets the session timeout. - /// - /// - /// The session timeout. - /// - [DataMember] - public int SessionTimeout - { - get - { - return _sessionTimeout; - } - set - { - SetPropertyValueAndDetectChanges(o => - { - _sessionTimeout = value; - return _sessionTimeout; - }, _sessionTimeout, SessionTimeoutSelector); - } - } - - /// - /// Gets or sets the start content id. - /// - /// - /// The start content id. - /// - [DataMember] - public int StartContentId - { - get - { - return _startContentId; - } - set - { - SetPropertyValueAndDetectChanges(o => - { - _startContentId = value; - return _startContentId; - }, _startContentId, StartContentIdSelector); - } - } - - /// - /// Gets or sets the start media id. - /// - /// - /// The start media id. - /// - [DataMember] - public int StartMediaId - { - get - { - return _startMediaId; - } - set - { - SetPropertyValueAndDetectChanges(o => - { - _startMediaId = value; - return _startMediaId; - }, _startMediaId, StartMediaIdSelector); - } - } - - public IEnumerable AllowedSections - { - get { return _sectionCollection; } - } - - public void RemoveAllowedSection(string sectionAlias) - { - _sectionCollection.Remove(sectionAlias); - } - - public void AddAllowedSection(string sectionAlias) - { - if (!_sectionCollection.Contains(sectionAlias)) - { - _sectionCollection.Add(sectionAlias); - } - } - - /// - /// Whenever resetting occurs, clear the remembered add/removed collections, even if - /// rememberPreviouslyChangedProperties is true, the AllowedSections property will still - /// be flagged as dirty. - /// - /// - internal override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties) - { - _addedSections.Clear(); - _removedSections.Clear(); - base.ResetDirtyProperties(rememberPreviouslyChangedProperties); - } - - /// - /// 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; } - } - - /// - /// Handles the collection changed event in order for us to flag the AllowedSections property as changed - /// - /// - /// - void SectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - OnPropertyChanged(AllowedSectionsSelector); - - if (e.Action == NotifyCollectionChangedAction.Add) - { - //remove from the removed/added sections (since people could add/remove all they want in one request) - _removedSections.RemoveAll(s => s == e.NewItems.Cast().First()); - _addedSections.RemoveAll(s => s == e.NewItems.Cast().First()); - - //add to the added sections - _addedSections.Add(e.NewItems.Cast().First()); - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - //remove from the removed/added sections (since people could add/remove all they want in one request) - _removedSections.RemoveAll(s => s == e.OldItems.Cast().First()); - _addedSections.RemoveAll(s => s == e.OldItems.Cast().First()); - - //add to the added sections - _removedSections.Add(e.OldItems.Cast().First()); - } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/UserType.cs b/src/Umbraco.Core/Models/Membership/UserType.cs index b09a568c22..b5553c10d2 100644 --- a/src/Umbraco.Core/Models/Membership/UserType.cs +++ b/src/Umbraco.Core/Models/Membership/UserType.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.Serialization; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Mappers; @@ -22,7 +23,13 @@ namespace Umbraco.Core.Models.Membership [DataMember] public 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. + /// [DataMember] - public string Permissions { get; set; } + public IEnumerable Permissions { get; set; } } } \ 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 0a046ca7a0..ddbcb5557a 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Globalization; +using System.Linq; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; @@ -18,22 +20,23 @@ namespace Umbraco.Core.Persistence.Factories public IUser BuildEntity(UserDto dto) { var user = new User(_userType) - { - Id = dto.Id, - ProfileId = dto.Id, - StartContentId = dto.ContentStartId, - StartMediaId = dto.MediaStartId.HasValue ? dto.MediaStartId.Value : -1, - Password = dto.Password, - Username = dto.Login, - Name = dto.UserName, - IsLockedOut = dto.Disabled, - IsApproved = dto.Disabled == false, - Email = dto.Email, - Language = dto.UserLanguage, - DefaultToLiveEditing = dto.DefaultToLiveEditing, - NoConsole = dto.NoConsole, - DefaultPermissions = dto.DefaultPermissions - }; + { + Id = dto.Id, + //ProfileId = dto.Id, + StartContentId = dto.ContentStartId, + StartMediaId = dto.MediaStartId.HasValue ? dto.MediaStartId.Value : -1, + Password = dto.Password, + Username = dto.Login, + Name = dto.UserName, + IsLockedOut = dto.NoConsole, + IsApproved = dto.Disabled == false, + Email = dto.Email, + Language = dto.UserLanguage, + DefaultToLiveEditing = dto.DefaultToLiveEditing, + DefaultPermissions = dto.DefaultPermissions.IsNullOrWhiteSpace() + ? Enumerable.Empty() + : dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)) + }; foreach (var app in dto.User2AppDtos) { @@ -53,16 +56,16 @@ namespace Umbraco.Core.Persistence.Factories { ContentStartId = entity.StartContentId, MediaStartId = entity.StartMediaId, - DefaultToLiveEditing = entity.DefaultToLiveEditing, + DefaultToLiveEditing = ((User)entity).DefaultToLiveEditing, Disabled = entity.IsApproved == false, Email = entity.Email, Login = entity.Username, - NoConsole = entity.NoConsole, + NoConsole = entity.IsLockedOut, Password = entity.Password, UserLanguage = entity.Language, UserName = entity.Name, - Type = short.Parse(entity.UserType.Id.ToString()), - DefaultPermissions = entity.DefaultPermissions, + Type = short.Parse(entity.UserType.Id.ToString(CultureInfo.InvariantCulture)), + DefaultPermissions = entity.DefaultPermissions == null ? "" : string.Join("", entity.DefaultPermissions), User2AppDtos = new List() }; diff --git a/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs index 66e79fd0cf..ad81d2b584 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Models.Membership; +using System.Globalization; +using System.Linq; +using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; namespace Umbraco.Core.Persistence.Factories @@ -10,12 +12,14 @@ namespace Umbraco.Core.Persistence.Factories public IUserType BuildEntity(UserTypeDto dto) { var userType = new UserType - { - Alias = dto.Alias, - Id = dto.Id, - Name = dto.Name, - Permissions = dto.DefaultPermissions - }; + { + Alias = dto.Alias, + Id = dto.Id, + Name = dto.Name, + 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); @@ -27,7 +31,7 @@ namespace Umbraco.Core.Persistence.Factories var userType = new UserTypeDto { Alias = entity.Alias, - DefaultPermissions = entity.Permissions, + DefaultPermissions = entity.Permissions == null ? "" : string.Join("", entity.Permissions), Name = entity.Name }; diff --git a/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs b/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs index 5e2947c3a7..bdb411fc5a 100644 --- a/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/UserMapper.cs @@ -38,7 +38,7 @@ namespace Umbraco.Core.Persistence.Mappers CacheMap(src => src.StartContentId, dto => dto.ContentStartId); CacheMap(src => src.DefaultToLiveEditing, dto => dto.DefaultToLiveEditing); CacheMap(src => src.IsApproved, dto => dto.Disabled); - CacheMap(src => src.NoConsole, dto => dto.NoConsole); + 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/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 6cd96204f2..80352ae0dd 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -269,9 +269,9 @@ namespace Umbraco.Core.Persistence.Repositories if (parentPermissions.Any()) { var userPermissions = parentPermissions.Select( - permissionDto => new KeyValuePair( + permissionDto => new KeyValuePair>( permissionDto.UserId, - permissionDto.Permission)); + permissionDto.Permission.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)))); AssignEntityPermissions(entity, userPermissions); //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. diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs index 0bf6a6eeb8..04dab367dc 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -44,14 +44,16 @@ namespace Umbraco.Core.Persistence.Repositories /// Assigns permissions to an entity for multiple users /// /// - /// + /// + /// A list of permissions to assign - currently in Umbraco each permission is a single char but this list of strings allows for flexibility in the future + /// /// - protected internal void AssignEntityPermissions(TEntity entity, string permissions, IEnumerable userIds) + protected internal void AssignEntityPermissions(TEntity entity, IEnumerable permissions, IEnumerable userIds) { var actions = userIds.Select(id => new User2NodePermissionDto { NodeId = entity.Id, - Permission = permissions, + Permission = string.Join("",permissions), UserId = (int)id }); @@ -63,14 +65,14 @@ namespace Umbraco.Core.Persistence.Repositories /// /// /// - /// A key/value pair list containing a userId and a permission to assign + /// A key/value pair list containing a userId and a permission to assign, currently in Umbraco each permission is a single char but this list of strings allows for flexibility in the future /// - protected internal void AssignEntityPermissions(TEntity entity, IEnumerable> userPermissions) + protected internal void AssignEntityPermissions(TEntity entity, IEnumerable>> userPermissions) { var actions = userPermissions.Select(p => new User2NodePermissionDto { NodeId = entity.Id, - Permission = p.Value, + Permission = string.Join("", p.Value), UserId = (int)p.Key }); @@ -81,9 +83,11 @@ namespace Umbraco.Core.Persistence.Repositories /// Replace permissions for an entity for multiple users /// /// - /// + /// + /// A list of permissions to assign - currently in Umbraco each permission is a single char but this list of strings allows for flexibility in the future + /// /// - protected internal void ReplaceEntityPermissions(TEntity entity, string permissions, IEnumerable userIds) + protected internal void ReplaceEntityPermissions(TEntity entity, IEnumerable permissions, IEnumerable userIds) { Database.Update( GenerateReplaceEntityPermissionsSql(entity.Id, permissions, userIds.ToArray())); @@ -93,12 +97,14 @@ namespace Umbraco.Core.Persistence.Repositories /// An overload to replace entity permissions and all replace all descendant permissions /// /// - /// + /// + /// A list of permissions to assign - currently in Umbraco each permission is a single char but this list of strings allows for flexibility in the future + /// /// /// A callback to get the descendant Ids of the current entity /// /// - protected internal void ReplaceEntityPermissions(TEntity entity, string permissions, Func> getDescendantIds, IEnumerable userIds) + protected internal void ReplaceEntityPermissions(TEntity entity, IEnumerable permissions, Func> getDescendantIds, IEnumerable userIds) { Database.Update( GenerateReplaceEntityPermissionsSql( @@ -107,17 +113,35 @@ namespace Umbraco.Core.Persistence.Repositories userIds.ToArray())); } - internal static string GenerateReplaceEntityPermissionsSql(int entityId, string permissions, object[] userIds) + /// + /// + /// + /// + /// + /// A list of permissions to assign - currently in Umbraco each permission is a single char but this list of strings allows for flexibility in the future + /// + /// + /// + internal static string GenerateReplaceEntityPermissionsSql(int entityId, IEnumerable permissions, object[] userIds) { return GenerateReplaceEntityPermissionsSql(new[] {entityId}, permissions, userIds); } - internal static string GenerateReplaceEntityPermissionsSql(int[] entityIds, string permissions, object[] userIds) + /// + /// + /// + /// + /// + /// A list of permissions to assign - currently in Umbraco each permission is a single char but this list of strings allows for flexibility in the future + /// + /// + /// + internal static string GenerateReplaceEntityPermissionsSql(int[] entityIds, IEnumerable permissions, object[] userIds) { //create the "SET" clause of the update statement var sqlSet = string.Format("SET {0}={1}", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("permission"), - SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(permissions)); + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(string.Join("", permissions))); //build the nodeIds part of the where clause var sqlNodeWhere = BuildOrClause(entityIds, "nodeId"); diff --git a/src/Umbraco.Core/Services/IMembershipMemberService.cs b/src/Umbraco.Core/Services/IMembershipMemberService.cs index 0b9ff79665..522a4dcb86 100644 --- a/src/Umbraco.Core/Services/IMembershipMemberService.cs +++ b/src/Umbraco.Core/Services/IMembershipMemberService.cs @@ -1,16 +1,30 @@ using System.Collections.Generic; using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Querying; namespace Umbraco.Core.Services { + /// /// Defines part of the MemberService, which is specific to methods used by the membership provider. /// /// /// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl. /// - public interface IMembershipMemberService : IService + public interface IMembershipMemberService : IMembershipMemberService + { + IMember CreateMember(string email, string username, string password, IMemberType memberType); + } + + /// + /// Defines part of the UserService/MemberService, which is specific to methods used by the membership provider. + /// + /// + /// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl. + /// + public interface IMembershipMemberService : IService + where T: IEntity { /// /// Checks if a member with the username exists @@ -27,28 +41,28 @@ namespace Umbraco.Core.Services /// /// /// - IMember CreateMember(string username, string email, string password, string memberTypeAlias); + T CreateMember(string username, string email, string password, string memberTypeAlias); - IMember GetById(object id); + T GetById(object id); /// /// Get a member by email /// /// /// - IMember GetByEmail(string email); + T GetByEmail(string email); - IMember GetByUsername(string login); + T GetByUsername(string login); - void Delete(IMember membershipUser); + void Delete(T membershipUser); - void Save(IMember membershipUser, bool raiseEvents = true); + void Save(T membershipUser, bool raiseEvents = true); - void Save(IEnumerable members, bool raiseEvents = true); + void Save(IEnumerable members, bool raiseEvents = true); - IEnumerable FindMembersByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith); + IEnumerable FindMembersByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith); - IEnumerable FindMembersByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith); + IEnumerable FindMembersByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith); /// /// Gets the total number of members based on the count type @@ -63,6 +77,6 @@ namespace Umbraco.Core.Services /// /// /// - IEnumerable GetAllMembers(int pageIndex, int pageSize, out int totalRecords); + IEnumerable GetAllMembers(int pageIndex, int pageSize, out int totalRecords); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IMembershipUserService.cs b/src/Umbraco.Core/Services/IMembershipUserService.cs index 5ae7f9af32..c79607edab 100644 --- a/src/Umbraco.Core/Services/IMembershipUserService.cs +++ b/src/Umbraco.Core/Services/IMembershipUserService.cs @@ -8,8 +8,10 @@ namespace Umbraco.Core.Services /// /// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl. /// - internal interface IMembershipUserService : IService + internal interface IMembershipUserService : IMembershipMemberService { - IMembershipUser CreateMembershipUser(string name, string login, string password, IUserType userType, string email = ""); + + IUser CreateMember(string username, string email, string password, IUserType userType); + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs index 8549699c53..637011d345 100644 --- a/src/Umbraco.Core/Services/IUserService.cs +++ b/src/Umbraco.Core/Services/IUserService.cs @@ -14,9 +14,10 @@ namespace Umbraco.Core.Services /// Id of the User to retrieve /// IProfile GetProfileById(int id); - IProfile GetProfileByUserName(string username); - IUser GetUserByUserName(string username); + + //IUser GetUserByUserName(string username); + IUser GetUserById(int id); /// diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index d180d13e82..6995bf79e3 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -511,6 +511,22 @@ namespace Umbraco.Core.Services throw new NotImplementedException(); } + public IMember CreateMember(string email, string username, string password, IMemberType memberType) + { + if (memberType == null) throw new ArgumentNullException("memberType"); + + var member = new Member(email, email, username, password, -1, memberType); + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberRepository(uow)) + { + repository.AddOrUpdate(member); + uow.Commit(); + } + + return member; + } + /// /// Creates and persists a new Member /// @@ -531,17 +547,11 @@ namespace Umbraco.Core.Services } if (memberType == null) - throw new Exception(string.Format("No MemberType matching the passed in Alias: '{0}' was found", memberTypeAlias)); - - var member = new Member(email, email, username, password, -1, memberType); - - using (var repository = _repositoryFactory.CreateMemberRepository(uow)) { - repository.AddOrUpdate(member); - uow.Commit(); + throw new ArgumentException(string.Format("No MemberType matching the passed in Alias: '{0}' was found", memberTypeAlias)); } - return member; + return CreateMember(email, username, password, memberTypeAlias); } /// diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index 5845c0faa0..0ff24715b5 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using Umbraco.Core.Events; @@ -33,6 +34,113 @@ namespace Umbraco.Core.Services _uowProvider = provider; } + #region Implementation of IMembershipUserService + + public bool Exists(string username) + { + throw new NotImplementedException(); + } + + public IUser CreateMember(string username, string email, string password, IUserType userType) + { + if (userType == null) throw new ArgumentNullException("userType"); + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateUserRepository(uow)) + { + var loginExists = uow.Database.ExecuteScalar("SELECT COUNT(id) FROM umbracoUser WHERE userLogin = @Login", new { Login = username }) != 0; + if (loginExists) + throw new ArgumentException("Login already exists"); + + var user = new User(userType) + { + DefaultToLiveEditing = false, + Email = email, + Language = Configuration.GlobalSettings.DefaultUILanguage, + Name = username, + Password = password, + DefaultPermissions = userType.Permissions, + Username = username, + StartContentId = -1, + StartMediaId = -1, + IsLockedOut = false, + IsApproved = true + }; + + repository.AddOrUpdate(user); + uow.Commit(); + + return user; + } + } + + public IUser CreateMember(string username, string email, string password, string memberTypeAlias) + { + var userType = GetUserTypeByAlias(memberTypeAlias); + if (userType == null) + { + throw new ArgumentException("The user type " + memberTypeAlias + " could not be resolved"); + } + + return CreateMember(username, email, password, userType); + } + + public IUser GetById(object id) + { + throw new NotImplementedException(); + } + + public IUser GetByEmail(string email) + { + throw new NotImplementedException(); + } + + public IUser GetByUsername(string login) + { + using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Username == login); + return repository.GetByQuery(query).FirstOrDefault(); + } + } + + public void Delete(IUser membershipUser) + { + throw new NotImplementedException(); + } + + public void Save(IUser membershipUser, bool raiseEvents = true) + { + throw new NotImplementedException(); + } + + public void Save(IEnumerable members, bool raiseEvents = true) + { + throw new NotImplementedException(); + } + + public IEnumerable FindMembersByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith) + { + throw new NotImplementedException(); + } + + public IEnumerable FindMembersByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith) + { + throw new NotImplementedException(); + } + + public int GetMemberCount(MemberCountType countType) + { + throw new NotImplementedException(); + } + + public IEnumerable GetAllMembers(int pageIndex, int pageSize, out int totalRecords) + { + throw new NotImplementedException(); + } + + #endregion + #region Implementation of IUserService /// @@ -43,22 +151,13 @@ namespace Umbraco.Core.Services public IProfile GetProfileById(int id) { var user = GetUserById(id); - return new Profile(user.Id, user.Name); + return user; } - public IProfile GetProfileByUserName(string username) + public IProfile GetProfileByUserName(string login) { - var user = GetUserByUserName(username); - return new Profile(user.Id, user.Name); - } - - public IUser GetUserByUserName(string username) - { - using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.Username == username); - return repository.GetByQuery(query).FirstOrDefault(); - } + var user = GetByUsername(login); + return user; } public IUser GetUserById(int id) @@ -69,7 +168,6 @@ namespace Umbraco.Core.Services } } - /// /// Gets an IUserType by its Alias /// @@ -139,45 +237,45 @@ namespace Umbraco.Core.Services } } - /// - /// Creates a new user for logging into the umbraco backoffice - /// - /// - /// - /// - /// - /// - /// - public IMembershipUser CreateMembershipUser(string name, string login, string password, IUserType userType, string email = "") - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateUserRepository(uow)) - { - var loginExists = uow.Database.ExecuteScalar("SELECT COUNT(id) FROM umbracoUser WHERE userLogin = @Login", new { Login = login }) != 0; - if (loginExists) - throw new ArgumentException("Login already exists"); + ///// + ///// Creates a new user for logging into the umbraco backoffice + ///// + ///// + ///// + ///// + ///// + ///// + ///// + //public IMembershipUser CreateMembershipUser(string name, string login, string password, IUserType userType, string email = "") + //{ + // var uow = _uowProvider.GetUnitOfWork(); + // using (var repository = _repositoryFactory.CreateUserRepository(uow)) + // { + // var loginExists = uow.Database.ExecuteScalar("SELECT COUNT(id) FROM umbracoUser WHERE userLogin = @Login", new { Login = login }) != 0; + // if (loginExists) + // throw new ArgumentException("Login already exists"); - var user = new User(userType) - { - DefaultToLiveEditing = false, - Email = email, - Language = Umbraco.Core.Configuration.GlobalSettings.DefaultUILanguage, - Name = name, - Password = password, - DefaultPermissions = userType.Permissions, - Username = login, - StartContentId = -1, - StartMediaId = -1, - NoConsole = false, - IsApproved = true - }; + // var user = new User(userType) + // { + // DefaultToLiveEditing = false, + // Email = email, + // Language = Umbraco.Core.Configuration.GlobalSettings.DefaultUILanguage, + // Name = name, + // Password = password, + // DefaultPermissions = userType.Permissions, + // Username = login, + // StartContentId = -1, + // StartMediaId = -1, + // NoConsole = false, + // IsApproved = true + // }; - repository.AddOrUpdate(user); - uow.Commit(); + // repository.AddOrUpdate(user); + // uow.Commit(); - return user; - } - } + // return user; + // } + //} #endregion diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 3119ae7cf0..27792b168c 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -266,14 +266,11 @@ - - - diff --git a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs index 8494ec7c8c..723bb7d7f3 100644 --- a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.Persistence.Querying public void Generate_Replace_Entity_Permissions_Test() { // Act - var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, "A", new object[] {10, 11, 12}); + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(123, new[]{"A"}, new object[] {10, 11, 12}); // Assert Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Persistence.Querying public void Generate_Replace_Entity_Permissions_With_Descendants_Test() { // Act - var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] {123, 456}, "A", new object[] {10, 11, 12}); + var sql = PermissionRepository.GenerateReplaceEntityPermissionsSql(new[] { 123, 456 }, new[] { "A" }, new object[] { 10, 11, 12 }); // Assert Assert.AreEqual(@"SET [permission]='A' WHERE (([nodeId]=123 OR [nodeId]=456) AND ([userId]=10 OR [userId]=11 OR [userId]=12))", sql); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index a1adedf149..ff47f5b172 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -69,7 +69,7 @@ namespace Umbraco.Tests.Persistence.Repositories unitOfWork.Commit(); // Act - repository.AssignEntityPermissions(parentPage, "A", new object[] { 0 }); + repository.AssignEntityPermissions(parentPage, new[] { "A" }, new object[] { 0 }); var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage); repository.AddOrUpdate(childPage); unitOfWork.Commit(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index b477d8b8a1..6a4ad7de12 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -131,14 +131,14 @@ namespace Umbraco.Tests.Persistence.Repositories unitOfWork.Commit(); // Act - var resolved = repository.Get((int)user.Id); + var resolved = (User)repository.Get((int)user.Id); resolved.Name = "New Name"; - resolved.DefaultPermissions = "ZYX"; + resolved.DefaultPermissions = new[]{"Z", "Y", "X"}; resolved.Language = "fr"; resolved.IsApproved = false; resolved.Password = "new"; - resolved.NoConsole = true; + resolved.IsLockedOut = true; resolved.StartContentId = 10; resolved.StartMediaId = 11; resolved.DefaultToLiveEditing = true; @@ -148,7 +148,7 @@ namespace Umbraco.Tests.Persistence.Repositories repository.AddOrUpdate(resolved); unitOfWork.Commit(); - var updatedItem = repository.Get((int)user.Id); + var updatedItem = (User)repository.Get((int)user.Id); // Assert Assert.That(updatedItem.Id, Is.EqualTo(resolved.Id)); @@ -157,7 +157,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(updatedItem.Language, Is.EqualTo(resolved.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(resolved.IsApproved)); Assert.That(updatedItem.Password, Is.EqualTo(resolved.Password)); - Assert.That(updatedItem.NoConsole, Is.EqualTo(resolved.NoConsole)); + Assert.That(updatedItem.IsLockedOut, Is.EqualTo(resolved.IsLockedOut)); Assert.That(updatedItem.StartContentId, Is.EqualTo(resolved.StartContentId)); Assert.That(updatedItem.StartMediaId, Is.EqualTo(resolved.StartMediaId)); Assert.That(updatedItem.DefaultToLiveEditing, Is.EqualTo(resolved.DefaultToLiveEditing)); @@ -492,10 +492,10 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); Assert.That(updatedItem.Password, Is.EqualTo(originalUser.Password)); - Assert.That(updatedItem.NoConsole, Is.EqualTo(originalUser.NoConsole)); + Assert.That(updatedItem.IsLockedOut, Is.EqualTo(originalUser.IsLockedOut)); Assert.That(updatedItem.StartContentId, Is.EqualTo(originalUser.StartContentId)); Assert.That(updatedItem.StartMediaId, Is.EqualTo(originalUser.StartMediaId)); - Assert.That(updatedItem.DefaultToLiveEditing, Is.EqualTo(originalUser.DefaultToLiveEditing)); + Assert.That(((User)updatedItem).DefaultToLiveEditing, Is.EqualTo(((User)originalUser).DefaultToLiveEditing)); Assert.That(updatedItem.Email, Is.EqualTo(originalUser.Email)); Assert.That(updatedItem.Username, Is.EqualTo(originalUser.Username)); Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(2)); diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs index 931523a794..67ded331e3 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserTypeRepositoryTest.cs @@ -125,7 +125,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var resolved = repository.Get(userType.Id); resolved.Name = "New Name"; - resolved.Permissions = "ZYX"; + resolved.Permissions = new[]{"Z", "Y", "X"}; repository.AddOrUpdate(resolved); unitOfWork.Commit(); var updatedItem = repository.Get(userType.Id); diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs index b8cc7f6225..8ff168df59 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests/Services/UserServiceTests.cs @@ -33,7 +33,7 @@ namespace Umbraco.Tests.Services var userType = userService.GetUserTypeByAlias("admin"); // Act - var membershipUser = userService.CreateMembershipUser("John Doe", "john@umbraco.io", "12345", userType, "john@umbraco.io"); + var membershipUser = userService.CreateMember("JohnDoe", "john@umbraco.io", "12345", userType); // Assert Assert.That(membershipUser.HasIdentity, Is.True); @@ -55,7 +55,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 = userService.CreateMembershipUser("John Doe", "john@umbraco.io", encodedPassword, userType, "john@umbraco.io"); + var membershipUser = userService.CreateMember("JohnDoe", "john@umbraco.io", encodedPassword, userType); // Assert Assert.That(membershipUser.HasIdentity, Is.True); @@ -70,9 +70,9 @@ namespace Umbraco.Tests.Services public void Can_Remove_Section_From_All_Assigned_Users() { var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - //we know this actually is an IUser so we'll just cast - var user1 = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com"); - var user2 = (IUser)ServiceContext.UserService.CreateMembershipUser("test2", "test2", "test2", userType, "test2@test.com"); + + var user1 = ServiceContext.UserService.CreateMember("test1", "test1@test.com", "test1", userType); + var user2 = ServiceContext.UserService.CreateMember("test2", "test2@test.com", "test2", userType); //adds some allowed sections user1.AddAllowedSection("test"); @@ -96,7 +96,7 @@ namespace Umbraco.Tests.Services { // Arrange var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - var user = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com"); + var user = ServiceContext.UserService.CreateMember("test1", "test1@test.com", "test1", userType); // Act @@ -113,7 +113,7 @@ namespace Umbraco.Tests.Services { // Arrange var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - var user = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com"); + var user = (IUser)ServiceContext.UserService.CreateMember("test1", "test1@test.com", "test1", userType); // Act @@ -130,11 +130,11 @@ namespace Umbraco.Tests.Services { // Arrange var userType = ServiceContext.UserService.GetUserTypeByAlias("admin"); - var originalUser = (IUser)ServiceContext.UserService.CreateMembershipUser("test1", "test1", "test1", userType, "test1@test.com"); + var originalUser = (User)ServiceContext.UserService.CreateMember("test1", "test1@test.com", "test1", userType); // Act - var updatedItem = ServiceContext.UserService.GetUserByUserName(originalUser.Username); + var updatedItem = (User)ServiceContext.UserService.GetByUsername(originalUser.Username); // Assert Assert.IsNotNull(updatedItem); @@ -144,7 +144,7 @@ namespace Umbraco.Tests.Services Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); Assert.That(updatedItem.Password, Is.EqualTo(originalUser.Password)); - Assert.That(updatedItem.NoConsole, Is.EqualTo(originalUser.NoConsole)); + Assert.That(updatedItem.IsLockedOut, Is.EqualTo(originalUser.IsLockedOut)); Assert.That(updatedItem.StartContentId, Is.EqualTo(originalUser.StartContentId)); Assert.That(updatedItem.StartMediaId, Is.EqualTo(originalUser.StartMediaId)); Assert.That(updatedItem.DefaultToLiveEditing, Is.EqualTo(originalUser.DefaultToLiveEditing)); diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs index 7df112515d..cdd561ee49 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs @@ -18,8 +18,8 @@ namespace Umbraco.Tests.TestHelpers.Entities IsApproved = true, Name = "TestUser" + suffix, Password = "testing", - NoConsole = false, - DefaultPermissions = "ABC", + IsLockedOut = false, + DefaultPermissions = new[]{"A", "B", "C"}, StartContentId = -1, StartMediaId = -1, DefaultToLiveEditing = false, diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs index 47ec3442b6..ace5ac405a 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUserType.cs @@ -10,7 +10,7 @@ namespace Umbraco.Tests.TestHelpers.Entities { Alias = "testUserType" + suffix, Name = "TestUserType" + suffix, - Permissions = "ABC" + Permissions = new[]{"A", "B", "C"} }; } }