From 988aa661ea89655ef2c8908596378883a3559509 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 12 Jan 2018 10:48:36 +0100 Subject: [PATCH] DataType refactoring preparation - Entity refactoring --- src/Umbraco.Core/Models/DataType.cs | 4 + .../Models/EntityBase/BeingDirty.cs | 37 ++++ src/Umbraco.Core/Models/EntityBase/IEntity.cs | 6 - .../Models/EntityBase/ITreeEntity.cs | 9 +- .../Models/EntityBase/IUmbracoEntity.cs | 19 +- .../Models/Identity/BackOfficeIdentityUser.cs | 184 +++++++++--------- src/Umbraco.Core/Models/Membership/User.cs | 6 +- src/Umbraco.Core/Models/UmbracoEntity.cs | 182 +++++++++-------- .../Models/UmbracoEntityExtensions.cs | 2 + .../Implement/EntityContainerRepository.cs | 2 +- .../Implement/EntityRepository.cs | 150 +++++++------- .../Services/Implement/EntityService.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Tests/Models/Collections/Item.cs | 6 + .../Models/UmbracoEntityTests.cs | 6 +- .../Mapping/ContentTypeMapperProfile.cs | 2 +- .../Mapping/ContentTypeProfileExtensions.cs | 2 +- .../Models/Mapping/EntityMapperProfile.cs | 16 +- .../Models/Mapping/UserMapperProfile.cs | 4 +- .../Trees/TemplatesTreeController.cs | 2 +- 20 files changed, 337 insertions(+), 305 deletions(-) create mode 100644 src/Umbraco.Core/Models/EntityBase/BeingDirty.cs diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs index 2f35115ffd..73c1f0003f 100644 --- a/src/Umbraco.Core/Models/DataType.cs +++ b/src/Umbraco.Core/Models/DataType.cs @@ -159,6 +159,10 @@ namespace Umbraco.Core.Models } } + // fixme - implement that one !! + [DataMember] + public object Configuration { get; set; } + /// [EditorBrowsable(EditorBrowsableState.Never)] IDictionary IUmbracoEntity.AdditionalData => _additionalData; diff --git a/src/Umbraco.Core/Models/EntityBase/BeingDirty.cs b/src/Umbraco.Core/Models/EntityBase/BeingDirty.cs new file mode 100644 index 0000000000..906208f0ac --- /dev/null +++ b/src/Umbraco.Core/Models/EntityBase/BeingDirty.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace Umbraco.Core.Models.EntityBase +{ + /// + /// Provides a concrete implementation of . + /// + /// + /// This class is provided for classes that cannot inherit from + /// and therefore need to implement , by re-using some of + /// logic. + /// + public sealed class BeingDirty : BeingDirtyBase + { + /// + /// Sets a property value, detects changes and manages the dirty flag. + /// + /// The type of the value. + /// The new value. + /// A reference to the value to set. + /// The property selector. + /// A comparer to compare property values. + public new void SetPropertyValueAndDetectChanges(T value, ref T valueRef, PropertyInfo propertySelector, IEqualityComparer comparer = null) + { + base.SetPropertyValueAndDetectChanges(value, ref valueRef, propertySelector, comparer); + } + + /// + /// Registers that a property has changed. + /// + public new void OnPropertyChanged(PropertyInfo propertySelector) + { + base.OnPropertyChanged(propertySelector); + } + } +} diff --git a/src/Umbraco.Core/Models/EntityBase/IEntity.cs b/src/Umbraco.Core/Models/EntityBase/IEntity.cs index c15eb3ca25..d6f017a7e8 100644 --- a/src/Umbraco.Core/Models/EntityBase/IEntity.cs +++ b/src/Umbraco.Core/Models/EntityBase/IEntity.cs @@ -11,25 +11,21 @@ namespace Umbraco.Core.Models.EntityBase /// /// Gets or sets the integer identifier of the entity. /// - [DataMember] int Id { get; set; } /// /// Gets or sets the Guid unique identifier of the entity. /// - [DataMember] Guid Key { get; set; } /// /// Gets or sets the creation date. /// - [DataMember] DateTime CreateDate { get; set; } /// /// Gets or sets the last update date. /// - [DataMember] DateTime UpdateDate { get; set; } /// @@ -40,13 +36,11 @@ namespace Umbraco.Core.Models.EntityBase /// The delete date has a value when the entity instance has been deleted, but this value /// is transient and not persisted in database (since the entity does not exist anymore). /// - [DataMember] DateTime? DeleteDate { get; set; } /// /// Gets a value indicating whether the entity has an identity. /// - [IgnoreDataMember] bool HasIdentity { get; } } } diff --git a/src/Umbraco.Core/Models/EntityBase/ITreeEntity.cs b/src/Umbraco.Core/Models/EntityBase/ITreeEntity.cs index e5a53903d4..6948e77826 100644 --- a/src/Umbraco.Core/Models/EntityBase/ITreeEntity.cs +++ b/src/Umbraco.Core/Models/EntityBase/ITreeEntity.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Models.EntityBase +using System; + +namespace Umbraco.Core.Models.EntityBase { /// /// Defines an entity that belongs to a tree. @@ -38,5 +40,10 @@ /// Always false for entities that do not support being trashed. /// bool Trashed { get; } + + /// + /// Gets or sets the identifier of the user who created this entity. + /// + int CreatorId { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs b/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs index d7ac509788..ca10bb1e18 100644 --- a/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs +++ b/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Umbraco.Core.Models.EntityBase { @@ -12,16 +13,22 @@ namespace Umbraco.Core.Models.EntityBase /// public interface IUmbracoEntity : ITreeEntity, IRememberBeingDirty { - /// - /// Gets or sets the identifier of the user who created this entity. - /// - int CreatorId { get; set; } - /// /// Gets additional data for this entity. /// IDictionary AdditionalData { get; } // fixme AdditionalData is never null, then we need a HasAdditionalData for checking values? + + ///// + ///// Gets a value indicating whether this entity has children. + ///// + //bool HasChildren { get; } + + ///// + ///// Gets the node object type of the entity. + ///// + //Guid NodeObjectType { get; } + } } diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index fb6a4f6a86..28659d6ffe 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Reflection; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.AspNet.Identity; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Core.Security; @@ -15,6 +14,25 @@ namespace Umbraco.Core.Models.Identity { public class BackOfficeIdentityUser : IdentityUser, IdentityUserClaim>, IRememberBeingDirty { + private static readonly Lazy Ps = new Lazy(); + + private string _email; + private string _userName; + private int _id; + private bool _hasIdentity; + private DateTime? _lastLoginDateUtc; + private bool _emailConfirmed; + private string _name; + private int _accessFailedCount; + private string _passwordHash; + private string _culture; + private ObservableCollection _logins; + private Lazy> _getLogins; + private IReadOnlyUserGroup[] _groups; + private string[] _allowedSections; + private int[] _startMediaIds; + private int[] _startContentIds; + /// /// Used to construct a new instance without an identity /// @@ -24,8 +42,8 @@ namespace Umbraco.Core.Models.Identity /// public static BackOfficeIdentityUser CreateNew(string username, string email, string culture) { - if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username"); - if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", "culture"); + if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(username)); + if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(culture)); var user = new BackOfficeIdentityUser(); user.DisableChangeTracking(); @@ -97,7 +115,7 @@ namespace Umbraco.Core.Models.Identity public override string Email { get => _email; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); } /// @@ -106,7 +124,7 @@ namespace Umbraco.Core.Models.Identity public override string UserName { get => _userName; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _userName, Ps.Value.UserNameSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _userName, Ps.Value.UserNameSelector); } /// @@ -115,7 +133,7 @@ namespace Umbraco.Core.Models.Identity public override DateTime? LastLoginDateUtc { get => _lastLoginDateUtc; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _lastLoginDateUtc, Ps.Value.LastLoginDateUtcSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _lastLoginDateUtc, Ps.Value.LastLoginDateUtcSelector); } /// @@ -124,7 +142,7 @@ namespace Umbraco.Core.Models.Identity public override bool EmailConfirmed { get => _emailConfirmed; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _emailConfirmed, Ps.Value.EmailConfirmedSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _emailConfirmed, Ps.Value.EmailConfirmedSelector); } /// @@ -133,7 +151,7 @@ namespace Umbraco.Core.Models.Identity public string Name { get => _name; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); } /// @@ -142,7 +160,7 @@ namespace Umbraco.Core.Models.Identity public override int AccessFailedCount { get => _accessFailedCount; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _accessFailedCount, Ps.Value.AccessFailedCountSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _accessFailedCount, Ps.Value.AccessFailedCountSelector); } /// @@ -151,7 +169,7 @@ namespace Umbraco.Core.Models.Identity public override string PasswordHash { get => _passwordHash; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _passwordHash, Ps.Value.PasswordHashSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _passwordHash, Ps.Value.PasswordHashSelector); } @@ -164,7 +182,7 @@ namespace Umbraco.Core.Models.Identity set { if (value == null) value = new int[0]; - _tracker.SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdsSelector, Ps.Value.StartIdsComparer); + _beingDirty.SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdsSelector, Ps.Value.StartIdsComparer); } } @@ -177,7 +195,7 @@ namespace Umbraco.Core.Models.Identity set { if (value == null) value = new int[0]; - _tracker.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdsSelector, Ps.Value.StartIdsComparer); + _beingDirty.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdsSelector, Ps.Value.StartIdsComparer); } } @@ -192,7 +210,7 @@ namespace Umbraco.Core.Models.Identity public string Culture { get => _culture; - set => _tracker.SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); + set => _beingDirty.SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); } public IReadOnlyUserGroup[] Groups @@ -216,7 +234,7 @@ namespace Umbraco.Core.Models.Identity } _roles.CollectionChanged += _roles_CollectionChanged; - _tracker.SetPropertyValueAndDetectChanges(value, ref _groups, Ps.Value.GroupsSelector, Ps.Value.GroupsComparer); + _beingDirty.SetPropertyValueAndDetectChanges(value, ref _groups, Ps.Value.GroupsSelector, Ps.Value.GroupsComparer); } } @@ -272,12 +290,12 @@ namespace Umbraco.Core.Models.Identity void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - _tracker.OnPropertyChanged(Ps.Value.LoginsSelector); + _beingDirty.OnPropertyChanged(Ps.Value.LoginsSelector); } private void _roles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - _tracker.OnPropertyChanged(Ps.Value.RolesSelector); + _beingDirty.OnPropertyChanged(Ps.Value.RolesSelector); } private readonly ObservableCollection> _roles; @@ -309,74 +327,80 @@ namespace Umbraco.Core.Models.Identity /// public void SetLoginsCallback(Lazy> callback) { - _getLogins = callback ?? throw new ArgumentNullException("callback"); + _getLogins = callback ?? throw new ArgumentNullException(nameof(callback)); } - #region Change tracking + #region BeingDirty - public void DisableChangeTracking() - { - _tracker.DisableChangeTracking(); - } + private readonly BeingDirty _beingDirty = new BeingDirty(); - public void EnableChangeTracking() - { - _tracker.EnableChangeTracking(); - } - - /// - /// Since this class only has change tracking turned on for Email/Username this will return true if either of those have changed - /// - /// + /// public bool IsDirty() { - return _tracker.IsDirty(); + return _beingDirty.IsDirty(); } - /// - /// Returns true if the specified property is dirty - /// - /// - /// + /// public bool IsPropertyDirty(string propName) { - return _tracker.IsPropertyDirty(propName); + return _beingDirty.IsPropertyDirty(propName); + } + + /// + public IEnumerable GetDirtyProperties() + { + return _beingDirty.GetDirtyProperties(); + } + + /// + public void ResetDirtyProperties() + { + _beingDirty.ResetDirtyProperties(); + } + + /// + public bool WasDirty() + { + return _beingDirty.WasDirty(); + } + + /// + public bool WasPropertyDirty(string propertyName) + { + return _beingDirty.WasPropertyDirty(propertyName); + } + + /// + public void ResetWereDirtyProperties() + { + _beingDirty.ResetWereDirtyProperties(); + } + + /// + public void ResetDirtyProperties(bool rememberDirty) + { + _beingDirty.ResetDirtyProperties(rememberDirty); } /// - /// Resets dirty properties + /// Disables change tracking. /// - void ICanBeDirty.ResetDirtyProperties() + public void DisableChangeTracking() { - _tracker.ResetDirtyProperties(); + _beingDirty.DisableChangeTracking(); } - bool IRememberBeingDirty.WasDirty() + /// + /// Enables change tracking. + /// + public void EnableChangeTracking() { - return _tracker.WasDirty(); + _beingDirty.EnableChangeTracking(); } - bool IRememberBeingDirty.WasPropertyDirty(string propertyName) - { - return _tracker.WasPropertyDirty(propertyName); - } + #endregion - IEnumerable ICanBeDirty.GetDirtyProperties() - { - return _tracker.GetDirtyProperties(); - } - - void IRememberBeingDirty.ResetWereDirtyProperties() - { - _tracker.ResetWereDirtyProperties(); - } - - public void ResetDirtyProperties(bool rememberDirty) - { - _tracker.ResetDirtyProperties(rememberDirty); - } - - private static readonly Lazy Ps = new Lazy(); + // ReSharper disable once ClassNeverInstantiated.Local private class PropertySelectors { public readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo(x => x.Email); @@ -402,39 +426,5 @@ namespace Umbraco.Core.Models.Identity groups => groups.GetHashCode()); } - - private readonly ChangeTracker _tracker = new ChangeTracker(); - private string _email; - private string _userName; - private int _id; - private bool _hasIdentity = false; - private DateTime? _lastLoginDateUtc; - private bool _emailConfirmed; - private string _name; - private int _accessFailedCount; - private string _passwordHash; - private string _culture; - private ObservableCollection _logins; - private Lazy> _getLogins; - private IReadOnlyUserGroup[] _groups; - private string[] _allowedSections; - private int[] _startMediaIds; - private int[] _startContentIds; - - /// - /// internal class used to track changes for properties that have it enabled - /// - private class ChangeTracker : BeingDirtyBase - { - /// - /// Make this public so that it's usable - /// - /// - public new void OnPropertyChanged(PropertyInfo propertyInfo) - { - base.OnPropertyChanged(propertyInfo); - } - } - #endregion } } diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 2d2375cc85..61b6077c0a 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -300,7 +300,7 @@ namespace Umbraco.Core.Models.Membership Id = int.MinValue, Key = Guid.Empty, CreateDate = default(DateTime), - DeletedDate = null, + DeleteDate = null, Name = "Temp", Permissions = new List(), UpdateDate = default(DateTime) @@ -321,7 +321,7 @@ namespace Umbraco.Core.Models.Membership Id = realGroup.Id, Key = realGroup.Key, CreateDate = realGroup.CreateDate, - DeletedDate = realGroup.DeleteDate, + DeleteDate = realGroup.DeleteDate, Name = realGroup.Name, Permissions = realGroup.Permissions, UpdateDate = realGroup.UpdateDate @@ -338,7 +338,7 @@ namespace Umbraco.Core.Models.Membership Id = realGroup.Id, Key = realGroup.Key, CreateDate = realGroup.CreateDate, - DeletedDate = realGroup.DeleteDate, + DeleteDate = realGroup.DeleteDate, Name = realGroup.Name, Permissions = realGroup.Permissions, UpdateDate = realGroup.UpdateDate diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs index aebf0a4de0..d2130c3f86 100644 --- a/src/Umbraco.Core/Models/UmbracoEntity.cs +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -6,12 +6,63 @@ using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Models { + // fixme - changing the name of some properties that were in additionalData => must update corresponding javascript? + + public class UmbracoContentEntity : UmbracoEntity + { + private static PropertySelectors _selectors; + private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); + + private string _contentTypeAlias; + + private class PropertySelectors + { + public readonly PropertyInfo ContentTypeAlias = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeAlias); + } + + public string ContentTypeAlias + { + get => _contentTypeAlias; + set => SetPropertyValueAndDetectChanges(value, ref _contentTypeAlias, Selectors.ContentTypeAlias); + } + } + + public class UmbracoDocumentEntity : UmbracoContentEntity + { + private static PropertySelectors _selectors; + private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); + + private bool _published; + private bool _edited; + + private class PropertySelectors + { + public readonly PropertyInfo Published = ExpressionHelper.GetPropertyInfo(x => x.Published); + public readonly PropertyInfo Edited = ExpressionHelper.GetPropertyInfo(x => x.Edited); + } + + public bool Published + { + get => _published; + set => SetPropertyValueAndDetectChanges(value, ref _published, Selectors.Published); + } + + public bool Edited + { + get => _edited; + set => SetPropertyValueAndDetectChanges(value, ref _edited, Selectors.Edited); + } + } + /// /// Implementation of the for internal use. /// public class UmbracoEntity : EntityBase.EntityBase, IUmbracoEntity { - private static readonly Lazy Ps = new Lazy(); + private static PropertySelectors _selectors; + private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors()); + + private Guid _nodeObjectType; private int _creatorId; @@ -24,147 +75,100 @@ namespace Umbraco.Core.Models private bool _hasChildren; - // fixme - these are for IContent only - MOVE! - private bool _published; - private bool _edited; - - // fixme - these are for IContentBase only - MOVE! - private string _contentTypeAlias; - private Guid _nodeObjectTypeId; - - // ReSharper disable once ClassNeverInstantiated.Local - private class PropertySelectors - { - public readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); - public readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level); - public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); - public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId); - public readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path); - public readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); - public readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed); - public readonly PropertyInfo HasChildrenSelector = ExpressionHelper.GetPropertyInfo(x => x.HasChildren); - public readonly PropertyInfo PublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.Published); - public readonly PropertyInfo EditedSelector = ExpressionHelper.GetPropertyInfo(x => x.Edited); - public readonly PropertyInfo ContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeAlias); - public readonly PropertyInfo ContentTypeIconSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeIcon); - public readonly PropertyInfo ContentTypeThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeThumbnail); - public readonly PropertyInfo NodeObjectTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeObjectTypeId); - } - + // fixme - usage private string _contentTypeIcon; private string _contentTypeThumbnail; - public static readonly UmbracoEntity Root = new UmbracoEntity(false) { Path = "-1", Name = "root", HasChildren = true }; + // fixme - are we tracking changes on something that's basically READONLY? + private class PropertySelectors + { + public readonly PropertyInfo CreatorId = ExpressionHelper.GetPropertyInfo(x => x.CreatorId); + public readonly PropertyInfo Level = ExpressionHelper.GetPropertyInfo(x => x.Level); + public readonly PropertyInfo Name = ExpressionHelper.GetPropertyInfo(x => x.Name); + public readonly PropertyInfo ParentId = ExpressionHelper.GetPropertyInfo(x => x.ParentId); + public readonly PropertyInfo Path = ExpressionHelper.GetPropertyInfo(x => x.Path); + public readonly PropertyInfo SortOrder = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); + public readonly PropertyInfo Trashed = ExpressionHelper.GetPropertyInfo(x => x.Trashed); + public readonly PropertyInfo HasChildren = ExpressionHelper.GetPropertyInfo(x => x.HasChildren); + public readonly PropertyInfo NodeObjectType = ExpressionHelper.GetPropertyInfo(x => x.NodeObjectType); + public readonly PropertyInfo ContentTypeIcon = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeIcon); + public readonly PropertyInfo ContentTypeThumbnail = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeThumbnail); + } + + public static readonly UmbracoEntity Root = new UmbracoEntity { Path = "-1", Name = "root", HasChildren = true }; public UmbracoEntity() { AdditionalData = new Dictionary(); } - public UmbracoEntity(bool trashed) - { - AdditionalData = new Dictionary(); - Trashed = trashed; - } - - // for MySql - public UmbracoEntity(UInt64 trashed) - { - AdditionalData = new Dictionary(); - Trashed = trashed == 1; - } - public int CreatorId { get => _creatorId; - set => SetPropertyValueAndDetectChanges(value, ref _creatorId, Ps.Value.CreatorIdSelector); + set => SetPropertyValueAndDetectChanges(value, ref _creatorId, Selectors.CreatorId); } public int Level { get => _level; - set => SetPropertyValueAndDetectChanges(value, ref _level, Ps.Value.LevelSelector); + set => SetPropertyValueAndDetectChanges(value, ref _level, Selectors.Level); } public string Name { get => _name; - set => SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); + set => SetPropertyValueAndDetectChanges(value, ref _name, Selectors.Name); } public int ParentId { get => _parentId; - set => SetPropertyValueAndDetectChanges(value, ref _parentId, Ps.Value.ParentIdSelector); + set => SetPropertyValueAndDetectChanges(value, ref _parentId, Selectors.ParentId); } public string Path { get => _path; - set => SetPropertyValueAndDetectChanges(value, ref _path, Ps.Value.PathSelector); + set => SetPropertyValueAndDetectChanges(value, ref _path, Selectors.Path); } public int SortOrder { get => _sortOrder; - set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, Ps.Value.SortOrderSelector); + set => SetPropertyValueAndDetectChanges(value, ref _sortOrder, Selectors.SortOrder); } public bool Trashed { get => _trashed; - private set => SetPropertyValueAndDetectChanges(value, ref _trashed, Ps.Value.TrashedSelector); + set => SetPropertyValueAndDetectChanges(value, ref _trashed, Selectors.Trashed); } - public IDictionary AdditionalData { get; } - - public bool HasChildren { get => _hasChildren; - set - { - SetPropertyValueAndDetectChanges(value, ref _hasChildren, Ps.Value.HasChildrenSelector); - AdditionalData["HasChildren"] = value; // custom and not in IUmbracoEntity - } + set => SetPropertyValueAndDetectChanges(value, ref _hasChildren, Selectors.HasChildren); } - public bool Published + public Guid NodeObjectType { - get => _published; - set - { - SetPropertyValueAndDetectChanges(value, ref _published, Ps.Value.PublishedSelector); - AdditionalData["IsPublished"] = value; // custom and not in IUmbracoEntity - } + get => _nodeObjectType; + set => SetPropertyValueAndDetectChanges(value, ref _nodeObjectType, Selectors.NodeObjectType); } - public bool Edited - { - get => _edited; - set - { - SetPropertyValueAndDetectChanges(value, ref _edited, Ps.Value.EditedSelector); - AdditionalData["IsEdited"] = value; // custom and not in IUmbracoEntity - } - } - public string ContentTypeAlias - { - get => _contentTypeAlias; - set - { - SetPropertyValueAndDetectChanges(value, ref _contentTypeAlias, Ps.Value.ContentTypeAliasSelector); - AdditionalData["ContentTypeAlias"] = value; // custom and not in IUmbracoEntity - } - } + + + + public IDictionary AdditionalData { get; } + public string ContentTypeIcon { get => _contentTypeIcon; set { - SetPropertyValueAndDetectChanges(value, ref _contentTypeIcon, Ps.Value.ContentTypeIconSelector); + SetPropertyValueAndDetectChanges(value, ref _contentTypeIcon, Selectors.ContentTypeIcon); AdditionalData["ContentTypeIcon"] = value; // custom and not in IUmbracoEntity } } @@ -174,21 +178,11 @@ namespace Umbraco.Core.Models get => _contentTypeThumbnail; set { - SetPropertyValueAndDetectChanges(value, ref _contentTypeThumbnail, Ps.Value.ContentTypeThumbnailSelector); + SetPropertyValueAndDetectChanges(value, ref _contentTypeThumbnail, Selectors.ContentTypeThumbnail); AdditionalData["ContentTypeThumbnail"] = value; // custom and not in IUmbracoEntity } } - public Guid NodeObjectTypeId - { - get => _nodeObjectTypeId; - set - { - SetPropertyValueAndDetectChanges(value, ref _nodeObjectTypeId, Ps.Value.NodeObjectTypeIdSelector); - AdditionalData["NodeObjectTypeId"] = value; // custom and not in IUmbracoEntity - } - } - public override object DeepClone() { var clone = (UmbracoEntity) base.DeepClone(); diff --git a/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs b/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs index d804feaf2a..e5ed355b2a 100644 --- a/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs +++ b/src/Umbraco.Core/Models/UmbracoEntityExtensions.cs @@ -115,6 +115,8 @@ namespace Umbraco.Core.Models /// public static bool HasChildren(this IUmbracoEntity entity) { + // fixme + //return entity.HasChildren; // but then we would not need this extension method? if (entity.AdditionalData.ContainsKey("HasChildren")) { var convert = entity.AdditionalData["HasChildren"].TryConvertTo(); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs index bd18cc12ac..71c266d210 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -158,7 +158,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // delete Database.Delete(nodeDto); - entity.DeletedDate = DateTime.Now; + entity.DeleteDate = DateTime.Now; } protected override void PersistNewItem(EntityContainer entity) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs index 6631f79859..fad35d0d3c 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs @@ -761,96 +761,86 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #region Factory - // fixme kill all this - //private static void AddAdditionalData(UmbracoEntity entity, IDictionary originalEntityProperties) - //{ - // var entityProps = typeof(IUmbracoEntity).GetPublicProperties().Select(x => x.Name).ToArray(); - - // // figure out what extra properties we have that are not on the IUmbracoEntity and add them to additional data - // foreach (var k in originalEntityProperties.Keys - // .Select(x => new { orig = x, title = x.ToCleanString(CleanStringType.PascalCase | CleanStringType.Ascii | CleanStringType.ConvertCase) }) - // .Where(x => entityProps.InvariantContains(x.title) == false)) - // { - // entity.AdditionalData[k.title] = originalEntityProperties[k.orig]; - // } - //} - - //private static UmbracoEntity BuildEntityFromDynamic(dynamic d) - //{ - // var asDictionary = (IDictionary) d; - // var entity = new UmbracoEntity(d.trashed); - - // try - // { - // entity.DisableChangeTracking(); - - // entity.CreateDate = d.createDate; - // entity.CreatorId = d.nodeUser == null ? 0 : d.nodeUser; - // entity.Id = d.id; - // entity.Key = d.uniqueID; - // entity.Level = d.level; - // entity.Name = d.text; - // entity.NodeObjectTypeId = d.nodeObjectType; - // entity.ParentId = d.parentID; - // entity.Path = d.path; - // entity.SortOrder = d.sortOrder; - // entity.HasChildren = d.children > 0; - - // entity.ContentTypeAlias = asDictionary.ContainsKey("alias") ? (d.alias ?? string.Empty) : string.Empty; - // entity.ContentTypeIcon = asDictionary.ContainsKey("icon") ? (d.icon ?? string.Empty) : string.Empty; - // entity.ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty; - // //entity.VersionId = asDictionary.ContainsKey("versionId") ? asDictionary["versionId"] : Guid.Empty; - - // entity.Published = asDictionary.ContainsKey("published") && (bool) asDictionary["published"]; - // entity.Edited = asDictionary.ContainsKey("edited") && (bool) asDictionary["edited"]; - - // // assign the additional data - // AddAdditionalData(entity, asDictionary); - - // return entity; - // } - // finally - // { - // entity.EnableChangeTracking(); - // } - //} - private static UmbracoEntity BuildEntity(bool isContent, bool isMedia, BaseDto dto) { - var entity = new UmbracoEntity(dto.Trashed); + if (isContent) + return BuildDocumentEntity(dto); + if (isMedia) + return BuildContentEntity(dto); + + var entity = new UmbracoEntity(); try { entity.DisableChangeTracking(); + BuildEntity(entity, dto); + } + finally + { + entity.EnableChangeTracking(); + } - entity.CreateDate = dto.CreateDate; - entity.CreatorId = dto.UserId ?? 0; - entity.Id = dto.NodeId; - entity.Key = dto.UniqueId; - entity.Level = dto.Level; - entity.Name = dto.Text; - entity.NodeObjectTypeId = dto.NodeObjectType; - entity.ParentId = dto.ParentId; - entity.Path = dto.Path; - entity.SortOrder = dto.SortOrder; - entity.HasChildren = dto.Children > 0; + return entity; + } - if (isContent) - { - entity.Published = dto.Published; - entity.Edited = dto.Edited; - } + private static void BuildEntity(UmbracoEntity entity, BaseDto dto) + { + entity.Trashed = dto.Trashed; + entity.CreateDate = dto.CreateDate; + entity.CreatorId = dto.UserId ?? 0; + entity.Id = dto.NodeId; + entity.Key = dto.UniqueId; + entity.Level = dto.Level; + entity.Name = dto.Text; + entity.NodeObjectType = dto.NodeObjectType; + entity.ParentId = dto.ParentId; + entity.Path = dto.Path; + entity.SortOrder = dto.SortOrder; + entity.HasChildren = dto.Children > 0; + } - // fixme what shall we do with versions? - //entity.VersionId = asDictionary.ContainsKey("versionId") ? asDictionary["versionId"] : Guid.Empty; + private static void BuildContentEntity(UmbracoContentEntity entity, BaseDto dto) + { + BuildEntity(entity, dto); + entity.ContentTypeAlias = dto.Alias; - if (isContent || isMedia) - { - entity.ContentTypeAlias = dto.Alias; - entity.ContentTypeIcon = dto.Icon; - entity.ContentTypeThumbnail = dto.Thumbnail; - //entity.??? = dto.IsContainer; - } + // fixme more here... + entity.ContentTypeIcon = dto.Icon; + entity.ContentTypeThumbnail = dto.Thumbnail; + } + + private static void BuildDocumentEntity(UmbracoDocumentEntity entity, BaseDto dto) + { + BuildContentEntity(entity, dto); + entity.Published = dto.Published; + entity.Edited = dto.Edited; + } + + private static UmbracoEntity BuildContentEntity(BaseDto dto) + { + var entity = new UmbracoContentEntity(); + + try + { + entity.DisableChangeTracking(); + BuildContentEntity(entity, dto); + } + finally + { + entity.EnableChangeTracking(); + } + + return entity; + } + + private static UmbracoEntity BuildDocumentEntity(BaseDto dto) + { + var entity = new UmbracoDocumentEntity(); + + try + { + entity.DisableChangeTracking(); + BuildDocumentEntity(entity, dto); } finally { diff --git a/src/Umbraco.Core/Services/Implement/EntityService.cs b/src/Umbraco.Core/Services/Implement/EntityService.cs index e6190f9a8b..df5daf40aa 100644 --- a/src/Umbraco.Core/Services/Implement/EntityService.cs +++ b/src/Umbraco.Core/Services/Implement/EntityService.cs @@ -642,7 +642,7 @@ namespace Umbraco.Core.Services.Implement public virtual UmbracoObjectTypes GetObjectType(IUmbracoEntity entity) { return entity is UmbracoEntity entityImpl - ? UmbracoObjectTypesExtensions.GetUmbracoObjectType(entityImpl.NodeObjectTypeId) + ? UmbracoObjectTypesExtensions.GetUmbracoObjectType(entityImpl.NodeObjectType) : GetObjectType(entity.Id); } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 950133f2da..a460d1ae5f 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -314,6 +314,7 @@ + diff --git a/src/Umbraco.Tests/Models/Collections/Item.cs b/src/Umbraco.Tests/Models/Collections/Item.cs index 0f84fc9cc9..bd9427ad24 100644 --- a/src/Umbraco.Tests/Models/Collections/Item.cs +++ b/src/Umbraco.Tests/Models/Collections/Item.cs @@ -68,6 +68,12 @@ namespace Umbraco.Tests.Models.Collections [DataMember] public DateTime UpdateDate { get; set; } + /// + /// Gets or sets the Deleted Date + /// + [DataMember] + public DateTime? DeleteDate { get; set; } + /// /// Gets or sets the WasCancelled flag, which is used to track /// whether some action against an entity was cancelled through some event. diff --git a/src/Umbraco.Tests/Models/UmbracoEntityTests.cs b/src/Umbraco.Tests/Models/UmbracoEntityTests.cs index 7e0109a286..5325fb4271 100644 --- a/src/Umbraco.Tests/Models/UmbracoEntityTests.cs +++ b/src/Umbraco.Tests/Models/UmbracoEntityTests.cs @@ -172,7 +172,7 @@ namespace Umbraco.Tests.Models HasChildren = true, Edited = true, Published = true, - NodeObjectTypeId = Guid.NewGuid() + NodeObjectType = Guid.NewGuid() }; item.AdditionalData.Add("test1", 3); item.AdditionalData.Add("test2", "valuie"); @@ -207,7 +207,7 @@ namespace Umbraco.Tests.Models Assert.AreEqual(clone.HasChildren, item.HasChildren); Assert.AreEqual(clone.Edited, item.Edited); Assert.AreEqual(clone.Published, item.Published); - Assert.AreEqual(clone.NodeObjectTypeId, item.NodeObjectTypeId); + Assert.AreEqual(clone.NodeObjectType, item.NodeObjectType); Assert.AreEqual(clone.UpdateDate, item.UpdateDate); Assert.AreEqual(clone.AdditionalData.Count, item.AdditionalData.Count); Assert.AreEqual(clone.AdditionalData, item.AdditionalData); @@ -243,7 +243,7 @@ namespace Umbraco.Tests.Models HasChildren = true, Edited = true, Published = true, - NodeObjectTypeId = Guid.NewGuid() + NodeObjectType = Guid.NewGuid() }; item.AdditionalData.Add("test1", 3); item.AdditionalData.Add("test2", "valuie"); diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs index c1155116e3..b7b72437ff 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs @@ -183,7 +183,7 @@ namespace Umbraco.Web.Models.Mapping // see note above - have to do this here? .ForMember(dest => dest.PropertyEditorAlias, opt => opt.Ignore()) - .ForMember(dest => dest.DeletedDate, opt => opt.Ignore()) + .ForMember(dest => dest.DeleteDate, opt => opt.Ignore()) .ForMember(dto => dto.Variations, opt => opt.Ignore()) // fixme - change when UI supports it! diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs index 8595987354..4de7439e0e 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs @@ -30,7 +30,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Id, map => map.Condition(src => src.Id > 0)) .ForMember(dest => dest.Key, map => map.Ignore()) .ForMember(dest => dest.HasIdentity, map => map.Ignore()) - .ForMember(dest => dest.DeletedDate, map => map.Ignore()) + .ForMember(dest => dest.DeleteDate, map => map.Ignore()) .ForMember(dest => dest.PropertyTypes, map => map.Ignore()); } diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs index b4775a3966..51d9320605 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs @@ -21,13 +21,13 @@ namespace Umbraco.Web.Models.Mapping var contentTypeUdiResolver = new ContentTypeUdiResolver(); CreateMap() - .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(src.NodeObjectTypeId), src.Key))) + .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(src.NodeObjectType), src.Key))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentTypeIcon)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.Alias, opt => opt.Ignore()) .AfterMap((src, dest) => { - if (src.NodeObjectTypeId == Constants.ObjectTypes.Member && dest.Icon.IsNullOrWhiteSpace()) + if (src.NodeObjectType == Constants.ObjectTypes.Member && dest.Icon.IsNullOrWhiteSpace()) { dest.Icon = "icon-user"; } @@ -80,7 +80,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); CreateMap() - .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(src.NodeObjectTypeId), src.Key))) + .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(src.NodeObjectType), src.Key))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src=> src.ContentTypeIcon)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.Alias, opt => opt.Ignore()) @@ -89,15 +89,15 @@ namespace Umbraco.Web.Models.Mapping { if (basic.Icon.IsNullOrWhiteSpace()) { - if (entity.NodeObjectTypeId == Constants.ObjectTypes.Member) + if (entity.NodeObjectType == Constants.ObjectTypes.Member) basic.Icon = "icon-user"; - else if (entity.NodeObjectTypeId == Constants.ObjectTypes.DataType) + else if (entity.NodeObjectType == Constants.ObjectTypes.DataType) basic.Icon = "icon-autofill"; - else if (entity.NodeObjectTypeId == Constants.ObjectTypes.DocumentType) + else if (entity.NodeObjectType == Constants.ObjectTypes.DocumentType) basic.Icon = "icon-item-arrangement"; - else if (entity.NodeObjectTypeId == Constants.ObjectTypes.MediaType) + else if (entity.NodeObjectType == Constants.ObjectTypes.MediaType) basic.Icon = "icon-thumbnails"; - else if (entity.NodeObjectTypeId == Constants.ObjectTypes.TemplateType) + else if (entity.NodeObjectType == Constants.ObjectTypes.TemplateType) basic.Icon = "icon-newspaper-alt"; } }); diff --git a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs index 0294ea3da8..731aeccc8d 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs @@ -157,14 +157,14 @@ namespace Umbraco.Web.Models.Mapping }); CreateMap() - .ForMember(x => x.Udi, opt => opt.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key))) + .ForMember(x => x.Udi, opt => opt.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectType), x.Key))) .ForMember(basic => basic.Icon, opt => opt.MapFrom(entity => entity.ContentTypeIcon)) .ForMember(dto => dto.Trashed, opt => opt.Ignore()) .ForMember(x => x.Alias, opt => opt.Ignore()) .ForMember(x => x.AssignedPermissions, opt => opt.Ignore()) .AfterMap((entity, basic) => { - if (entity.NodeObjectTypeId == Constants.ObjectTypes.Member && basic.Icon.IsNullOrWhiteSpace()) + if (entity.NodeObjectType == Constants.ObjectTypes.Member && basic.Icon.IsNullOrWhiteSpace()) { basic.Icon = "icon-user"; } diff --git a/src/Umbraco.Web/Trees/TemplatesTreeController.cs b/src/Umbraco.Web/Trees/TemplatesTreeController.cs index ddde201e8b..8a0910af0e 100644 --- a/src/Umbraco.Web/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web/Trees/TemplatesTreeController.cs @@ -105,7 +105,7 @@ namespace Umbraco.Web.Trees Id = template.Id, Key = template.Key, Name = template.Name, - NodeObjectTypeId = Constants.ObjectTypes.Template, + NodeObjectType = Constants.ObjectTypes.Template, //TODO: Fix parent/paths on templates ParentId = -1, Path = template.Path,