2012-11-05 14:42:21 -01:00
using System ;
using System.Collections.Generic ;
2014-01-06 11:04:26 +11:00
using System.Collections.ObjectModel ;
using System.Collections.Specialized ;
2012-11-09 19:54:10 -01:00
using System.Linq ;
2014-01-06 11:04:26 +11:00
using System.Reflection ;
2012-11-11 06:53:02 -01:00
using System.Runtime.Serialization ;
2014-01-23 18:44:41 +11:00
using Umbraco.Core.Configuration ;
2012-11-09 14:45:28 -01:00
using Umbraco.Core.Models.EntityBase ;
2013-03-07 22:27:47 +06:00
using Umbraco.Core.Persistence.Mappers ;
2012-11-05 14:42:21 -01:00
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a backoffice user
/// </summary>
/// <remarks>
/// Should be internal until a proper user/membership implementation
/// is part of the roadmap.
/// </remarks>
2012-11-11 06:53:02 -01:00
[Serializable]
[DataContract(IsReference = true)]
2014-01-22 14:07:18 +11:00
public class User : TracksChangesEntityBase , IUser
2012-11-05 14:42:21 -01:00
{
2012-11-09 19:54:10 -01:00
public User ( IUserType userType )
{
2014-01-06 11:56:53 +11:00
if ( userType = = null ) throw new ArgumentNullException ( "userType" ) ;
2014-01-06 11:04:26 +11:00
_userType = userType ;
//Groups = new List<object> { userType };
SessionTimeout = 60 ;
_sectionCollection = new ObservableCollection < string > ( ) ;
_addedSections = new List < string > ( ) ;
_removedSections = new List < string > ( ) ;
2014-01-23 18:44:41 +11:00
_language = GlobalSettings . DefaultUILanguage ;
2014-01-06 11:04:26 +11:00
_sectionCollection . CollectionChanged + = SectionCollectionChanged ;
2014-02-17 11:17:15 +11:00
_isApproved = true ;
_isLockedOut = false ;
2014-02-17 11:48:32 +11:00
_startContentId = - 1 ;
_startMediaId = - 1 ;
2012-11-09 19:54:10 -01:00
}
2014-01-06 11:56:53 +11:00
public User ( string name , string email , string username , string password , IUserType userType )
: this ( userType )
{
_name = name ;
_email = email ;
_username = username ;
2014-02-17 11:17:15 +11:00
_password = password ;
_isApproved = true ;
_isLockedOut = false ;
2014-02-17 11:48:32 +11:00
_startContentId = - 1 ;
_startMediaId = - 1 ;
2014-01-06 11:56:53 +11:00
}
2014-01-23 18:44:41 +11:00
private IUserType _userType ;
2014-01-06 11:04:26 +11:00
private bool _hasIdentity ;
2014-01-22 14:07:18 +11:00
private int _id ;
2014-01-06 11:04:26 +11:00
private string _name ;
private Type _userTypeKey ;
private readonly List < string > _addedSections ;
private readonly List < string > _removedSections ;
private readonly ObservableCollection < string > _sectionCollection ;
private int _sessionTimeout ;
private int _startContentId ;
private int _startMediaId ;
private string _username ;
private string _email ;
private string _password ;
private bool _isApproved ;
private bool _isLockedOut ;
private string _language ;
private IEnumerable < string > _defaultPermissions ;
private bool _defaultToLiveEditing ;
private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper . GetPropertyInfo < User , int > ( x = > x . SessionTimeout ) ;
private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper . GetPropertyInfo < User , int > ( x = > x . StartContentId ) ;
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper . GetPropertyInfo < User , int > ( x = > x . StartMediaId ) ;
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper . GetPropertyInfo < User , IEnumerable < string > > ( x = > x . AllowedSections ) ;
private static readonly PropertyInfo IdSelector = ExpressionHelper . GetPropertyInfo < User , object > ( x = > x . Id ) ;
private static readonly PropertyInfo NameSelector = ExpressionHelper . GetPropertyInfo < User , string > ( x = > x . Name ) ;
private static readonly PropertyInfo UserTypeKeySelector = ExpressionHelper . GetPropertyInfo < User , Type > ( x = > x . ProviderUserKeyType ) ;
private static readonly PropertyInfo UsernameSelector = ExpressionHelper . GetPropertyInfo < User , string > ( x = > x . Username ) ;
private static readonly PropertyInfo EmailSelector = ExpressionHelper . GetPropertyInfo < User , string > ( x = > x . Email ) ;
private static readonly PropertyInfo PasswordSelector = ExpressionHelper . GetPropertyInfo < User , string > ( x = > x . Password ) ;
private static readonly PropertyInfo IsLockedOutSelector = ExpressionHelper . GetPropertyInfo < User , bool > ( x = > x . IsLockedOut ) ;
private static readonly PropertyInfo IsApprovedSelector = ExpressionHelper . GetPropertyInfo < User , bool > ( x = > x . IsApproved ) ;
private static readonly PropertyInfo LanguageSelector = ExpressionHelper . GetPropertyInfo < User , string > ( x = > x . Language ) ;
private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper . GetPropertyInfo < User , IEnumerable < string > > ( x = > x . DefaultPermissions ) ;
private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper . GetPropertyInfo < User , bool > ( x = > x . DefaultToLiveEditing ) ;
2014-01-23 17:11:58 +11:00
private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper . GetPropertyInfo < User , bool > ( x = > x . HasIdentity ) ;
2014-01-23 18:44:41 +11:00
private static readonly PropertyInfo UserTypeSelector = ExpressionHelper . GetPropertyInfo < User , IUserType > ( x = > x . UserType ) ;
2014-01-06 11:04:26 +11:00
2012-11-09 14:45:28 -01:00
#region Implementation of IEntity
2012-11-11 06:53:02 -01:00
[IgnoreDataMember]
2014-01-23 17:11:58 +11:00
public bool HasIdentity
{
get
{
return _hasIdentity ;
}
protected set
{
SetPropertyValueAndDetectChanges ( o = >
{
_hasIdentity = value ;
return _hasIdentity ;
} , _hasIdentity , HasIdentitySelector ) ;
}
}
2012-11-09 14:45:28 -01:00
2014-01-23 17:11:58 +11:00
[DataMember]
public int Id
2012-11-09 14:45:28 -01:00
{
get
{
2014-01-23 17:11:58 +11:00
return _id ;
2012-11-09 14:45:28 -01:00
}
set
{
2014-01-23 17:11:58 +11:00
SetPropertyValueAndDetectChanges ( o = >
{
_id = value ;
HasIdentity = true ; //set the has Identity
return _id ;
} , _id , IdSelector ) ;
2012-11-09 14:45:28 -01:00
}
}
2014-01-08 18:12:07 +11:00
//this doesn't get used
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-08 18:12:07 +11:00
public Guid Key { get ; set ; }
2012-11-09 14:45:28 -01:00
#endregion
2012-11-05 14:42:21 -01:00
#region Implementation of IMembershipUser
2014-01-06 11:04:26 +11:00
[IgnoreDataMember]
public object ProviderUserKey
{
2014-01-08 18:12:07 +11:00
get { return Id ; }
set { throw new NotSupportedException ( "Cannot set the provider user key for a user" ) ; }
2014-01-06 11:04:26 +11:00
}
/// <summary>
/// Gets or sets the type of the provider user key.
/// </summary>
/// <value>
/// The type of the provider user key.
/// </value>
[IgnoreDataMember]
internal Type ProviderUserKeyType
{
get
{
return _userTypeKey ;
}
private set
{
SetPropertyValueAndDetectChanges ( o = >
{
_userTypeKey = value ;
return _userTypeKey ;
} , _userTypeKey , UserTypeKeySelector ) ;
}
}
/// <summary>
/// Sets the type of the provider user key.
/// </summary>
/// <param name="type">The type.</param>
internal void SetProviderUserKeyType ( Type type )
{
ProviderUserKeyType = type ;
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public string Username
{
get { return _username ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_username = value ;
return _username ;
} , _username , UsernameSelector ) ;
}
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public string Email
{
get { return _email ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_email = value ;
return _email ;
} , _email , EmailSelector ) ;
}
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public string Password
{
get { return _password ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_password = value ;
return _password ;
} , _password , PasswordSelector ) ;
}
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public bool IsApproved
{
get { return _isApproved ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_isApproved = value ;
return _isApproved ;
} , _isApproved , IsApprovedSelector ) ;
}
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public bool IsLockedOut
{
get { return _isLockedOut ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_isLockedOut = value ;
return _isLockedOut ;
} , _isLockedOut , IsLockedOutSelector ) ;
}
2014-01-06 15:38:34 +11:00
}
2014-01-06 11:04:26 +11:00
2014-01-07 17:01:22 +11:00
//TODO: Figure out how to support all of this! - we cannot have NotImplementedExceptions because these get used by the IMembershipMemberService<IUser> service so
// we'll just have them as generic get/set which don't interact with the db.
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public string PasswordQuestion { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public string PasswordAnswer { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public string Comments { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public DateTime CreateDate { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public DateTime UpdateDate { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public DateTime LastLoginDate { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public DateTime LastPasswordChangeDate { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public DateTime LastLockoutDate { get ; set ; }
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
2014-01-07 17:01:22 +11:00
public int FailedPasswordAttempts { get ; set ; }
2014-01-06 11:04:26 +11:00
#endregion
2014-01-23 15:31:49 +11:00
#region Implementation of IUser
2014-01-22 14:07:18 +11:00
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public string Name
{
get { return _name ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
2014-01-23 15:31:49 +11:00
{
_name = value ;
return _name ;
} , _name , NameSelector ) ;
2014-01-06 11:04:26 +11:00
}
}
2012-11-05 14:42:21 -01:00
2014-01-06 11:04:26 +11:00
public IEnumerable < string > 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 ) ;
}
}
2014-01-23 15:31:49 +11:00
public IProfile ProfileData
{
get { return new UserProfile ( this ) ; }
}
2014-01-06 11:04:26 +11:00
/// <summary>
/// Used internally to check if we need to add a section in the repository to the db
/// </summary>
internal IEnumerable < string > AddedSections
{
get { return _addedSections ; }
}
/// <summary>
/// Used internally to check if we need to remove a section in the repository to the db
/// </summary>
internal IEnumerable < string > RemovedSections
{
get { return _removedSections ; }
}
/// <summary>
/// Gets or sets the session timeout.
/// </summary>
/// <value>
/// The session timeout.
/// </value>
[DataMember]
public int SessionTimeout
{
get { return _sessionTimeout ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_sessionTimeout = value ;
return _sessionTimeout ;
} , _sessionTimeout , SessionTimeoutSelector ) ;
}
}
/// <summary>
/// Gets or sets the start content id.
/// </summary>
/// <value>
/// The start content id.
/// </value>
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public int StartContentId
{
get { return _startContentId ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_startContentId = value ;
return _startContentId ;
} , _startContentId , StartContentIdSelector ) ;
}
}
/// <summary>
/// Gets or sets the start media id.
/// </summary>
/// <value>
/// The start media id.
/// </value>
[DataMember]
public int StartMediaId
{
get { return _startMediaId ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_startMediaId = value ;
return _startMediaId ;
} , _startMediaId , StartMediaIdSelector ) ;
}
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public string Language
{
get { return _language ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_language = value ;
return _language ;
} , _language , LanguageSelector ) ;
}
}
2012-11-11 06:53:02 -01:00
[DataMember]
2014-01-06 11:04:26 +11:00
public IEnumerable < string > DefaultPermissions
{
get { return _defaultPermissions ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_defaultPermissions = value ;
return _defaultPermissions ;
} , _defaultPermissions , DefaultPermissionsSelector ) ;
}
}
2012-11-09 19:54:10 -01:00
2012-11-11 06:53:02 -01:00
[IgnoreDataMember]
2014-01-06 11:04:26 +11:00
internal bool DefaultToLiveEditing
2012-11-09 19:54:10 -01:00
{
2014-01-06 11:04:26 +11:00
get { return _defaultToLiveEditing ; }
set
2013-07-03 16:40:22 +10:00
{
2014-01-06 11:04:26 +11:00
SetPropertyValueAndDetectChanges ( o = >
{
_defaultToLiveEditing = value ;
return _defaultToLiveEditing ;
} , _defaultToLiveEditing , DefaultToLiveEditingSelector ) ;
2012-11-09 19:54:10 -01:00
}
}
2014-01-06 11:04:26 +11:00
[IgnoreDataMember]
public IUserType UserType
{
get { return _userType ; }
2014-01-23 18:44:41 +11:00
set
{
if ( value . HasIdentity = = false )
{
throw new InvalidOperationException ( "Cannot assign a User Type that has not been persisted" ) ;
}
SetPropertyValueAndDetectChanges ( o = >
{
_userType = value ;
return _userType ;
} , _userType , UserTypeSelector ) ;
}
2014-01-06 11:04:26 +11:00
}
2012-11-09 19:54:10 -01:00
#endregion
2014-01-06 11:04:26 +11:00
/// <summary>
/// Whenever resetting occurs, clear the remembered add/removed collections, even if
/// rememberPreviouslyChangedProperties is true, the AllowedSections property will still
/// be flagged as dirty.
/// </summary>
/// <param name="rememberPreviouslyChangedProperties"></param>
internal override void ResetDirtyProperties ( bool rememberPreviouslyChangedProperties )
{
_addedSections . Clear ( ) ;
_removedSections . Clear ( ) ;
base . ResetDirtyProperties ( rememberPreviouslyChangedProperties ) ;
}
/// <summary>
/// Handles the collection changed event in order for us to flag the AllowedSections property as changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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 < string > ( ) . First ( ) ) ;
_addedSections . RemoveAll ( s = > s = = e . NewItems . Cast < string > ( ) . First ( ) ) ;
//add to the added sections
_addedSections . Add ( e . NewItems . Cast < string > ( ) . 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 < string > ( ) . First ( ) ) ;
_addedSections . RemoveAll ( s = > s = = e . OldItems . Cast < string > ( ) . First ( ) ) ;
//add to the added sections
_removedSections . Add ( e . OldItems . Cast < string > ( ) . First ( ) ) ;
}
}
2014-01-23 15:31:49 +11:00
/// <summary>
/// Internal class used to wrap the user in a profile
/// </summary>
private class UserProfile : IProfile
{
private readonly IUser _user ;
public UserProfile ( IUser user )
{
_user = user ;
}
public object Id
{
get { return _user . Id ; }
set { _user . Id = ( int ) value ; }
}
public string Name
{
get { return _user . Name ; }
set { _user . Name = value ; }
}
}
2012-11-05 14:42:21 -01:00
}
}