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 ;
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-06 11:04:26 +11:00
internal 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 > ( ) ;
_sectionCollection . CollectionChanged + = SectionCollectionChanged ;
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 ;
_password = password ;
}
2014-01-06 11:04:26 +11:00
private readonly IUserType _userType ;
private bool _hasIdentity ;
private object _id ;
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 ;
2014-01-06 15:38:34 +11:00
private Guid _key ;
2014-01-06 11:04:26 +11:00
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 ) ;
2014-01-06 15:38:34 +11:00
private static readonly PropertyInfo KeySelector = ExpressionHelper . GetPropertyInfo < User , Guid > ( x = > x . Key ) ;
2014-01-06 11:04:26 +11:00
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 ) ;
2012-11-09 14:45:28 -01:00
#region Implementation of IEntity
2012-11-11 06:53:02 -01:00
[IgnoreDataMember]
2012-11-09 14:45:28 -01:00
public bool HasIdentity { get { return Id ! = null | | _hasIdentity ; } }
2012-11-11 06:53:02 -01:00
[IgnoreDataMember]
2012-11-09 14:45:28 -01:00
int IEntity . Id
{
get
{
2014-01-06 11:04:26 +11:00
return int . Parse ( Id . ToString ( ) ) ;
2012-11-09 14:45:28 -01:00
}
set
{
2014-01-06 11:04:26 +11:00
Id = value ;
2012-11-09 14:45:28 -01:00
_hasIdentity = true ;
}
}
2014-01-06 15:38:34 +11:00
[IgnoreDataMember]
public Guid Key
{
get
{
return _key ;
}
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_key = value ;
return _key ;
} , _key , KeySelector ) ;
}
}
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-06 15:38:34 +11:00
get { return Key ; }
2014-01-06 11:04:26 +11:00
set
{
2014-01-06 15:38:34 +11:00
var result = value . TryConvertTo < Guid > ( ) ;
if ( result . Success )
2014-01-06 11:04:26 +11:00
{
2014-01-06 15:38:34 +11:00
Key = result . Result ;
}
else
{
throw new NotSupportedException ( "The User object cannot have a ProviderUserKey of anything other than a GUID" ) ;
}
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
#region Implementation of IProfile
2012-11-05 14:42:21 -01: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 = >
{
_name = value ;
return _name ;
} , _name , NameSelector ) ;
}
}
2012-11-05 14:42:21 -01:00
#endregion
2012-11-09 19:54:10 -01:00
#region Implementation of IUser
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 ) ;
}
}
/// <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 object Id
{
get { return _id ; }
set
{
SetPropertyValueAndDetectChanges ( o = >
{
_id = value ;
return _id ;
} , _id , IdSelector ) ;
}
}
2013-07-03 16:40:22 +10:00
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 ; }
}
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 ( ) ) ;
}
}
2012-11-05 14:42:21 -01:00
}
}