Moved Models from Umbraco.Core to Umbraco.Infrastructure

This commit is contained in:
Bjarke Berg
2019-12-09 14:12:06 +01:00
parent 2ea8e7cdd0
commit becce7800b
162 changed files with 1073 additions and 858 deletions

View File

@@ -1,467 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Umbraco.Core.Composing;
using Umbraco.Core.Models.Entities;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a backoffice user
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public class User : EntityBase, IUser, IProfile
{
/// <summary>
/// Constructor for creating a new/empty user
/// </summary>
public User()
{
SessionTimeout = 60;
_userGroups = new HashSet<IReadOnlyUserGroup>();
_language = Current.Configs.Global().DefaultUILanguage; // TODO: inject
_isApproved = true;
_isLockedOut = false;
_startContentIds = new int[] { };
_startMediaIds = new int[] { };
//cannot be null
_rawPasswordValue = "";
}
/// <summary>
/// Constructor for creating a new/empty user
/// </summary>
/// <param name="name"></param>
/// <param name="email"></param>
/// <param name="username"></param>
/// <param name="rawPasswordValue"></param>
public User(string name, string email, string username, string rawPasswordValue)
: this()
{
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Value cannot be null or whitespace.", "email");
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
if (string.IsNullOrEmpty(rawPasswordValue)) throw new ArgumentException("Value cannot be null or empty.", "rawPasswordValue");
_name = name;
_email = email;
_username = username;
_rawPasswordValue = rawPasswordValue;
_userGroups = new HashSet<IReadOnlyUserGroup>();
_isApproved = true;
_isLockedOut = false;
_startContentIds = new int[] { };
_startMediaIds = new int[] { };
}
/// <summary>
/// Constructor for creating a new User instance for an existing user
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="email"></param>
/// <param name="username"></param>
/// <param name="rawPasswordValue"></param>
/// <param name="userGroups"></param>
/// <param name="startContentIds"></param>
/// <param name="startMediaIds"></param>
public User(int id, string name, string email, string username, string rawPasswordValue, IEnumerable<IReadOnlyUserGroup> userGroups, int[] startContentIds, int[] startMediaIds)
: this()
{
//we allow whitespace for this value so just check null
if (rawPasswordValue == null) throw new ArgumentNullException("rawPasswordValue");
if (userGroups == null) throw new ArgumentNullException("userGroups");
if (startContentIds == null) throw new ArgumentNullException("startContentIds");
if (startMediaIds == null) throw new ArgumentNullException("startMediaIds");
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
Id = id;
_name = name;
_email = email;
_username = username;
_rawPasswordValue = rawPasswordValue;
_userGroups = new HashSet<IReadOnlyUserGroup>(userGroups);
_isApproved = true;
_isLockedOut = false;
_startContentIds = startContentIds;
_startMediaIds = startMediaIds;
}
private string _name;
private string _securityStamp;
private string _avatar;
private string _tourData;
private int _sessionTimeout;
private int[] _startContentIds;
private int[] _startMediaIds;
private int _failedLoginAttempts;
private string _username;
private DateTime? _emailConfirmedDate;
private DateTime? _invitedDate;
private string _email;
private string _rawPasswordValue;
private IEnumerable<string> _allowedSections;
private HashSet<IReadOnlyUserGroup> _userGroups;
private bool _isApproved;
private bool _isLockedOut;
private string _language;
private DateTime _lastPasswordChangedDate;
private DateTime _lastLoginDate;
private DateTime _lastLockoutDate;
private bool _defaultToLiveEditing;
private IDictionary<string, object> _additionalData;
private object _additionalDataLock = new object();
//Custom comparer for enumerable
private static readonly DelegateEqualityComparer<IEnumerable<int>> IntegerEnumerableComparer =
new DelegateEqualityComparer<IEnumerable<int>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode());
#region Implementation of IMembershipUser
[DataMember]
public DateTime? EmailConfirmedDate
{
get => _emailConfirmedDate;
set => SetPropertyValueAndDetectChanges(value, ref _emailConfirmedDate, nameof(EmailConfirmedDate));
}
[DataMember]
public DateTime? InvitedDate
{
get => _invitedDate;
set => SetPropertyValueAndDetectChanges(value, ref _invitedDate, nameof(InvitedDate));
}
[DataMember]
public string Username
{
get => _username;
set => SetPropertyValueAndDetectChanges(value, ref _username, nameof(Username));
}
[DataMember]
public string Email
{
get => _email;
set => SetPropertyValueAndDetectChanges(value, ref _email, nameof(Email));
}
[DataMember]
public string RawPasswordValue
{
get => _rawPasswordValue;
set => SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, nameof(RawPasswordValue));
}
[DataMember]
public bool IsApproved
{
get => _isApproved;
set => SetPropertyValueAndDetectChanges(value, ref _isApproved, nameof(IsApproved));
}
[IgnoreDataMember]
public bool IsLockedOut
{
get => _isLockedOut;
set => SetPropertyValueAndDetectChanges(value, ref _isLockedOut, nameof(IsLockedOut));
}
[IgnoreDataMember]
public DateTime LastLoginDate
{
get => _lastLoginDate;
set => SetPropertyValueAndDetectChanges(value, ref _lastLoginDate, nameof(LastLoginDate));
}
[IgnoreDataMember]
public DateTime LastPasswordChangeDate
{
get => _lastPasswordChangedDate;
set => SetPropertyValueAndDetectChanges(value, ref _lastPasswordChangedDate, nameof(LastPasswordChangeDate));
}
[IgnoreDataMember]
public DateTime LastLockoutDate
{
get => _lastLockoutDate;
set => SetPropertyValueAndDetectChanges(value, ref _lastLockoutDate, nameof(LastLockoutDate));
}
[IgnoreDataMember]
public int FailedPasswordAttempts
{
get => _failedLoginAttempts;
set => SetPropertyValueAndDetectChanges(value, ref _failedLoginAttempts, nameof(FailedPasswordAttempts));
}
[IgnoreDataMember]
public string Comments { get; set; }
#endregion
#region Implementation of IUser
public UserState UserState
{
get
{
if (LastLoginDate == default && IsApproved == false && InvitedDate != null)
return UserState.Invited;
if (IsLockedOut)
return UserState.LockedOut;
if (IsApproved == false)
return UserState.Disabled;
// User is not disabled or locked and has never logged in before
if (LastLoginDate == default && IsApproved && IsLockedOut == false)
return UserState.Inactive;
return UserState.Active;
}
}
[DataMember]
public string Name
{
get => _name;
set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name));
}
public IEnumerable<string> AllowedSections
{
get { return _allowedSections ?? (_allowedSections = new List<string>(_userGroups.SelectMany(x => x.AllowedSections).Distinct())); }
}
/// <summary>
/// This used purely for hacking backwards compatibility into this class for &lt; 7.7 compat
/// </summary>
[DoNotClone]
[IgnoreDataMember]
internal List<IUserGroup> GroupsToSave = new List<IUserGroup>();
public IProfile ProfileData => new WrappedUserProfile(this);
/// <summary>
/// The security stamp used by ASP.Net identity
/// </summary>
[IgnoreDataMember]
public string SecurityStamp
{
get => _securityStamp;
set => SetPropertyValueAndDetectChanges(value, ref _securityStamp, nameof(SecurityStamp));
}
[DataMember]
public string Avatar
{
get => _avatar;
set => SetPropertyValueAndDetectChanges(value, ref _avatar, nameof(Avatar));
}
/// <summary>
/// A Json blob stored for recording tour data for a user
/// </summary>
[DataMember]
public string TourData
{
get => _tourData;
set => SetPropertyValueAndDetectChanges(value, ref _tourData, nameof(TourData));
}
/// <summary>
/// Gets or sets the session timeout.
/// </summary>
/// <value>
/// The session timeout.
/// </value>
[DataMember]
public int SessionTimeout
{
get => _sessionTimeout;
set => SetPropertyValueAndDetectChanges(value, ref _sessionTimeout, nameof(SessionTimeout));
}
/// <summary>
/// Gets or sets the start content id.
/// </summary>
/// <value>
/// The start content id.
/// </value>
[DataMember]
[DoNotClone]
public int[] StartContentIds
{
get => _startContentIds;
set => SetPropertyValueAndDetectChanges(value, ref _startContentIds, nameof(StartContentIds), IntegerEnumerableComparer);
}
/// <summary>
/// Gets or sets the start media id.
/// </summary>
/// <value>
/// The start media id.
/// </value>
[DataMember]
[DoNotClone]
public int[] StartMediaIds
{
get => _startMediaIds;
set => SetPropertyValueAndDetectChanges(value, ref _startMediaIds, nameof(StartMediaIds), IntegerEnumerableComparer);
}
[DataMember]
public string Language
{
get => _language;
set => SetPropertyValueAndDetectChanges(value, ref _language, nameof(Language));
}
[IgnoreDataMember]
internal bool DefaultToLiveEditing
{
get => _defaultToLiveEditing;
set => SetPropertyValueAndDetectChanges(value, ref _defaultToLiveEditing, nameof(DefaultToLiveEditing));
}
/// <summary>
/// Gets the groups that user is part of
/// </summary>
[DataMember]
public IEnumerable<IReadOnlyUserGroup> Groups => _userGroups;
public void RemoveGroup(string group)
{
foreach (var userGroup in _userGroups.ToArray())
{
if (userGroup.Alias == group)
{
_userGroups.Remove(userGroup);
//reset this flag so it's rebuilt with the assigned groups
_allowedSections = null;
OnPropertyChanged(nameof(Groups));
}
}
}
public void ClearGroups()
{
if (_userGroups.Count > 0)
{
_userGroups.Clear();
//reset this flag so it's rebuilt with the assigned groups
_allowedSections = null;
OnPropertyChanged(nameof(Groups));
}
}
public void AddGroup(IReadOnlyUserGroup group)
{
if (_userGroups.Add(group))
{
//reset this flag so it's rebuilt with the assigned groups
_allowedSections = null;
OnPropertyChanged(nameof(Groups));
}
}
#endregion
/// <summary>
/// This is used as an internal cache for this entity - specifically for calculating start nodes so we don't re-calculated all of the time
/// </summary>
[IgnoreDataMember]
[DoNotClone]
internal IDictionary<string, object> AdditionalData
{
get
{
lock (_additionalDataLock)
{
return _additionalData ?? (_additionalData = new Dictionary<string, object>());
}
}
}
[IgnoreDataMember]
[DoNotClone]
internal object AdditionalDataLock => _additionalDataLock;
protected override void PerformDeepClone(object clone)
{
base.PerformDeepClone(clone);
var clonedEntity = (User)clone;
//manually clone the start node props
clonedEntity._startContentIds = _startContentIds.ToArray();
clonedEntity._startMediaIds = _startMediaIds.ToArray();
// this value has been cloned and points to the same object
// which obviously is bad - needs to point to a new object
clonedEntity._additionalDataLock = new object();
if (_additionalData != null)
{
// clone._additionalData points to the same dictionary, which is bad, because
// changing one clone impacts all of them - so we need to reset it with a fresh
// dictionary that will contain the same values - and, if some values are deep
// cloneable, they should be deep-cloned too
var cloneAdditionalData = clonedEntity._additionalData = new Dictionary<string, object>();
lock (_additionalDataLock)
{
foreach (var kvp in _additionalData)
{
var deepCloneable = kvp.Value as IDeepCloneable;
cloneAdditionalData[kvp.Key] = deepCloneable == null ? kvp.Value : deepCloneable.DeepClone();
}
}
}
//need to create new collections otherwise they'll get copied by ref
clonedEntity._userGroups = new HashSet<IReadOnlyUserGroup>(_userGroups);
clonedEntity._allowedSections = _allowedSections != null ? new List<string>(_allowedSections) : null;
}
/// <summary>
/// Internal class used to wrap the user in a profile
/// </summary>
private class WrappedUserProfile : IProfile
{
private readonly IUser _user;
public WrappedUserProfile(IUser user)
{
_user = user;
}
public int Id => _user.Id;
public string Name => _user.Name;
private bool Equals(WrappedUserProfile other)
{
return _user.Equals(other._user);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((WrappedUserProfile) obj);
}
public override int GetHashCode()
{
return _user.GetHashCode();
}
}
}
}

View File

@@ -1,125 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a Group for a Backoffice User
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public class UserGroup : EntityBase, IUserGroup, IReadOnlyUserGroup
{
private int? _startContentId;
private int? _startMediaId;
private string _alias;
private string _icon;
private string _name;
private IEnumerable<string> _permissions;
private readonly List<string> _sectionCollection;
//Custom comparer for enumerable
private static readonly DelegateEqualityComparer<IEnumerable<string>> StringEnumerableComparer =
new DelegateEqualityComparer<IEnumerable<string>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode());
/// <summary>
/// Constructor to create a new user group
/// </summary>
public UserGroup()
{
_sectionCollection = new List<string>();
}
/// <summary>
/// Constructor to create an existing user group
/// </summary>
/// <param name="userCount"></param>
/// <param name="alias"></param>
/// <param name="name"></param>
/// <param name="permissions"></param>
/// <param name="icon"></param>
public UserGroup(int userCount, string alias, string name, IEnumerable<string> permissions, string icon)
: this()
{
UserCount = userCount;
_alias = alias;
_name = name;
_permissions = permissions;
_icon = icon;
}
[DataMember]
public int? StartMediaId
{
get => _startMediaId;
set => SetPropertyValueAndDetectChanges(value, ref _startMediaId, nameof(StartMediaId));
}
[DataMember]
public int? StartContentId
{
get => _startContentId;
set => SetPropertyValueAndDetectChanges(value, ref _startContentId, nameof(StartContentId));
}
[DataMember]
public string Icon
{
get => _icon;
set => SetPropertyValueAndDetectChanges(value, ref _icon, nameof(Icon));
}
[DataMember]
public string Alias
{
get => _alias;
set => SetPropertyValueAndDetectChanges(value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase), ref _alias, nameof(Alias));
}
[DataMember]
public string Name
{
get => _name;
set => SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name));
}
/// <summary>
/// The set of default permissions for the user group
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
[DataMember]
public IEnumerable<string> Permissions
{
get => _permissions;
set => SetPropertyValueAndDetectChanges(value, ref _permissions, nameof(Permissions), StringEnumerableComparer);
}
public IEnumerable<string> AllowedSections => _sectionCollection;
public void RemoveAllowedSection(string sectionAlias)
{
if (_sectionCollection.Contains(sectionAlias))
_sectionCollection.Remove(sectionAlias);
}
public void AddAllowedSection(string sectionAlias)
{
if (_sectionCollection.Contains(sectionAlias) == false)
_sectionCollection.Add(sectionAlias);
}
public void ClearAllowedSections()
{
_sectionCollection.Clear();
}
public int UserCount { get; }
}
}