diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 9758c05dd6..88281cb84b 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -15,31 +15,35 @@ en-US umbraco - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index fabd1e25a8..c52c8831e0 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -15,30 +15,35 @@ en-US umbraco - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index b0f30b9779..ee0764bdd3 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -15,18 +15,25 @@ en-US umbraco - - - - - - - - + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index e30bf85fd0..02b26aec86 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -31,7 +31,7 @@ namespace Umbraco.Core.Configuration private static string _reservedPaths; private static string _reservedUrls; //ensure the built on (non-changeable) reserved paths are there at all times - internal const string StaticReservedPaths = "~/app_plugins/,~/install/,"; //must end with a comma! + internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma! internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma! #endregion diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 174b4233f4..f802c2d0d9 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -109,10 +109,9 @@ namespace Umbraco.Core /// public static IEnumerable GetNonGroupedProperties(this IContentBase content) { - var propertyIdsInTabs = content.PropertyGroups.SelectMany(pg => pg.PropertyTypes); return content.Properties - .Where(property => propertyIdsInTabs.Contains(property.PropertyType) == false) - .OrderBy(x => x.PropertyType.SortOrder); + .Where(x => x.PropertyType.PropertyGroupId == null) + .OrderBy(x => x.PropertyType.SortOrder); } /// @@ -178,8 +177,7 @@ namespace Umbraco.Core var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); if (property != null) return property; - var contentTypeService = contentTypeBaseServiceProvider.For(content); - var contentType = contentTypeService.Get(content.ContentTypeId); + var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); var propertyType = contentType.CompositionPropertyTypes .FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); if (propertyType == null) @@ -208,8 +206,7 @@ namespace Umbraco.Core /// public static string StoreFile(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string filepath) { - var contentTypeService = contentTypeBaseServiceProvider.For(content); - var contentType = contentTypeService.Get(content.ContentTypeId); + var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); var propertyType = contentType .CompositionPropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); if (propertyType == null) throw new ArgumentException("Invalid property type alias " + propertyTypeAlias + "."); diff --git a/src/Umbraco.Core/Events/CancellableEnumerableObjectEventArgs.cs b/src/Umbraco.Core/Events/CancellableEnumerableObjectEventArgs.cs index 1a651ef348..1d52d0d847 100644 --- a/src/Umbraco.Core/Events/CancellableEnumerableObjectEventArgs.cs +++ b/src/Umbraco.Core/Events/CancellableEnumerableObjectEventArgs.cs @@ -1,34 +1,36 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Security.Permissions; namespace Umbraco.Core.Events { - [HostProtection(SecurityAction.LinkDemand, SharedState = true)] - public class CancellableEnumerableObjectEventArgs : CancellableObjectEventArgs>, IEquatable> + /// + /// Represents event data, for events that support cancellation, and expose impacted objects. + /// + /// The type of the exposed, impacted objects. + public class CancellableEnumerableObjectEventArgs : CancellableObjectEventArgs>, IEquatable> { - public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, bool canCancel, EventMessages messages, IDictionary additionalData) + public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, bool canCancel, EventMessages messages, IDictionary additionalData) : base(eventObject, canCancel, messages, additionalData) { } - public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, bool canCancel, EventMessages eventMessages) + public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, bool canCancel, EventMessages eventMessages) : base(eventObject, canCancel, eventMessages) { } - public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, EventMessages eventMessages) + public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, EventMessages eventMessages) : base(eventObject, eventMessages) { } - public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, bool canCancel) + public CancellableEnumerableObjectEventArgs(IEnumerable eventObject, bool canCancel) : base(eventObject, canCancel) { } - public CancellableEnumerableObjectEventArgs(IEnumerable eventObject) + public CancellableEnumerableObjectEventArgs(IEnumerable eventObject) : base(eventObject) { } - public bool Equals(CancellableEnumerableObjectEventArgs other) + public bool Equals(CancellableEnumerableObjectEventArgs other) { if (other is null) return false; if (ReferenceEquals(this, other)) return true; @@ -41,7 +43,7 @@ namespace Umbraco.Core.Events if (obj is null) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; - return Equals((CancellableEnumerableObjectEventArgs)obj); + return Equals((CancellableEnumerableObjectEventArgs)obj); } public override int GetHashCode() @@ -49,4 +51,4 @@ namespace Umbraco.Core.Events return HashCodeHelper.GetHashCode(EventObject); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Events/CancellableEventArgs.cs b/src/Umbraco.Core/Events/CancellableEventArgs.cs index 19f576478f..d9d670ea59 100644 --- a/src/Umbraco.Core/Events/CancellableEventArgs.cs +++ b/src/Umbraco.Core/Events/CancellableEventArgs.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Security.Permissions; namespace Umbraco.Core.Events { /// - /// Event args for that can support cancellation + /// Represents event data for events that support cancellation. /// - [HostProtection(SecurityAction.LinkDemand, SharedState = true)] public class CancellableEventArgs : EventArgs, IEquatable { private bool _cancel; diff --git a/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs b/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs index 27ffb1b75d..daf36fd6c8 100644 --- a/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs +++ b/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs @@ -1,15 +1,10 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Security.Permissions; -using Umbraco.Core.Models; +using System.Collections.Generic; namespace Umbraco.Core.Events { /// - /// Used as a base class for the generic type CancellableObjectEventArgs{T} so that we can get direct 'object' access to the underlying EventObject + /// Provides a base class for classes representing event data, for events that support cancellation, and expose an impacted object. /// - [HostProtection(SecurityAction.LinkDemand, SharedState = true)] public abstract class CancellableObjectEventArgs : CancellableEventArgs { protected CancellableObjectEventArgs(object eventObject, bool canCancel, EventMessages messages, IDictionary additionalData) @@ -41,90 +36,11 @@ namespace Umbraco.Core.Events } /// - /// Returns the object relating to the event + /// Gets or sets the impacted object. /// /// /// This is protected so that inheritors can expose it with their own name /// internal object EventObject { get; set; } - - } - - /// - /// Event args for a strongly typed object that can support cancellation - /// - /// - [HostProtection(SecurityAction.LinkDemand, SharedState = true)] - public class CancellableObjectEventArgs : CancellableObjectEventArgs, IEquatable> - { - public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages messages, IDictionary additionalData) - : base(eventObject, canCancel, messages, additionalData) - { - } - - public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages eventMessages) - : base(eventObject, canCancel, eventMessages) - { - } - - public CancellableObjectEventArgs(T eventObject, EventMessages eventMessages) - : base(eventObject, eventMessages) - { - } - - public CancellableObjectEventArgs(T eventObject, bool canCancel) - : base(eventObject, canCancel) - { - } - - public CancellableObjectEventArgs(T eventObject) - : base(eventObject) - { - } - - /// - /// Returns the object relating to the event - /// - /// - /// This is protected so that inheritors can expose it with their own name - /// - protected new T EventObject - { - get { return (T) base.EventObject; } - set { base.EventObject = value; } - } - - public bool Equals(CancellableObjectEventArgs other) - { - if (other is null) return false; - if (ReferenceEquals(this, other)) return true; - return base.Equals(other) && EqualityComparer.Default.Equals(EventObject, other.EventObject); - } - - public override bool Equals(object obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((CancellableObjectEventArgs)obj); - } - - public override int GetHashCode() - { - unchecked - { - return (base.GetHashCode() * 397) ^ EqualityComparer.Default.GetHashCode(EventObject); - } - } - - public static bool operator ==(CancellableObjectEventArgs left, CancellableObjectEventArgs right) - { - return Equals(left, right); - } - - public static bool operator !=(CancellableObjectEventArgs left, CancellableObjectEventArgs right) - { - return !Equals(left, right); - } } } diff --git a/src/Umbraco.Core/Events/CancellableObjectEventArgsOfTEventObject.cs b/src/Umbraco.Core/Events/CancellableObjectEventArgsOfTEventObject.cs new file mode 100644 index 0000000000..ace2ce0a4f --- /dev/null +++ b/src/Umbraco.Core/Events/CancellableObjectEventArgsOfTEventObject.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.Events +{ + /// + /// Represent event data, for events that support cancellation, and expose an impacted object. + /// + /// The type of the exposed, impacted object. + public class CancellableObjectEventArgs : CancellableObjectEventArgs, IEquatable> + { + public CancellableObjectEventArgs(TEventObject eventObject, bool canCancel, EventMessages messages, IDictionary additionalData) + : base(eventObject, canCancel, messages, additionalData) + { + } + + public CancellableObjectEventArgs(TEventObject eventObject, bool canCancel, EventMessages eventMessages) + : base(eventObject, canCancel, eventMessages) + { + } + + public CancellableObjectEventArgs(TEventObject eventObject, EventMessages eventMessages) + : base(eventObject, eventMessages) + { + } + + public CancellableObjectEventArgs(TEventObject eventObject, bool canCancel) + : base(eventObject, canCancel) + { + } + + public CancellableObjectEventArgs(TEventObject eventObject) + : base(eventObject) + { + } + + /// + /// Gets or sets the impacted object. + /// + /// + /// This is protected so that inheritors can expose it with their own name + /// + protected new TEventObject EventObject + { + get => (TEventObject) base.EventObject; + set => base.EventObject = value; + } + + public bool Equals(CancellableObjectEventArgs other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return base.Equals(other) && EqualityComparer.Default.Equals(EventObject, other.EventObject); + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((CancellableObjectEventArgs)obj); + } + + public override int GetHashCode() + { + unchecked + { + return (base.GetHashCode() * 397) ^ EqualityComparer.Default.GetHashCode(EventObject); + } + } + + public static bool operator ==(CancellableObjectEventArgs left, CancellableObjectEventArgs right) + { + return Equals(left, right); + } + + public static bool operator !=(CancellableObjectEventArgs left, CancellableObjectEventArgs right) + { + return !Equals(left, right); + } + } +} diff --git a/src/Umbraco.Core/Events/ContentPublishedEventArgs.cs b/src/Umbraco.Core/Events/ContentPublishedEventArgs.cs index 589e447ba7..8c0690d591 100644 --- a/src/Umbraco.Core/Events/ContentPublishedEventArgs.cs +++ b/src/Umbraco.Core/Events/ContentPublishedEventArgs.cs @@ -1,29 +1,30 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Models; namespace Umbraco.Core.Events { + /// + /// Represents event data for the Published event. + /// public class ContentPublishedEventArgs : PublishEventArgs { + /// + /// Initializes a new instance of the class. + /// public ContentPublishedEventArgs(IEnumerable eventObject, bool canCancel, EventMessages eventMessages) : base(eventObject, canCancel, eventMessages) - { - } + { } /// /// Determines whether a culture has been published, during a Published event. /// public bool HasPublishedCulture(IContent content, string culture) - => content.WasPropertyDirty("_changedCulture_" + culture); + => content.WasPropertyDirty(ContentBase.ChangeTrackingPrefix.ChangedCulture + culture); /// /// Determines whether a culture has been unpublished, during a Published event. /// public bool HasUnpublishedCulture(IContent content, string culture) - => content.WasPropertyDirty("_unpublishedCulture_" + culture); - - - + => content.WasPropertyDirty(ContentBase.ChangeTrackingPrefix.UnpublishedCulture + culture); } } diff --git a/src/Umbraco.Core/Events/ContentPublishingEventArgs.cs b/src/Umbraco.Core/Events/ContentPublishingEventArgs.cs index 35cbf63441..b64bb19def 100644 --- a/src/Umbraco.Core/Events/ContentPublishingEventArgs.cs +++ b/src/Umbraco.Core/Events/ContentPublishingEventArgs.cs @@ -1,21 +1,19 @@ -using System; -using System.Linq; -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Models; namespace Umbraco.Core.Events { + /// + /// Represents event data for the Publishing event. + /// public class ContentPublishingEventArgs : PublishEventArgs { /// - /// Creates a new + /// Initializes a new instance of the class. /// - /// - /// public ContentPublishingEventArgs(IEnumerable eventObject, EventMessages eventMessages) : base(eventObject, eventMessages) - { - } + { } /// /// Determines whether a culture is being published, during a Publishing event. @@ -27,7 +25,6 @@ namespace Umbraco.Core.Events /// Determines whether a culture is being unpublished, during a Publishing event. /// public bool IsUnpublishingCulture(IContent content, string culture) - => content.IsPropertyDirty("_unpublishedCulture_" + culture); //bit of a hack since we know that the content implementation tracks changes this way - + => content.IsPropertyDirty(ContentBase.ChangeTrackingPrefix.UnpublishedCulture + culture); //bit of a hack since we know that the content implementation tracks changes this way } } diff --git a/src/Umbraco.Core/Events/ContentSavedEventArgs.cs b/src/Umbraco.Core/Events/ContentSavedEventArgs.cs index 4d4085b064..e2d8c25dd1 100644 --- a/src/Umbraco.Core/Events/ContentSavedEventArgs.cs +++ b/src/Umbraco.Core/Events/ContentSavedEventArgs.cs @@ -1,30 +1,24 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Models; namespace Umbraco.Core.Events { + /// + /// Represents event data for the Saved event. + /// public class ContentSavedEventArgs : SaveEventArgs { - #region Constructors - /// - /// Creates a new + /// Initializes a new instance of the class. /// - /// - /// - /// public ContentSavedEventArgs(IEnumerable eventObject, EventMessages messages, IDictionary additionalData) : base(eventObject, false, messages, additionalData) - { - } - - #endregion + { } /// /// Determines whether a culture has been saved, during a Saved event. /// public bool HasSavedCulture(IContent content, string culture) - => content.WasPropertyDirty("_updatedCulture_" + culture); + => content.WasPropertyDirty(ContentBase.ChangeTrackingPrefix.UpdatedCulture + culture); } } diff --git a/src/Umbraco.Core/Events/ContentSavingEventArgs.cs b/src/Umbraco.Core/Events/ContentSavingEventArgs.cs index aa62f64349..384353ee2e 100644 --- a/src/Umbraco.Core/Events/ContentSavingEventArgs.cs +++ b/src/Umbraco.Core/Events/ContentSavingEventArgs.cs @@ -1,12 +1,15 @@ -using System.Linq; -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Models; namespace Umbraco.Core.Events { + /// + /// Represent event data for the Saving event. + /// public class ContentSavingEventArgs : SaveEventArgs { #region Factory Methods + /// /// Converts to while preserving all args state /// @@ -43,24 +46,32 @@ namespace Umbraco.Core.Events EventState = EventState, AdditionalData = AdditionalData }; - } + } + #endregion #region Constructors - public ContentSavingEventArgs(IEnumerable eventObject, EventMessages eventMessages) : base(eventObject, eventMessages) - { - } + /// + /// Initializes a new instance of the class. + /// + public ContentSavingEventArgs(IEnumerable eventObject, EventMessages eventMessages) + : base(eventObject, eventMessages) + { } - public ContentSavingEventArgs(IContent eventObject, EventMessages eventMessages) : base(eventObject, eventMessages) - { - } + /// + /// Initializes a new instance of the class. + /// + public ContentSavingEventArgs(IContent eventObject, EventMessages eventMessages) + : base(eventObject, eventMessages) + { } #endregion /// /// Determines whether a culture is being saved, during a Saving event. /// - public bool IsSavingCulture(IContent content, string culture) => content.CultureInfos.TryGetValue(culture, out var cultureInfo) && cultureInfo.IsDirty(); + public bool IsSavingCulture(IContent content, string culture) + => content.CultureInfos.TryGetValue(culture, out var cultureInfo) && cultureInfo.IsDirty(); } } diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 483ba8b0d2..c5930bf998 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -51,7 +51,6 @@ namespace Umbraco.Core.Models : base(name, parent, contentType, properties, culture) { if (contentType == null) throw new ArgumentNullException(nameof(contentType)); - ContentType = new SimpleContentType(contentType); _publishedState = PublishedState.Unpublished; PublishedVersionId = 0; } @@ -79,7 +78,6 @@ namespace Umbraco.Core.Models : base(name, parentId, contentType, properties, culture) { if (contentType == null) throw new ArgumentNullException(nameof(contentType)); - ContentType = new SimpleContentType(contentType); _publishedState = PublishedState.Unpublished; PublishedVersionId = 0; } @@ -172,12 +170,6 @@ namespace Umbraco.Core.Models [IgnoreDataMember] public bool Edited { get; set; } - /// - /// Gets the ContentType used by this content object - /// - [IgnoreDataMember] - public ISimpleContentType ContentType { get; private set; } - /// [IgnoreDataMember] public DateTime? PublishDate { get; set; } // set by persistence @@ -242,7 +234,7 @@ namespace Umbraco.Core.Models public string GetPublishName(string culture) { if (culture.IsNullOrWhiteSpace()) return PublishName; - if (!ContentTypeBase.VariesByCulture()) return null; + if (!ContentType.VariesByCulture()) return null; if (_publishInfos == null) return null; return _publishInfos.TryGetValue(culture, out var infos) ? infos.Name : null; } @@ -251,7 +243,7 @@ namespace Umbraco.Core.Models public DateTime? GetPublishDate(string culture) { if (culture.IsNullOrWhiteSpace()) return PublishDate; - if (!ContentTypeBase.VariesByCulture()) return null; + if (!ContentType.VariesByCulture()) return null; if (_publishInfos == null) return null; return _publishInfos.TryGetValue(culture, out var infos) ? infos.Date : (DateTime?)null; } @@ -311,13 +303,7 @@ namespace Umbraco.Core.Models /// Leaves PropertyTypes intact after change internal void ChangeContentType(IContentType contentType) { - ContentTypeId = contentType.Id; - ContentType = new SimpleContentType(contentType); - ContentTypeBase = contentType; - Properties.EnsurePropertyTypes(PropertyTypes); - - Properties.CollectionChanged -= PropertiesChanged; // be sure not to double add - Properties.CollectionChanged += PropertiesChanged; + ChangeContentType(contentType, false); } /// @@ -328,19 +314,15 @@ namespace Umbraco.Core.Models /// Boolean indicating whether to clear PropertyTypes upon change internal void ChangeContentType(IContentType contentType, bool clearProperties) { + ChangeContentType(new SimpleContentType(contentType)); + if (clearProperties) - { - ContentTypeId = contentType.Id; - ContentType = new SimpleContentType(contentType); - ContentTypeBase = contentType; - Properties.EnsureCleanPropertyTypes(PropertyTypes); + Properties.EnsureCleanPropertyTypes(contentType.CompositionPropertyTypes); + else + Properties.EnsurePropertyTypes(contentType.CompositionPropertyTypes); - Properties.CollectionChanged -= PropertiesChanged; // be sure not to double add - Properties.CollectionChanged += PropertiesChanged; - return; - } - - ChangeContentType(contentType); + Properties.CollectionChanged -= PropertiesChanged; // be sure not to double add + Properties.CollectionChanged += PropertiesChanged; } public override void ResetWereDirtyProperties() @@ -385,19 +367,19 @@ namespace Umbraco.Core.Models public override bool IsPropertyDirty(string propertyName) { //Special check here since we want to check if the request is for changed cultures - if (propertyName.StartsWith("_publishedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.PublishedCulture)) { - var culture = propertyName.TrimStart("_publishedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.PublishedCulture); return _currentPublishCultureChanges.addedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_unpublishedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.UnpublishedCulture)) { - var culture = propertyName.TrimStart("_unpublishedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.UnpublishedCulture); return _currentPublishCultureChanges.removedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_changedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.ChangedCulture)) { - var culture = propertyName.TrimStart("_changedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.ChangedCulture); return _currentPublishCultureChanges.updatedCultures?.Contains(culture) ?? false; } @@ -409,19 +391,19 @@ namespace Umbraco.Core.Models public override bool WasPropertyDirty(string propertyName) { //Special check here since we want to check if the request is for changed cultures - if (propertyName.StartsWith("_publishedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.PublishedCulture)) { - var culture = propertyName.TrimStart("_publishedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.PublishedCulture); return _previousPublishCultureChanges.addedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_unpublishedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.UnpublishedCulture)) { - var culture = propertyName.TrimStart("_unpublishedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.UnpublishedCulture); return _previousPublishCultureChanges.removedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_changedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.ChangedCulture)) { - var culture = propertyName.TrimStart("_changedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.ChangedCulture); return _previousPublishCultureChanges.updatedCultures?.Contains(culture) ?? false; } @@ -453,9 +435,6 @@ namespace Umbraco.Core.Models //fixme - need to reset change tracking bits - //need to manually clone this since it's not settable - clonedContent.ContentType = ContentType; - //if culture infos exist then deal with event bindings if (clonedContent._publishInfos != null) { diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index 50de59931c..fbb68194b7 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -4,6 +4,7 @@ using System.Collections.Specialized; using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; +using Umbraco.Core.Composing; using Umbraco.Core.Exceptions; using Umbraco.Core.Models.Entities; @@ -14,21 +15,30 @@ namespace Umbraco.Core.Models /// [Serializable] [DataContract(IsReference = true)] - [DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")] + [DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentType.Alias}")] public abstract class ContentBase : TreeEntityBase, IContentBase { - private int _contentTypeId; - protected IContentTypeComposition ContentTypeBase; private int _writerId; private PropertyCollection _properties; private ContentCultureInfosCollection _cultureInfos; + internal IReadOnlyList AllPropertyTypes { get; } #region Used for change tracking private (HashSet addedCultures, HashSet removedCultures, HashSet updatedCultures) _currentCultureChanges; private (HashSet addedCultures, HashSet removedCultures, HashSet updatedCultures) _previousCultureChanges; + public static class ChangeTrackingPrefix + { + public const string UpdatedCulture = "_updatedCulture_"; + public const string ChangedCulture = "_changedCulture_"; + public const string PublishedCulture = "_publishedCulture_"; + public const string UnpublishedCulture = "_unpublishedCulture_"; + public const string AddedCulture = "_addedCulture_"; + public const string RemovedCulture = "_removedCulture_"; + } + #endregion /// @@ -53,7 +63,7 @@ namespace Umbraco.Core.Models private ContentBase(string name, IContentTypeComposition contentType, PropertyCollection properties, string culture = null) { - ContentTypeBase = contentType ?? throw new ArgumentNullException(nameof(contentType)); + ContentType = contentType?.ToSimple() ?? throw new ArgumentNullException(nameof(contentType)); // initially, all new instances have Id = 0; // no identity @@ -63,7 +73,21 @@ namespace Umbraco.Core.Models _contentTypeId = contentType.Id; _properties = properties ?? throw new ArgumentNullException(nameof(properties)); - _properties.EnsurePropertyTypes(PropertyTypes); + _properties.EnsurePropertyTypes(contentType.CompositionPropertyTypes); + + //track all property types on this content type, these can never change during the lifetime of this single instance + //there is no real extra memory overhead of doing this since these property types are already cached on this object via the + //properties already. + AllPropertyTypes = new List(contentType.CompositionPropertyTypes); + } + + [IgnoreDataMember] + public ISimpleContentType ContentType { get; private set; } + + internal void ChangeContentType(ISimpleContentType contentType) + { + ContentType = contentType; + ContentTypeId = contentType.Id; } protected void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e) @@ -71,8 +95,6 @@ namespace Umbraco.Core.Models OnPropertyChanged(nameof(Properties)); } - - /// /// Id of the user who wrote/updated this entity /// @@ -96,13 +118,13 @@ namespace Umbraco.Core.Models { //There will be cases where this has not been updated to reflect the true content type ID. //This will occur when inserting new content. - if (_contentTypeId == 0 && ContentTypeBase != null && ContentTypeBase.HasIdentity) + if (_contentTypeId == 0 && ContentType != null) { - _contentTypeId = ContentTypeBase.Id; + _contentTypeId = ContentType.Id; } return _contentTypeId; } - protected set => SetPropertyValueAndDetectChanges(value, ref _contentTypeId, nameof(ContentTypeId)); + private set => SetPropertyValueAndDetectChanges(value, ref _contentTypeId, nameof(ContentTypeId)); } /// @@ -124,20 +146,6 @@ namespace Umbraco.Core.Models } } - /// - /// Gets the enumeration of property groups for the entity. - /// TODO: remove this proxy method - /// - [IgnoreDataMember] - public IEnumerable PropertyGroups => ContentTypeBase.CompositionPropertyGroups; - - /// - /// Gets the numeration of property types for the entity. - /// TODO: remove this proxy method - /// - [IgnoreDataMember] - public IEnumerable PropertyTypes => ContentTypeBase.CompositionPropertyTypes; - #region Cultures // notes - common rules @@ -178,7 +186,7 @@ namespace Umbraco.Core.Models public string GetCultureName(string culture) { if (culture.IsNullOrWhiteSpace()) return Name; - if (!ContentTypeBase.VariesByCulture()) return null; + if (!ContentType.VariesByCulture()) return null; if (_cultureInfos == null) return null; return _cultureInfos.TryGetValue(culture, out var infos) ? infos.Name : null; } @@ -187,7 +195,7 @@ namespace Umbraco.Core.Models public DateTime? GetUpdateDate(string culture) { if (culture.IsNullOrWhiteSpace()) return null; - if (!ContentTypeBase.VariesByCulture()) return null; + if (!ContentType.VariesByCulture()) return null; if (_cultureInfos == null) return null; return _cultureInfos.TryGetValue(culture, out var infos) ? infos.Date : (DateTime?)null; } @@ -195,7 +203,7 @@ namespace Umbraco.Core.Models /// public void SetCultureName(string name, string culture) { - if (ContentTypeBase.VariesByCulture()) // set on variant content type + if (ContentType.VariesByCulture()) // set on variant content type { if (culture.IsNullOrWhiteSpace()) // invariant is ok { @@ -299,21 +307,10 @@ namespace Umbraco.Core.Models /// public void SetValue(string propertyTypeAlias, object value, string culture = null, string segment = null) { - if (Properties.Contains(propertyTypeAlias)) - { - Properties[propertyTypeAlias].SetValue(value, culture, segment); - //bump the culture to be flagged for updating - this.TouchCulture(culture); - return; - } - - var propertyType = PropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); - if (propertyType == null) + if (!Properties.TryGetValue(propertyTypeAlias, out var property)) throw new InvalidOperationException($"No PropertyType exists with the supplied alias \"{propertyTypeAlias}\"."); - var property = propertyType.CreateProperty(); property.SetValue(value, culture, segment); - Properties.Add(property); //bump the culture to be flagged for updating this.TouchCulture(culture); @@ -402,19 +399,19 @@ namespace Umbraco.Core.Models return true; //Special check here since we want to check if the request is for changed cultures - if (propertyName.StartsWith("_addedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.AddedCulture)) { - var culture = propertyName.TrimStart("_addedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.AddedCulture); return _currentCultureChanges.addedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_removedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.RemovedCulture)) { - var culture = propertyName.TrimStart("_removedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.RemovedCulture); return _currentCultureChanges.removedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_updatedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.UpdatedCulture)) { - var culture = propertyName.TrimStart("_updatedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.UpdatedCulture); return _currentCultureChanges.updatedCultures?.Contains(culture) ?? false; } @@ -429,19 +426,19 @@ namespace Umbraco.Core.Models return true; //Special check here since we want to check if the request is for changed cultures - if (propertyName.StartsWith("_addedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.AddedCulture)) { - var culture = propertyName.TrimStart("_addedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.AddedCulture); return _previousCultureChanges.addedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_removedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.RemovedCulture)) { - var culture = propertyName.TrimStart("_removedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.RemovedCulture); return _previousCultureChanges.removedCultures?.Contains(culture) ?? false; } - if (propertyName.StartsWith("_updatedCulture_")) + if (propertyName.StartsWith(ChangeTrackingPrefix.UpdatedCulture)) { - var culture = propertyName.TrimStart("_updatedCulture_"); + var culture = propertyName.TrimStart(ChangeTrackingPrefix.UpdatedCulture); return _previousCultureChanges.updatedCultures?.Contains(culture) ?? false; } @@ -478,6 +475,9 @@ namespace Umbraco.Core.Models var clonedContent = (ContentBase)clone; + //need to manually clone this since it's not settable + clonedContent.ContentType = ContentType; + //if culture infos exist then deal with event bindings if (clonedContent._cultureInfos != null) { diff --git a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs index ca9bf57902..27678c047c 100644 --- a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs +++ b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Models return Array.Empty(); var culturesUnpublishing = content.CultureInfos.Values - .Where(x => content.IsPropertyDirty("_unpublishedCulture_" + x.Culture)) + .Where(x => content.IsPropertyDirty(ContentBase.ChangeTrackingPrefix.UnpublishedCulture + x.Culture)) .Select(x => x.Culture); return culturesUnpublishing.ToList(); @@ -88,8 +88,7 @@ namespace Umbraco.Core.Models { content.CultureInfos.Clear(); content.CultureInfos = null; - } - + } if (culture == null || culture == "*") content.Name = other.Name; @@ -158,8 +157,9 @@ namespace Umbraco.Core.Models if (!content.PublishCultureInfos.TryGetValue(culture, out var publishInfos)) continue; + // if it's not dirty, it means it hasn't changed so there's nothing to adjust if (!publishInfos.IsDirty()) - continue; //if it's not dirty, it means it hasn't changed so there's nothing to adjust + continue; content.PublishCultureInfos.AddOrUpdate(culture, publishInfos.Name, date); diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs index 61fabe6fb0..63c758611a 100644 --- a/src/Umbraco.Core/Models/ContentType.cs +++ b/src/Umbraco.Core/Models/ContentType.cs @@ -41,6 +41,9 @@ namespace Umbraco.Core.Models _allowedTemplates = new List(); } + /// + public override ISimpleContentType ToSimple() => new SimpleContentType(this); + /// public override bool IsPublishing => IsPublishingConst; @@ -97,8 +100,8 @@ namespace Umbraco.Core.Models /// True if AllowedTemplates contains the templateId else False public bool IsAllowedTemplate(int templateId) { - return AllowedTemplates == null - ? false + return AllowedTemplates == null + ? false : AllowedTemplates.Any(t => t.Id == templateId); } diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 2aa114a88f..320f667e07 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -67,6 +67,8 @@ namespace Umbraco.Core.Models _variations = ContentVariation.Nothing; } + public abstract ISimpleContentType ToSimple(); + /// /// Gets a value indicating whether the content type is publishing. /// diff --git a/src/Umbraco.Core/Models/Entities/TreeEntityPath.cs b/src/Umbraco.Core/Models/Entities/TreeEntityPath.cs index 54142a7527..adbb0d9a39 100644 --- a/src/Umbraco.Core/Models/Entities/TreeEntityPath.cs +++ b/src/Umbraco.Core/Models/Entities/TreeEntityPath.cs @@ -14,5 +14,14 @@ /// Gets or sets the path of the entity. /// public string Path { get; set; } + + /// + /// Proxy of the Id + /// + public int NodeId + { + get => Id; + set => Id = value; + } } } diff --git a/src/Umbraco.Core/Models/IContent.cs b/src/Umbraco.Core/Models/IContent.cs index e953bef1eb..6990a7f7da 100644 --- a/src/Umbraco.Core/Models/IContent.cs +++ b/src/Umbraco.Core/Models/IContent.cs @@ -66,11 +66,6 @@ namespace Umbraco.Core.Models /// DateTime? PublishDate { get; set; } - /// - /// Gets the content type of this content. - /// - ISimpleContentType ContentType { get; } - /// /// Gets a value indicating whether a culture is published. /// diff --git a/src/Umbraco.Core/Models/IContentBase.cs b/src/Umbraco.Core/Models/IContentBase.cs index 1ebbfa1d49..0f660181fb 100644 --- a/src/Umbraco.Core/Models/IContentBase.cs +++ b/src/Umbraco.Core/Models/IContentBase.cs @@ -18,6 +18,11 @@ namespace Umbraco.Core.Models /// int ContentTypeId { get; } + /// + /// Gets the content type of this content. + /// + ISimpleContentType ContentType { get; } + /// /// Gets the identifier of the writer. /// @@ -58,7 +63,7 @@ namespace Umbraco.Core.Models /// culture name, which must be get or set via the property. /// ContentCultureInfosCollection CultureInfos { get; set; } - + /// /// Gets the available cultures. /// @@ -95,18 +100,6 @@ namespace Umbraco.Core.Models /// Properties are loaded as part of the Content object graph PropertyCollection Properties { get; set; } - /// - /// List of PropertyGroups available on this Content object - /// - /// PropertyGroups are kind of lazy loaded as part of the object graph - IEnumerable PropertyGroups { get; } - - /// - /// List of PropertyTypes available on this Content object - /// - /// PropertyTypes are kind of lazy loaded as part of the object graph - IEnumerable PropertyTypes { get; } - /// /// Gets a value indicating whether the content entity has a property with the supplied alias. /// diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index aea84d9767..215c8532c1 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -159,5 +159,10 @@ namespace Umbraco.Core.Models /// Name of the PropertyGroup to move the PropertyType to /// bool MovePropertyType(string propertyTypeAlias, string propertyGroupName); + + /// + /// Gets an corresponding to this content type. + /// + ISimpleContentType ToSimple(); } } diff --git a/src/Umbraco.Core/Models/IMedia.cs b/src/Umbraco.Core/Models/IMedia.cs index cfb79bbf2c..75e94d66e7 100644 --- a/src/Umbraco.Core/Models/IMedia.cs +++ b/src/Umbraco.Core/Models/IMedia.cs @@ -1,27 +1,5 @@ -using Umbraco.Core.Persistence.Mappers; - -namespace Umbraco.Core.Models +namespace Umbraco.Core.Models { public interface IMedia : IContentBase - { - /// - /// Gets the ContentType used by this Media object - /// - IMediaType ContentType { get; } - - /// - /// Changes the for the current content object - /// - /// New ContentType for this content - /// Leaves PropertyTypes intact after change - void ChangeContentType(IMediaType contentType); - - /// - /// Changes the for the current content object and removes PropertyTypes, - /// which are not part of the new ContentType. - /// - /// New ContentType for this content - /// Boolean indicating whether to clear PropertyTypes upon change - void ChangeContentType(IMediaType contentType, bool clearProperties); - } + { } } diff --git a/src/Umbraco.Core/Models/IMember.cs b/src/Umbraco.Core/Models/IMember.cs index 15826f03f3..199d53b174 100644 --- a/src/Umbraco.Core/Models/IMember.cs +++ b/src/Umbraco.Core/Models/IMember.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; namespace Umbraco.Core.Models @@ -11,10 +9,5 @@ namespace Umbraco.Core.Models /// String alias of the default ContentType /// string ContentTypeAlias { get; } - - /// - /// Gets the ContentType used by this content object - /// - IMemberType ContentType { get; } } } diff --git a/src/Umbraco.Core/Models/ISimpleContentType.cs b/src/Umbraco.Core/Models/ISimpleContentType.cs index 8c9413f934..740db8e73f 100644 --- a/src/Umbraco.Core/Models/ISimpleContentType.cs +++ b/src/Umbraco.Core/Models/ISimpleContentType.cs @@ -1,20 +1,20 @@ -namespace Umbraco.Core.Models +using Umbraco.Core.Models.Entities; + +namespace Umbraco.Core.Models { /// /// Represents a simplified view of a content type. /// - public interface ISimpleContentType + public interface ISimpleContentType : IUmbracoEntity { + new int Id { get; } + new string Name { get; } + /// /// Gets the alias of the content type. /// string Alias { get; } - /// - /// Gets the identifier of the content type. - /// - int Id { get; } - /// /// Gets the default template of the content type. /// @@ -35,11 +35,6 @@ /// bool IsContainer { get; } - /// - /// Gets the name of the content type. - /// - string Name { get; } - /// /// Gets a value indicating whether content of that type can be created at the root of the tree. /// diff --git a/src/Umbraco.Core/Models/Media.cs b/src/Umbraco.Core/Models/Media.cs index a0f3aa35de..002611c09c 100644 --- a/src/Umbraco.Core/Models/Media.cs +++ b/src/Umbraco.Core/Models/Media.cs @@ -10,8 +10,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class Media : ContentBase, IMedia { - private IMediaType _contentType; - /// /// Constructor for creating a Media object /// @@ -31,9 +29,7 @@ namespace Umbraco.Core.Models /// Collection of properties public Media(string name, IMedia parent, IMediaType contentType, PropertyCollection properties) : base(name, parent, contentType, properties) - { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - } + { } /// /// Constructor for creating a Media object @@ -54,30 +50,16 @@ namespace Umbraco.Core.Models /// Collection of properties public Media(string name, int parentId, IMediaType contentType, PropertyCollection properties) : base(name, parentId, contentType, properties) - { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - } - - /// - /// Gets the ContentType used by this Media object - /// - [IgnoreDataMember] - public IMediaType ContentType => _contentType; + { } /// /// Changes the for the current Media object /// /// New MediaType for this Media /// Leaves PropertyTypes intact after change - public void ChangeContentType(IMediaType contentType) + internal void ChangeContentType(IMediaType contentType) { - ContentTypeId = contentType.Id; - _contentType = contentType; - ContentTypeBase = contentType; - Properties.EnsurePropertyTypes(PropertyTypes); - - Properties.CollectionChanged -= PropertiesChanged; // be sure not to double add - Properties.CollectionChanged += PropertiesChanged; + ChangeContentType(contentType, false); } /// @@ -86,33 +68,17 @@ namespace Umbraco.Core.Models /// /// New MediaType for this Media /// Boolean indicating whether to clear PropertyTypes upon change - public void ChangeContentType(IMediaType contentType, bool clearProperties) + internal void ChangeContentType(IMediaType contentType, bool clearProperties) { + ChangeContentType(new SimpleContentType(contentType)); + if (clearProperties) - { - ContentTypeId = contentType.Id; - _contentType = contentType; - ContentTypeBase = contentType; - Properties.EnsureCleanPropertyTypes(PropertyTypes); + Properties.EnsureCleanPropertyTypes(contentType.CompositionPropertyTypes); + else + Properties.EnsurePropertyTypes(contentType.CompositionPropertyTypes); - Properties.CollectionChanged -= PropertiesChanged; // be sure not to double add - Properties.CollectionChanged += PropertiesChanged; - return; - } - - ChangeContentType(contentType); - } - - /// - /// Changes the Trashed state of the content object - /// - /// Boolean indicating whether content is trashed (true) or not trashed (false) - /// - public void ChangeTrashedState(bool isTrashed, int parentId = -20) - { - Trashed = isTrashed; - //The Media Recycle Bin Id is -21 so we correct that here - ParentId = parentId == -20 ? -21 : parentId; + Properties.CollectionChanged -= PropertiesChanged; // be sure not to double add + Properties.CollectionChanged += PropertiesChanged; } } } diff --git a/src/Umbraco.Core/Models/MediaExtensions.cs b/src/Umbraco.Core/Models/MediaExtensions.cs index e281aaf5ab..1166698adb 100644 --- a/src/Umbraco.Core/Models/MediaExtensions.cs +++ b/src/Umbraco.Core/Models/MediaExtensions.cs @@ -15,20 +15,17 @@ namespace Umbraco.Core.Models /// public static string GetUrl(this IMedia media, string propertyAlias, ILogger logger) { - var propertyType = media.PropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyAlias)); - if (propertyType == null) return string.Empty; - - var val = media.Properties[propertyType]; - if (val == null) return string.Empty; + if (!media.Properties.TryGetValue(propertyAlias, out var property)) + return string.Empty; // TODO: would need to be adjusted to variations, when media become variants - var jsonString = val.GetValue() as string; - if (jsonString == null) return string.Empty; + if (!(property.GetValue() is string jsonString)) + return string.Empty; - if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.UploadField) + if (property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.UploadField) return jsonString; - if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.ImageCropper) + if (property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.ImageCropper) { if (jsonString.DetectIsJson() == false) return jsonString; diff --git a/src/Umbraco.Core/Models/MediaType.cs b/src/Umbraco.Core/Models/MediaType.cs index 83e1acfbc0..f7598b4965 100644 --- a/src/Umbraco.Core/Models/MediaType.cs +++ b/src/Umbraco.Core/Models/MediaType.cs @@ -41,6 +41,9 @@ namespace Umbraco.Core.Models { } + /// + public override ISimpleContentType ToSimple() => new SimpleContentType(this); + /// public override bool IsPublishing => IsPublishingConst; diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index 78d1cfafd5..0e91065d56 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -15,8 +15,6 @@ namespace Umbraco.Core.Models public class Member : ContentBase, IMember { private IDictionary _additionalData; - private IMemberType _contentType; - private readonly string _contentTypeAlias; private string _username; private string _email; private string _rawPasswordValue; @@ -29,8 +27,6 @@ namespace Umbraco.Core.Models public Member(IMemberType contentType) : base("", -1, contentType, new PropertyCollection()) { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - _contentTypeAlias = contentType.Alias; IsApproved = true; //this cannot be null but can be empty @@ -49,8 +45,6 @@ namespace Umbraco.Core.Models { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - _contentTypeAlias = contentType.Alias; IsApproved = true; //this cannot be null but can be empty @@ -73,8 +67,6 @@ namespace Umbraco.Core.Models if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name)); if (string.IsNullOrWhiteSpace(username)) throw new ArgumentNullOrEmptyException(nameof(username)); - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - _contentTypeAlias = contentType.Alias; _email = email; _username = username; IsApproved = isApproved; @@ -96,9 +88,6 @@ namespace Umbraco.Core.Models public Member(string name, string email, string username, string rawPasswordValue, IMemberType contentType) : base(name, -1, contentType, new PropertyCollection()) { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - _contentTypeAlias = contentType.Alias; - _email = email; _username = username; _rawPasswordValue = rawPasswordValue; @@ -119,8 +108,6 @@ namespace Umbraco.Core.Models public Member(string name, string email, string username, string rawPasswordValue, IMemberType contentType, bool isApproved) : base(name, -1, contentType, new PropertyCollection()) { - _contentType = contentType ?? throw new ArgumentNullException(nameof(contentType)); - _contentTypeAlias = contentType.Alias; _email = email; _username = username; _rawPasswordValue = rawPasswordValue; @@ -473,7 +460,7 @@ namespace Umbraco.Core.Models /// String alias of the default ContentType /// [DataMember] - public virtual string ContentTypeAlias => _contentTypeAlias; + public virtual string ContentTypeAlias => ContentType.Alias; /// /// User key from the Provider. @@ -504,12 +491,6 @@ namespace Umbraco.Core.Models ProviderUserKey = Key; } - /// - /// Gets the ContentType used by this content object - /// - [IgnoreDataMember] - public IMemberType ContentType => _contentType; - /* Internal experiment - only used for mapping queries. * Adding these to have first level properties instead of the Properties collection. */ @@ -575,17 +556,6 @@ namespace Umbraco.Core.Models return true; } - protected override void PerformDeepClone(object clone) - { - base.PerformDeepClone(clone); - - var clonedEntity = (Member)clone; - - //need to manually clone this since it's not settable - clonedEntity._contentType = (IMemberType)ContentType.DeepClone(); - - } - /// [DataMember] [DoNotClone] diff --git a/src/Umbraco.Core/Models/MemberType.cs b/src/Umbraco.Core/Models/MemberType.cs index a6c1518446..e85aa0e15e 100644 --- a/src/Umbraco.Core/Models/MemberType.cs +++ b/src/Umbraco.Core/Models/MemberType.cs @@ -31,6 +31,9 @@ namespace Umbraco.Core.Models MemberTypePropertyTypes = new Dictionary(); } + /// + public override ISimpleContentType ToSimple() => new SimpleContentType(this); + /// public override bool IsPublishing => IsPublishingConst; diff --git a/src/Umbraco.Core/Models/PropertyCollection.cs b/src/Umbraco.Core/Models/PropertyCollection.cs index 5e71fe9f65..977600a2f7 100644 --- a/src/Umbraco.Core/Models/PropertyCollection.cs +++ b/src/Umbraco.Core/Models/PropertyCollection.cs @@ -93,7 +93,7 @@ namespace Umbraco.Core.Models } /// - /// Adds a property. + /// Adds or updates a property. /// internal new void Add(Property property) { diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs index 8a44a7a9b4..2ca3593b55 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs @@ -87,8 +87,20 @@ namespace Umbraco.Core.Models.PublishedContent { lock (_publishedDataTypesLocker) { - var dataTypes = _dataTypeService.GetAll(ids); - _publishedDataTypes = dataTypes.ToDictionary(x => x.Id, CreatePublishedDataType); + if (_publishedDataTypes == null) + { + var dataTypes = _dataTypeService.GetAll(); + _publishedDataTypes = dataTypes.ToDictionary(x => x.Id, CreatePublishedDataType); + } + else + { + foreach (var id in ids) + _publishedDataTypes.Remove(id); + + var dataTypes = _dataTypeService.GetAll(ids); + foreach (var dataType in dataTypes) + _publishedDataTypes[dataType.Id] = CreatePublishedDataType(dataType); + } } } diff --git a/src/Umbraco.Core/Models/SimpleContentType.cs b/src/Umbraco.Core/Models/SimpleContentType.cs index be1f87fcda..5c81017ec8 100644 --- a/src/Umbraco.Core/Models/SimpleContentType.cs +++ b/src/Umbraco.Core/Models/SimpleContentType.cs @@ -1,4 +1,8 @@ -namespace Umbraco.Core.Models +using System; +using System.Collections.Generic; +using Umbraco.Core.Models.Entities; + +namespace Umbraco.Core.Models { /// /// Implements . @@ -9,14 +13,34 @@ /// Initializes a new instance of the class. /// public SimpleContentType(IContentType contentType) + : this((IContentTypeBase)contentType) { + DefaultTemplate = contentType.DefaultTemplate; + } + + /// + /// Initializes a new instance of the class. + /// + public SimpleContentType(IMediaType mediaType) + : this((IContentTypeBase)mediaType) + { } + + /// + /// Initializes a new instance of the class. + /// + public SimpleContentType(IMemberType memberType) + : this((IContentTypeBase)memberType) + { } + + private SimpleContentType(IContentTypeBase contentType) + { + if (contentType == null) throw new ArgumentNullException(nameof(contentType)); + Id = contentType.Id; Alias = contentType.Alias; - DefaultTemplate = contentType.DefaultTemplate; Variations = contentType.Variations; Icon = contentType.Icon; IsContainer = contentType.IsContainer; - Icon = contentType.Icon; Name = contentType.Name; AllowedAsRoot = contentType.AllowedAsRoot; IsElement = contentType.IsElement; @@ -25,8 +49,7 @@ /// public string Alias { get; } - /// - public int Id { get; } + public int Id { get; } /// public ITemplate DefaultTemplate { get; } @@ -39,8 +62,7 @@ /// public bool IsContainer { get; } - - /// + public string Name { get; } /// @@ -80,5 +102,33 @@ return ((Alias != null ? Alias.GetHashCode() : 0) * 397) ^ Id; } } + + // we have to have all this, because we're an IUmbracoEntity, because that is + // required by the query expression visitor / SimpleContentTypeMapper + + string ITreeEntity.Name { get => this.Name; set => throw new NotImplementedException(); } + int IEntity.Id { get => this.Id; set => throw new NotImplementedException(); } + bool IEntity.HasIdentity => this.Id != default; + int ITreeEntity.CreatorId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + int ITreeEntity.ParentId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + int ITreeEntity.Level { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + string ITreeEntity.Path { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + int ITreeEntity.SortOrder { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + bool ITreeEntity.Trashed => throw new NotImplementedException(); + Guid IEntity.Key { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime IEntity.CreateDate { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime IEntity.UpdateDate { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime? IEntity.DeleteDate { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + void ITreeEntity.SetParent(ITreeEntity parent) => throw new NotImplementedException(); + object IDeepCloneable.DeepClone() => throw new NotImplementedException(); + bool IRememberBeingDirty.WasDirty() => throw new NotImplementedException(); + bool IRememberBeingDirty.WasPropertyDirty(string propertyName) => throw new NotImplementedException(); + void IRememberBeingDirty.ResetWereDirtyProperties() => throw new NotImplementedException(); + void IRememberBeingDirty.ResetDirtyProperties(bool rememberDirty) => throw new NotImplementedException(); + IEnumerable IRememberBeingDirty.GetWereDirtyProperties() => throw new NotImplementedException(); + bool ICanBeDirty.IsDirty() => throw new NotImplementedException(); + bool ICanBeDirty.IsPropertyDirty(string propName) => throw new NotImplementedException(); + IEnumerable ICanBeDirty.GetDirtyProperties() => throw new NotImplementedException(); + void ICanBeDirty.ResetDirtyProperties() => throw new NotImplementedException(); } } diff --git a/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs b/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs index 20586cb6f4..835f76f9f9 100644 --- a/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs +++ b/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs @@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence do { c = unwrapped; - if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.InnerConnection; + if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.WrappedConnection; if (unwrapped is RetryDbConnection retrying) unwrapped = retrying.Inner; } while (c != unwrapped); diff --git a/src/Umbraco.Core/Persistence/Mappers/MapperCollectionBuilder.cs b/src/Umbraco.Core/Persistence/Mappers/MapperCollectionBuilder.cs index 80819933f5..e20f7c1911 100644 --- a/src/Umbraco.Core/Persistence/Mappers/MapperCollectionBuilder.cs +++ b/src/Umbraco.Core/Persistence/Mappers/MapperCollectionBuilder.cs @@ -25,6 +25,7 @@ namespace Umbraco.Core.Persistence.Mappers Add(); Add(); Add(); + Add(); Add(); Add(); Add(); diff --git a/src/Umbraco.Core/Persistence/Mappers/SimpleContentTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/SimpleContentTypeMapper.cs new file mode 100644 index 0000000000..3ad975defb --- /dev/null +++ b/src/Umbraco.Core/Persistence/Mappers/SimpleContentTypeMapper.cs @@ -0,0 +1,38 @@ +using System.Collections.Concurrent; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Persistence.Mappers +{ + [MapperFor(typeof(ISimpleContentType))] + [MapperFor(typeof(SimpleContentType))] + public sealed class SimpleContentTypeMapper : BaseMapper + { + private static readonly ConcurrentDictionary PropertyInfoCacheInstance = new ConcurrentDictionary(); + + internal override ConcurrentDictionary PropertyInfoCache => PropertyInfoCacheInstance; + + protected override void BuildMap() + { + if (PropertyInfoCache.IsEmpty == false) return; + + CacheMap(src => src.Id, dto => dto.NodeId); + CacheMap(src => src.CreateDate, dto => dto.CreateDate); + CacheMap(src => src.Level, dto => dto.Level); + CacheMap(src => src.ParentId, dto => dto.ParentId); + CacheMap(src => src.Path, dto => dto.Path); + CacheMap(src => src.SortOrder, dto => dto.SortOrder); + CacheMap(src => src.Name, dto => dto.Text); + CacheMap(src => src.Trashed, dto => dto.Trashed); + CacheMap(src => src.Key, dto => dto.UniqueId); + CacheMap(src => src.CreatorId, dto => dto.UserId); + CacheMap(src => src.Alias, dto => dto.Alias); + CacheMap(src => src.AllowedAsRoot, dto => dto.AllowAtRoot); + CacheMap(src => src.Description, dto => dto.Description); + CacheMap(src => src.Icon, dto => dto.Icon); + CacheMap(src => src.IsContainer, dto => dto.IsContainer); + CacheMap(src => src.IsElement, dto => dto.IsElement); + CacheMap(src => src.Thumbnail, dto => dto.Thumbnail); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs index 248f91284f..bb4c60a0df 100644 --- a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs @@ -148,7 +148,7 @@ namespace Umbraco.Core.Persistence where TConnection : class, IDbConnection { var profiled = connection as ProfiledDbConnection; - return profiled == null ? connection as TConnection : profiled.InnerConnection as TConnection; + return profiled == null ? connection as TConnection : profiled.WrappedConnection as TConnection; } /// diff --git a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs index a353f01f5b..bf26523d9e 100644 --- a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs +++ b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionVisitor.cs @@ -60,7 +60,7 @@ namespace Umbraco.Core.Persistence.Querying if (m.Expression != null && m.Expression.Type != typeof(T) - && TypeHelper.IsTypeAssignableFrom(m.Expression.Type) + && TypeHelper.IsTypeAssignableFrom(m.Expression.Type) //TODO: Could this just be `IEntity` ? why does it need to be IUmbracoEntity, we aren't even using the reference to that below && EndsWithConstant(m) == false) { //if this is the case, it means we have a sub expression / nested property access, such as: x.ContentType.Alias == "Test"; diff --git a/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs index d49c92f1bf..fc5382499f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs @@ -7,8 +7,6 @@ namespace Umbraco.Core.Persistence.Repositories { public interface IDocumentRepository : IContentRepository, IReadRepository { - - /// /// Clears the publishing schedule for all entries having an a date before (lower than, or equal to) a specified date. /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 04af52047c..d8e6fd2c0e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -120,15 +119,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement break; case QueryType.Single: case QueryType.Many: + // R# may flag this ambiguous and red-squiggle it, but it is not + sql = sql.Select(r => + r.Select(documentDto => documentDto.ContentDto, r1 => + r1.Select(contentDto => contentDto.NodeDto)) + .Select(documentDto => documentDto.DocumentVersionDto, r1 => + r1.Select(documentVersionDto => documentVersionDto.ContentVersionDto)) + .Select(documentDto => documentDto.PublishedVersionDto, "pdv", r1 => + r1.Select(documentVersionDto => documentVersionDto.ContentVersionDto, "pcv"))) - //we've put this in a local function so that the below sql.Select statement doesn't have a problem - //thinking that the call is ambiguous - NPocoSqlExtensions.SqlRef SelectStatement(NPocoSqlExtensions.SqlRef r) => - r.Select(documentDto => documentDto.ContentDto, r1 => r1.Select(contentDto => contentDto.NodeDto)) - .Select(documentDto => documentDto.DocumentVersionDto, r1 => r1.Select(documentVersionDto => documentVersionDto.ContentVersionDto)) - .Select(documentDto => documentDto.PublishedVersionDto, "pdv", r1 => r1.Select(documentVersionDto => documentVersionDto.ContentVersionDto, "pcv")); - - sql = sql.Select(SelectStatement) // select the variant name, coalesce to the invariant name, as "variantName" .AndSelect(VariantNameSqlExpression + " AS variantName"); break; @@ -954,8 +953,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #endregion - - protected override string ApplySystemOrdering(ref Sql sql, Ordering ordering) { // note: 'updater' is the user who created the latest draft version, @@ -1187,17 +1184,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return result; } - private void SetVariations(Content content, IDictionary> contentVariations, IDictionary> documentVariations) { if (contentVariations.TryGetValue(content.VersionId, out var contentVariation)) foreach (var v in contentVariation) content.SetCultureInfo(v.Culture, v.Name, v.Date); + if (content.PublishedVersionId > 0 && contentVariations.TryGetValue(content.PublishedVersionId, out contentVariation)) { foreach (var v in contentVariation) content.SetPublishInfo(v.Culture, v.Name, v.Date); } + if (documentVariations.TryGetValue(content.Id, out var documentVariation)) content.SetCultureEdited(documentVariation.Where(x => x.Edited).Select(x => x.Culture)); } diff --git a/src/Umbraco.Core/Services/ContentServiceExtensions.cs b/src/Umbraco.Core/Services/ContentServiceExtensions.cs index 03a790d4b8..4d673fc902 100644 --- a/src/Umbraco.Core/Services/ContentServiceExtensions.cs +++ b/src/Umbraco.Core/Services/ContentServiceExtensions.cs @@ -34,7 +34,7 @@ namespace Umbraco.Core.Services /// /// /// - public static IContent CreateContent(this IContentService contentService, string name, Udi parentId, string mediaTypeAlias, int userId = 0) + public static IContent CreateContent(this IContentService contentService, string name, Udi parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { var guidUdi = parentId as GuidUdi; if (guidUdi == null) diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 600921ee78..b2fce8f3e6 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -32,27 +32,27 @@ namespace Umbraco.Core.Services /// /// Saves a blueprint. /// - void SaveBlueprint(IContent content, int userId = 0); + void SaveBlueprint(IContent content, int userId = Constants.Security.SuperUserId); /// /// Deletes a blueprint. /// - void DeleteBlueprint(IContent content, int userId = 0); + void DeleteBlueprint(IContent content, int userId = Constants.Security.SuperUserId); /// /// Creates a new content item from a blueprint. /// - IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0); + IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = Constants.Security.SuperUserId); /// /// Deletes blueprints for a content type. /// - void DeleteBlueprintsOfType(int contentTypeId, int userId = 0); + void DeleteBlueprintsOfType(int contentTypeId, int userId = Constants.Security.SuperUserId); /// /// Deletes blueprints for content types. /// - void DeleteBlueprintsOfTypes(IEnumerable contentTypeIds, int userId = 0); + void DeleteBlueprintsOfTypes(IEnumerable contentTypeIds, int userId = Constants.Security.SuperUserId); #endregion @@ -237,13 +237,13 @@ namespace Umbraco.Core.Services /// /// Saves a document. /// - OperationResult Save(IContent content, int userId = 0, bool raiseEvents = true); + OperationResult Save(IContent content, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Saves documents. /// // TODO: why only 1 result not 1 per content?! - OperationResult Save(IEnumerable contents, int userId = 0, bool raiseEvents = true); + OperationResult Save(IEnumerable contents, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Deletes a document. @@ -252,7 +252,7 @@ namespace Umbraco.Core.Services /// This method will also delete associated media files, child content and possibly associated domains. /// This method entirely clears the content from the database. /// - OperationResult Delete(IContent content, int userId = 0); + OperationResult Delete(IContent content, int userId = Constants.Security.SuperUserId); /// /// Deletes all documents of a given document type. @@ -261,7 +261,7 @@ namespace Umbraco.Core.Services /// All non-deleted descendants of the deleted documents are moved to the recycle bin. /// This operation is potentially dangerous and expensive. /// - void DeleteOfType(int documentTypeId, int userId = 0); + void DeleteOfType(int documentTypeId, int userId = Constants.Security.SuperUserId); /// /// Deletes all documents of given document types. @@ -270,17 +270,17 @@ namespace Umbraco.Core.Services /// All non-deleted descendants of the deleted documents are moved to the recycle bin. /// This operation is potentially dangerous and expensive. /// - void DeleteOfTypes(IEnumerable contentTypeIds, int userId = 0); + void DeleteOfTypes(IEnumerable contentTypeIds, int userId = Constants.Security.SuperUserId); /// /// Deletes versions of a document prior to a given date. /// - void DeleteVersions(int id, DateTime date, int userId = 0); + void DeleteVersions(int id, DateTime date, int userId = Constants.Security.SuperUserId); /// /// Deletes a version of a document. /// - void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = 0); + void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = Constants.Security.SuperUserId); #endregion @@ -289,7 +289,7 @@ namespace Umbraco.Core.Services /// /// Moves a document under a new parent. /// - void Move(IContent content, int parentId, int userId = 0); + void Move(IContent content, int parentId, int userId = Constants.Security.SuperUserId); /// /// Copies a document. @@ -297,7 +297,7 @@ namespace Umbraco.Core.Services /// /// Recursively copies all children. /// - IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = 0); + IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = Constants.Security.SuperUserId); /// /// Copies a document. @@ -305,12 +305,12 @@ namespace Umbraco.Core.Services /// /// Optionally recursively copies all children. /// - IContent Copy(IContent content, int parentId, bool relateToOriginal, bool recursive, int userId = 0); + IContent Copy(IContent content, int parentId, bool relateToOriginal, bool recursive, int userId = Constants.Security.SuperUserId); /// /// Moves a document to the recycle bin. /// - OperationResult MoveToRecycleBin(IContent content, int userId = 0); + OperationResult MoveToRecycleBin(IContent content, int userId = Constants.Security.SuperUserId); /// /// Empties the recycle bin. @@ -320,12 +320,12 @@ namespace Umbraco.Core.Services /// /// Sorts documents. /// - OperationResult Sort(IEnumerable items, int userId = 0, bool raiseEvents = true); + OperationResult Sort(IEnumerable items, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Sorts documents. /// - OperationResult Sort(IEnumerable ids, int userId = 0, bool raiseEvents = true); + OperationResult Sort(IEnumerable ids, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); #endregion @@ -341,12 +341,11 @@ namespace Umbraco.Core.Services /// If the content type is variant, then culture can be either '*' or an actual culture, but neither 'null' nor /// 'empty'. If the content type is invariant, then culture can be either '*' or null or empty. /// - /// - /// - /// - /// - /// - PublishResult SaveAndPublish(IContent content, string culture = "*", int userId = 0, bool raiseEvents = true); + /// The document to publish. + /// The culture to publish. + /// The identifier of the user performing the action. + /// A value indicating whether to raise events. + PublishResult SaveAndPublish(IContent content, string culture = "*", int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Saves and publishes a document. @@ -356,12 +355,11 @@ namespace Umbraco.Core.Services /// When a culture is being published, it includes all varying values along with all invariant values. /// The document is *always* saved, even when publishing fails. /// - /// + /// The document to publish. /// The cultures to publish. - /// - /// - /// - PublishResult SaveAndPublish(IContent content, string[] cultures, int userId = 0, bool raiseEvents = true); + /// The identifier of the user performing the action. + /// A value indicating whether to raise events. + PublishResult SaveAndPublish(IContent content, string[] cultures, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Saves and publishes a document branch. @@ -377,7 +375,7 @@ namespace Umbraco.Core.Services /// only those documents that are already published, are republished. When true, all documents are /// published. The root of the branch is always published, regardless of . /// - IEnumerable SaveAndPublishBranch(IContent content, bool force, string culture = "*", int userId = 0); + IEnumerable SaveAndPublishBranch(IContent content, bool force, string culture = "*", int userId = Constants.Security.SuperUserId); /// /// Saves and publishes a document branch. @@ -391,7 +389,7 @@ namespace Umbraco.Core.Services /// only those documents that are already published, are republished. When true, all documents are /// published. The root of the branch is always published, regardless of . /// - IEnumerable SaveAndPublishBranch(IContent content, bool force, string[] cultures, int userId = 0); + IEnumerable SaveAndPublishBranch(IContent content, bool force, string[] cultures, int userId = Constants.Security.SuperUserId); /// /// Saves and publishes a document branch. @@ -416,7 +414,7 @@ namespace Umbraco.Core.Services IEnumerable SaveAndPublishBranch(IContent content, bool force, Func> shouldPublish, Func, bool> publishCultures, - int userId = 0); + int userId = Constants.Security.SuperUserId); /// /// Unpublishes a document. @@ -428,7 +426,7 @@ namespace Umbraco.Core.Services /// If the content type is variant, then culture can be either '*' or an actual culture, but neither null nor /// empty. If the content type is invariant, then culture can be either '*' or null or empty. /// - PublishResult Unpublish(IContent content, string culture = "*", int userId = 0); + PublishResult Unpublish(IContent content, string culture = "*", int userId = Constants.Security.SuperUserId); /// /// Gets a value indicating whether a document is path-publishable. @@ -445,7 +443,7 @@ namespace Umbraco.Core.Services /// /// Saves a document and raises the "sent to publication" events. /// - bool SendToPublication(IContent content, int userId = 0); + bool SendToPublication(IContent content, int userId = Constants.Security.SuperUserId); /// /// Publishes and unpublishes scheduled documents. @@ -480,27 +478,27 @@ namespace Umbraco.Core.Services /// /// Creates a document. /// - IContent Create(string name, Guid parentId, string documentTypeAlias, int userId = 0); + IContent Create(string name, Guid parentId, string documentTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates a document. /// - IContent Create(string name, int parentId, string documentTypeAlias, int userId = 0); + IContent Create(string name, int parentId, string documentTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates a document. /// - IContent Create(string name, IContent parent, string documentTypeAlias, int userId = 0); + IContent Create(string name, IContent parent, string documentTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates and saves a document. /// - IContent CreateAndSave(string name, int parentId, string contentTypeAlias, int userId = 0); + IContent CreateAndSave(string name, int parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates and saves a document. /// - IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = 0); + IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = Constants.Security.SuperUserId); #endregion @@ -516,7 +514,7 @@ namespace Umbraco.Core.Services /// /// When no culture is specified, all cultures are rolled back. /// - OperationResult Rollback(int id, int versionId, string culture = "*", int userId = 0); + OperationResult Rollback(int id, int versionId, string culture = "*", int userId = Constants.Security.SuperUserId); #endregion } diff --git a/src/Umbraco.Core/Services/IContentTypeBaseServiceProvider.cs b/src/Umbraco.Core/Services/IContentTypeBaseServiceProvider.cs index 70327e7baf..d0146ce043 100644 --- a/src/Umbraco.Core/Services/IContentTypeBaseServiceProvider.cs +++ b/src/Umbraco.Core/Services/IContentTypeBaseServiceProvider.cs @@ -18,5 +18,10 @@ namespace Umbraco.Core.Services /// to retrieve the content / media / whatever type as . /// IContentTypeBaseService For(IContentBase contentBase); + + /// + /// Gets the content type of an object. + /// + IContentTypeComposition GetContentTypeOf(IContentBase contentBase); } } diff --git a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs index 8fa77e4836..b86494adb5 100644 --- a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs @@ -47,11 +47,11 @@ namespace Umbraco.Core.Services IEnumerable GetChildren(int id); bool HasChildren(int id); - void Save(TItem item, int userId = 0); - void Save(IEnumerable items, int userId = 0); + void Save(TItem item, int userId = Constants.Security.SuperUserId); + void Save(IEnumerable items, int userId = Constants.Security.SuperUserId); - void Delete(TItem item, int userId = 0); - void Delete(IEnumerable item, int userId = 0); + void Delete(TItem item, int userId = Constants.Security.SuperUserId); + void Delete(IEnumerable item, int userId = Constants.Security.SuperUserId); Attempt ValidateComposition(TItem compo); @@ -63,15 +63,15 @@ namespace Umbraco.Core.Services /// bool HasContainerInPath(string contentPath); - Attempt> CreateContainer(int parentContainerId, string name, int userId = 0); - Attempt SaveContainer(EntityContainer container, int userId = 0); + Attempt> CreateContainer(int parentContainerId, string name, int userId = Constants.Security.SuperUserId); + Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId); EntityContainer GetContainer(int containerId); EntityContainer GetContainer(Guid containerId); IEnumerable GetContainers(int[] containerIds); IEnumerable GetContainers(TItem contentType); IEnumerable GetContainers(string folderName, int level); - Attempt DeleteContainer(int containerId, int userId = 0); - Attempt> RenameContainer(int id, string name, int userId = 0); + Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId); + Attempt> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId); Attempt> Move(TItem moving, int containerId); Attempt> Copy(TItem copying, int containerId); diff --git a/src/Umbraco.Core/Services/IDataTypeService.cs b/src/Umbraco.Core/Services/IDataTypeService.cs index 537c0e629f..3dc530e250 100644 --- a/src/Umbraco.Core/Services/IDataTypeService.cs +++ b/src/Umbraco.Core/Services/IDataTypeService.cs @@ -9,15 +9,15 @@ namespace Umbraco.Core.Services /// public interface IDataTypeService : IService { - Attempt> CreateContainer(int parentId, string name, int userId = 0); - Attempt SaveContainer(EntityContainer container, int userId = 0); + Attempt> CreateContainer(int parentId, string name, int userId = Constants.Security.SuperUserId); + Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId); EntityContainer GetContainer(int containerId); EntityContainer GetContainer(Guid containerId); IEnumerable GetContainers(string folderName, int level); IEnumerable GetContainers(IDataType dataType); IEnumerable GetContainers(int[] containerIds); - Attempt DeleteContainer(int containerId, int userId = 0); - Attempt> RenameContainer(int id, string name, int userId = 0); + Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId); + Attempt> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId); /// /// Gets a by its Name @@ -52,14 +52,14 @@ namespace Umbraco.Core.Services /// /// to save /// Id of the user issuing the save - void Save(IDataType dataType, int userId = 0); + void Save(IDataType dataType, int userId = Constants.Security.SuperUserId); /// /// Saves a collection of /// /// to save /// Id of the user issuing the save - void Save(IEnumerable dataTypeDefinitions, int userId = 0); + void Save(IEnumerable dataTypeDefinitions, int userId = Constants.Security.SuperUserId); /// /// Saves a collection of @@ -78,7 +78,7 @@ namespace Umbraco.Core.Services /// /// to delete /// Id of the user issuing the deletion - void Delete(IDataType dataType, int userId = 0); + void Delete(IDataType dataType, int userId = Constants.Security.SuperUserId); /// /// Gets a by its control Id diff --git a/src/Umbraco.Core/Services/IFileService.cs b/src/Umbraco.Core/Services/IFileService.cs index 8596424b03..5fe52559ee 100644 --- a/src/Umbraco.Core/Services/IFileService.cs +++ b/src/Umbraco.Core/Services/IFileService.cs @@ -18,12 +18,12 @@ namespace Umbraco.Core.Services IPartialView GetPartialView(string path); IPartialView GetPartialViewMacro(string path); IEnumerable GetPartialViewMacros(params string[] names); - Attempt CreatePartialView(IPartialView partialView, string snippetName = null, int userId = 0); - Attempt CreatePartialViewMacro(IPartialView partialView, string snippetName = null, int userId = 0); - bool DeletePartialView(string path, int userId = 0); - bool DeletePartialViewMacro(string path, int userId = 0); - Attempt SavePartialView(IPartialView partialView, int userId = 0); - Attempt SavePartialViewMacro(IPartialView partialView, int userId = 0); + Attempt CreatePartialView(IPartialView partialView, string snippetName = null, int userId = Constants.Security.SuperUserId); + Attempt CreatePartialViewMacro(IPartialView partialView, string snippetName = null, int userId = Constants.Security.SuperUserId); + bool DeletePartialView(string path, int userId = Constants.Security.SuperUserId); + bool DeletePartialViewMacro(string path, int userId = Constants.Security.SuperUserId); + Attempt SavePartialView(IPartialView partialView, int userId = Constants.Security.SuperUserId); + Attempt SavePartialViewMacro(IPartialView partialView, int userId = Constants.Security.SuperUserId); bool ValidatePartialView(PartialView partialView); bool ValidatePartialViewMacro(PartialView partialView); @@ -45,14 +45,14 @@ namespace Umbraco.Core.Services /// /// to save /// Optional id of the user saving the stylesheet - void SaveStylesheet(Stylesheet stylesheet, int userId = 0); + void SaveStylesheet(Stylesheet stylesheet, int userId = Constants.Security.SuperUserId); /// /// Deletes a stylesheet by its name /// /// Name incl. extension of the Stylesheet to delete /// Optional id of the user deleting the stylesheet - void DeleteStylesheet(string path, int userId = 0); + void DeleteStylesheet(string path, int userId = Constants.Security.SuperUserId); /// /// Validates a @@ -79,14 +79,14 @@ namespace Umbraco.Core.Services /// /// to save /// Optional id of the user saving the script - void SaveScript(Script script, int userId = 0); + void SaveScript(Script script, int userId = Constants.Security.SuperUserId); /// /// Deletes a script by its name /// /// Name incl. extension of the Script to delete /// Optional id of the user deleting the script - void DeleteScript(string path, int userId = 0); + void DeleteScript(string path, int userId = Constants.Security.SuperUserId); /// /// Validates a @@ -187,7 +187,7 @@ namespace Umbraco.Core.Services /// /// to save /// Optional id of the user saving the template - void SaveTemplate(ITemplate template, int userId = 0); + void SaveTemplate(ITemplate template, int userId = Constants.Security.SuperUserId); /// /// Creates a template for a content type @@ -198,16 +198,16 @@ namespace Umbraco.Core.Services /// /// The template created /// - Attempt> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0); + Attempt> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = Constants.Security.SuperUserId); - ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = 0); + ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = Constants.Security.SuperUserId); /// /// Deletes a template by its alias /// /// Alias of the to delete /// Optional id of the user deleting the template - void DeleteTemplate(string alias, int userId = 0); + void DeleteTemplate(string alias, int userId = Constants.Security.SuperUserId); /// /// Validates a @@ -221,7 +221,7 @@ namespace Umbraco.Core.Services /// /// List of to save /// Optional id of the user - void SaveTemplate(IEnumerable templates, int userId = 0); + void SaveTemplate(IEnumerable templates, int userId = Constants.Security.SuperUserId); /// /// Gets the content of a template as a stream. diff --git a/src/Umbraco.Core/Services/ILocalizationService.cs b/src/Umbraco.Core/Services/ILocalizationService.cs index 4882c7e829..54022d37bb 100644 --- a/src/Umbraco.Core/Services/ILocalizationService.cs +++ b/src/Umbraco.Core/Services/ILocalizationService.cs @@ -86,7 +86,7 @@ namespace Umbraco.Core.Services /// /// to save /// Optional id of the user saving the dictionary item - void Save(IDictionaryItem dictionaryItem, int userId = 0); + void Save(IDictionaryItem dictionaryItem, int userId = Constants.Security.SuperUserId); /// /// Deletes a object and its related translations @@ -94,7 +94,7 @@ namespace Umbraco.Core.Services /// /// to delete /// Optional id of the user deleting the dictionary item - void Delete(IDictionaryItem dictionaryItem, int userId = 0); + void Delete(IDictionaryItem dictionaryItem, int userId = Constants.Security.SuperUserId); /// /// Gets a by its id @@ -153,14 +153,14 @@ namespace Umbraco.Core.Services /// /// to save /// Optional id of the user saving the language - void Save(ILanguage language, int userId = 0); + void Save(ILanguage language, int userId = Constants.Security.SuperUserId); /// /// Deletes a by removing it and its usages from the db /// /// to delete /// Optional id of the user deleting the language - void Delete(ILanguage language, int userId = 0); + void Delete(ILanguage language, int userId = Constants.Security.SuperUserId); /// /// Gets the full dictionary key map. diff --git a/src/Umbraco.Core/Services/IMacroService.cs b/src/Umbraco.Core/Services/IMacroService.cs index 8c3acfd619..597c986f37 100644 --- a/src/Umbraco.Core/Services/IMacroService.cs +++ b/src/Umbraco.Core/Services/IMacroService.cs @@ -39,14 +39,14 @@ namespace Umbraco.Core.Services /// /// to delete /// Optional id of the user deleting the macro - void Delete(IMacro macro, int userId = 0); + void Delete(IMacro macro, int userId = Constants.Security.SuperUserId); /// /// Saves an /// /// to save /// Optional id of the user saving the macro - void Save(IMacro macro, int userId = 0); + void Save(IMacro macro, int userId = Constants.Security.SuperUserId); ///// ///// Gets a list all available plugins diff --git a/src/Umbraco.Core/Services/IMediaService.cs b/src/Umbraco.Core/Services/IMediaService.cs index ce2062d08d..02398c3634 100644 --- a/src/Umbraco.Core/Services/IMediaService.cs +++ b/src/Umbraco.Core/Services/IMediaService.cs @@ -37,7 +37,7 @@ namespace Umbraco.Core.Services /// Alias of the /// Optional id of the user creating the media item /// - IMedia CreateMedia(string name, Guid parentId, string mediaTypeAlias, int userId = 0); + IMedia CreateMedia(string name, Guid parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates an object using the alias of the @@ -53,7 +53,7 @@ namespace Umbraco.Core.Services /// Alias of the /// Optional id of the user creating the media item /// - IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = 0); + IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates an object using the alias of the @@ -69,7 +69,7 @@ namespace Umbraco.Core.Services /// Alias of the /// Optional id of the user creating the media item /// - IMedia CreateMedia(string name, IMedia parent, string mediaTypeAlias, int userId = 0); + IMedia CreateMedia(string name, IMedia parent, string mediaTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Gets an object by Id @@ -152,14 +152,14 @@ namespace Umbraco.Core.Services /// Id of the Media's new Parent /// Id of the User moving the Media /// True if moving succeeded, otherwise False - Attempt Move(IMedia media, int parentId, int userId = 0); + Attempt Move(IMedia media, int parentId, int userId = Constants.Security.SuperUserId); /// /// Deletes an object by moving it to the Recycle Bin /// /// The to delete /// Id of the User deleting the Media - Attempt MoveToRecycleBin(IMedia media, int userId = 0); + Attempt MoveToRecycleBin(IMedia media, int userId = Constants.Security.SuperUserId); /// /// Empties the Recycle Bin by deleting all that resides in the bin @@ -172,7 +172,7 @@ namespace Umbraco.Core.Services /// This needs extra care and attention as its potentially a dangerous and extensive operation /// Id of the /// Optional Id of the user deleting Media - void DeleteMediaOfType(int mediaTypeId, int userId = 0); + void DeleteMediaOfType(int mediaTypeId, int userId = Constants.Security.SuperUserId); /// /// Deletes all media of the specified types. All Descendants of deleted media that is not of these types is moved to Recycle Bin. @@ -180,7 +180,7 @@ namespace Umbraco.Core.Services /// This needs extra care and attention as its potentially a dangerous and extensive operation /// Ids of the s /// Optional Id of the user issuing the delete operation - void DeleteMediaOfTypes(IEnumerable mediaTypeIds, int userId = 0); + void DeleteMediaOfTypes(IEnumerable mediaTypeIds, int userId = Constants.Security.SuperUserId); /// /// Permanently deletes an object @@ -191,7 +191,7 @@ namespace Umbraco.Core.Services /// /// The to delete /// Id of the User deleting the Media - Attempt Delete(IMedia media, int userId = 0); + Attempt Delete(IMedia media, int userId = Constants.Security.SuperUserId); /// /// Saves a single object @@ -199,7 +199,7 @@ namespace Umbraco.Core.Services /// The to save /// Id of the User saving the Media /// Optional boolean indicating whether or not to raise events. - Attempt Save(IMedia media, int userId = 0, bool raiseEvents = true); + Attempt Save(IMedia media, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Saves a collection of objects @@ -207,7 +207,7 @@ namespace Umbraco.Core.Services /// Collection of to save /// Id of the User saving the Media /// Optional boolean indicating whether or not to raise events. - Attempt Save(IEnumerable medias, int userId = 0, bool raiseEvents = true); + Attempt Save(IEnumerable medias, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Gets an object by its 'UniqueId' @@ -250,7 +250,7 @@ namespace Umbraco.Core.Services /// Id of the object to delete versions from /// Latest version date /// Optional Id of the User deleting versions of a Content object - void DeleteVersions(int id, DateTime versionDate, int userId = 0); + void DeleteVersions(int id, DateTime versionDate, int userId = Constants.Security.SuperUserId); /// /// Permanently deletes specific version(s) from an object. @@ -259,7 +259,7 @@ namespace Umbraco.Core.Services /// Id of the version to delete /// Boolean indicating whether to delete versions prior to the versionId /// Optional Id of the User deleting versions of a Content object - void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = 0); + void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = Constants.Security.SuperUserId); /// /// Gets an object from the path stored in the 'umbracoFile' property. @@ -304,7 +304,7 @@ namespace Umbraco.Core.Services /// /// /// True if sorting succeeded, otherwise False - bool Sort(IEnumerable items, int userId = 0, bool raiseEvents = true); + bool Sort(IEnumerable items, int userId = Constants.Security.SuperUserId, bool raiseEvents = true); /// /// Creates an object using the alias of the @@ -319,7 +319,7 @@ namespace Umbraco.Core.Services /// Alias of the /// Optional id of the user creating the media item /// - IMedia CreateMediaWithIdentity(string name, IMedia parent, string mediaTypeAlias, int userId = 0); + IMedia CreateMediaWithIdentity(string name, IMedia parent, string mediaTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Creates an object using the alias of the @@ -334,7 +334,7 @@ namespace Umbraco.Core.Services /// Alias of the /// Optional id of the user creating the media item /// - IMedia CreateMediaWithIdentity(string name, int parentId, string mediaTypeAlias, int userId = 0); + IMedia CreateMediaWithIdentity(string name, int parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId); /// /// Gets the content of a media as a stream. diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index c14882fe7a..b38b5a426b 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -27,7 +27,7 @@ namespace Umbraco.Core.Services /// /// /// - IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); + IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = Constants.Security.SuperUserId); /// /// Installs the data, entities, objects contained in an umbraco package file (zip) @@ -35,7 +35,7 @@ namespace Umbraco.Core.Services /// /// /// - InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); + InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = Constants.Security.SuperUserId); /// /// Uninstalls all versions of the package by name @@ -43,7 +43,7 @@ namespace Umbraco.Core.Services /// /// /// - UninstallationSummary UninstallPackage(string packageName, int userId = 0); + UninstallationSummary UninstallPackage(string packageName, int userId = Constants.Security.SuperUserId); #endregion @@ -75,7 +75,7 @@ namespace Umbraco.Core.Services /// If the package is an upgrade, the original/current PackageDefinition is returned /// PackageInstallType GetPackageInstallType(string packageName, SemVersion packageVersion, out PackageDefinition alreadyInstalled); - void DeleteInstalledPackage(int packageId, int userId = 0); + void DeleteInstalledPackage(int packageId, int userId = Constants.Security.SuperUserId); /// /// Persists a package definition to storage @@ -89,7 +89,7 @@ namespace Umbraco.Core.Services IEnumerable GetAllCreatedPackages(); PackageDefinition GetCreatedPackageById(int id); - void DeleteCreatedPackage(int id, int userId = 0); + void DeleteCreatedPackage(int id, int userId = Constants.Security.SuperUserId); /// /// Persists a package definition to storage diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index ce7417722d..485299c18a 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -159,7 +159,7 @@ namespace Umbraco.Core.Services.Implement /// Alias of the /// Optional id of the user creating the content /// - public IContent Create(string name, Guid parentId, string contentTypeAlias, int userId = 0) + public IContent Create(string name, Guid parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId) { // TODO: what about culture? @@ -179,7 +179,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the content type. /// The optional id of the user creating the content. /// The content object. - public IContent Create(string name, int parentId, string contentTypeAlias, int userId = 0) + public IContent Create(string name, int parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId) { // TODO: what about culture? @@ -212,7 +212,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the content type. /// The optional id of the user creating the content. /// The content object. - public IContent Create(string name, IContent parent, string contentTypeAlias, int userId = 0) + public IContent Create(string name, IContent parent, string contentTypeAlias, int userId = Constants.Security.SuperUserId) { // TODO: what about culture? @@ -243,7 +243,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the content type. /// The optional id of the user creating the content. /// The content object. - public IContent CreateAndSave(string name, int parentId, string contentTypeAlias, int userId = 0) + public IContent CreateAndSave(string name, int parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId) { // TODO: what about culture? @@ -277,7 +277,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the content type. /// The optional id of the user creating the content. /// The content object. - public IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = 0) + public IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = Constants.Security.SuperUserId) { // TODO: what about culture? @@ -749,7 +749,7 @@ namespace Umbraco.Core.Services.Implement #region Save, Publish, Unpublish /// - public OperationResult Save(IContent content, int userId = 0, bool raiseEvents = true) + public OperationResult Save(IContent content, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var publishedState = content.PublishedState; if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished) @@ -807,7 +807,7 @@ namespace Umbraco.Core.Services.Implement } /// - public OperationResult Save(IEnumerable contents, int userId = 0, bool raiseEvents = true) + public OperationResult Save(IEnumerable contents, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var evtMsgs = EventMessagesFactory.Get(); var contentsA = contents.ToArray(); @@ -847,7 +847,7 @@ namespace Umbraco.Core.Services.Implement } /// - public PublishResult SaveAndPublish(IContent content, string culture = "*", int userId = 0, bool raiseEvents = true) + public PublishResult SaveAndPublish(IContent content, string culture = "*", int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var evtMsgs = EventMessagesFactory.Get(); @@ -908,14 +908,15 @@ namespace Umbraco.Core.Services.Implement : new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content); } + // TODO: currently, no way to know which one failed if (cultures.Select(content.PublishCulture).Any(isValid => !isValid)) - return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content); //fixme: no way to know which one failed? + return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content); return CommitDocumentChanges(content, userId, raiseEvents); } /// - public PublishResult Unpublish(IContent content, string culture = "*", int userId = 0) + public PublishResult Unpublish(IContent content, string culture = "*", int userId = Constants.Security.SuperUserId) { if (content == null) throw new ArgumentNullException(nameof(content)); @@ -980,7 +981,7 @@ namespace Umbraco.Core.Services.Implement /// to actually commit the changes to the database. /// The document is *always* saved, even when publishing fails. /// - internal PublishResult CommitDocumentChanges(IContent content, int userId = 0, bool raiseEvents = true) + internal PublishResult CommitDocumentChanges(IContent content, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { using (var scope = ScopeProvider.CreateScope()) { @@ -991,7 +992,7 @@ namespace Umbraco.Core.Services.Implement } } - private PublishResult CommitDocumentChangesInternal(IScope scope, IContent content, int userId = 0, bool raiseEvents = true, bool branchOne = false, bool branchRoot = false) + private PublishResult CommitDocumentChangesInternal(IScope scope, IContent content, int userId = Constants.Security.SuperUserId, bool raiseEvents = true, bool branchOne = false, bool branchRoot = false) { var evtMsgs = EventMessagesFactory.Get(); PublishResult publishResult = null; @@ -1055,9 +1056,10 @@ namespace Umbraco.Core.Services.Implement } // reset published state from temp values (publishing, unpublishing) to original value - // (published, unpublished) in order to save the document, unchanged - //TODO: why? this seems odd, were just setting the exact same value that it already has - // instead do we want to just set the PublishState? + // (published, unpublished) in order to save the document, unchanged - yes, this is odd, + // but: (a) it means we don't reproduce the PublishState logic here and (b) setting the + // PublishState to anything other than Publishing or Unpublishing - which is precisely + // what we want to do here - throws content.Published = content.Published; } } @@ -1080,9 +1082,10 @@ namespace Umbraco.Core.Services.Implement else { // reset published state from temp values (publishing, unpublishing) to original value - // (published, unpublished) in order to save the document, unchanged - //TODO: why? this seems odd, were just setting the exact same value that it already has - // instead do we want to just set the PublishState? + // (published, unpublished) in order to save the document, unchanged - yes, this is odd, + // but: (a) it means we don't reproduce the PublishState logic here and (b) setting the + // PublishState to anything other than Publishing or Unpublishing - which is precisely + // what we want to do here - throws content.Published = content.Published; } } @@ -1356,7 +1359,7 @@ namespace Umbraco.Core.Services.Implement /// - public IEnumerable SaveAndPublishBranch(IContent content, bool force, string culture = "*", int userId = 0) + public IEnumerable SaveAndPublishBranch(IContent content, bool force, string culture = "*", int userId = Constants.Security.SuperUserId) { // note: EditedValue and PublishedValue are objects here, so it is important to .Equals() // and not to == them, else we would be comparing references, and that is a bad thing @@ -1398,7 +1401,7 @@ namespace Umbraco.Core.Services.Implement } /// - public IEnumerable SaveAndPublishBranch(IContent content, bool force, string[] cultures, int userId = 0) + public IEnumerable SaveAndPublishBranch(IContent content, bool force, string[] cultures, int userId = Constants.Security.SuperUserId) { // note: EditedValue and PublishedValue are objects here, so it is important to .Equals() // and not to == them, else we would be comparing references, and that is a bad thing @@ -1438,7 +1441,7 @@ namespace Umbraco.Core.Services.Implement public IEnumerable SaveAndPublishBranch(IContent document, bool force, Func> shouldPublish, Func, bool> publishCultures, - int userId = 0) + int userId = Constants.Security.SuperUserId) { if (shouldPublish == null) throw new ArgumentNullException(nameof(shouldPublish)); if (publishCultures == null) throw new ArgumentNullException(nameof(publishCultures)); @@ -1507,9 +1510,8 @@ namespace Umbraco.Core.Services.Implement Audit(AuditType.Publish, userId, document.Id, "Branch published"); // trigger events for the entire branch + // (SaveAndPublishBranchOne does *not* do it) scope.Events.Dispatch(TreeChanged, this, new TreeChange(document, TreeChangeTypes.RefreshBranch).ToEventArgs()); - - //fixme - in the SaveAndPublishBranchOne -> CommitDocumentChangesInternal publishing/published is going to be raised there, so are we raising it 2x for the same thing? scope.Events.Dispatch(Published, this, new ContentPublishedEventArgs(publishedDocuments, false, evtMsgs), nameof(Published)); scope.Complete(); @@ -1617,7 +1619,7 @@ namespace Umbraco.Core.Services.Implement /// Id of the object to delete versions from /// Latest version date /// Optional Id of the User deleting versions of a Content object - public void DeleteVersions(int id, DateTime versionDate, int userId = 0) + public void DeleteVersions(int id, DateTime versionDate, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -1647,7 +1649,7 @@ namespace Umbraco.Core.Services.Implement /// Id of the version to delete /// Boolean indicating whether to delete versions prior to the versionId /// Optional Id of the User deleting versions of a Content object - public void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = 0) + public void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -1733,7 +1735,7 @@ namespace Umbraco.Core.Services.Implement /// The to move /// Id of the Content's new Parent /// Optional Id of the User moving the Content - public void Move(IContent content, int parentId, int userId = 0) + public void Move(IContent content, int parentId, int userId = Constants.Security.SuperUserId) { // if moving to the recycle bin then use the proper method if (parentId == Constants.System.RecycleBinContent) @@ -1909,7 +1911,7 @@ namespace Umbraco.Core.Services.Implement /// Boolean indicating whether the copy should be related to the original /// Optional Id of the User copying the Content /// The newly created object - public IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = 0) + public IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = Constants.Security.SuperUserId) { return Copy(content, parentId, relateToOriginal, true, userId); } @@ -1924,7 +1926,7 @@ namespace Umbraco.Core.Services.Implement /// A value indicating whether to recursively copy children. /// Optional Id of the User copying the Content /// The newly created object - public IContent Copy(IContent content, int parentId, bool relateToOriginal, bool recursive, int userId = 0) + public IContent Copy(IContent content, int parentId, bool relateToOriginal, bool recursive, int userId = Constants.Security.SuperUserId) { var copy = content.DeepCloneWithResetIdentities(); copy.ParentId = parentId; @@ -2027,7 +2029,7 @@ namespace Umbraco.Core.Services.Implement /// The to send to publication /// Optional Id of the User issuing the send to publication /// True if sending publication was successful otherwise false - public bool SendToPublication(IContent content, int userId = 0) + public bool SendToPublication(IContent content, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -2081,7 +2083,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// Result indicating what action was taken when handling the command. - public OperationResult Sort(IEnumerable items, int userId = 0, bool raiseEvents = true) + public OperationResult Sort(IEnumerable items, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var evtMsgs = EventMessagesFactory.Get(); @@ -2110,7 +2112,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// Result indicating what action was taken when handling the command. - public OperationResult Sort(IEnumerable ids, int userId = 0, bool raiseEvents = true) + public OperationResult Sort(IEnumerable ids, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var evtMsgs = EventMessagesFactory.Get(); @@ -2595,7 +2597,7 @@ namespace Umbraco.Core.Services.Implement /// /// Id of the /// Optional Id of the user issuing the delete operation - public void DeleteOfTypes(IEnumerable contentTypeIds, int userId = 0) + public void DeleteOfTypes(IEnumerable contentTypeIds, int userId = Constants.Security.SuperUserId) { // TODO: This currently this is called from the ContentTypeService but that needs to change, // if we are deleting a content type, we should just delete the data and do this operation slightly differently. @@ -2671,7 +2673,7 @@ namespace Umbraco.Core.Services.Implement /// This needs extra care and attention as its potentially a dangerous and extensive operation /// Id of the /// Optional id of the user deleting the media - public void DeleteOfType(int contentTypeId, int userId = 0) + public void DeleteOfType(int contentTypeId, int userId = Constants.Security.SuperUserId) { DeleteOfTypes(new[] { contentTypeId }, userId); } @@ -2729,7 +2731,7 @@ namespace Umbraco.Core.Services.Implement } } - public void SaveBlueprint(IContent content, int userId = 0) + public void SaveBlueprint(IContent content, int userId = Constants.Security.SuperUserId) { //always ensure the blueprint is at the root if (content.ParentId != -1) @@ -2755,7 +2757,7 @@ namespace Umbraco.Core.Services.Implement } } - public void DeleteBlueprint(IContent content, int userId = 0) + public void DeleteBlueprint(IContent content, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -2768,7 +2770,7 @@ namespace Umbraco.Core.Services.Implement private static readonly string[] ArrayOfOneNullString = { null }; - public IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0) + public IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = Constants.Security.SuperUserId) { if (blueprint == null) throw new ArgumentNullException(nameof(blueprint)); @@ -2817,7 +2819,7 @@ namespace Umbraco.Core.Services.Implement } } - public void DeleteBlueprintsOfTypes(IEnumerable contentTypeIds, int userId = 0) + public void DeleteBlueprintsOfTypes(IEnumerable contentTypeIds, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -2844,7 +2846,7 @@ namespace Umbraco.Core.Services.Implement } } - public void DeleteBlueprintsOfType(int contentTypeId, int userId = 0) + public void DeleteBlueprintsOfType(int contentTypeId, int userId = Constants.Security.SuperUserId) { DeleteBlueprintsOfTypes(new[] { contentTypeId }, userId); } @@ -2853,7 +2855,7 @@ namespace Umbraco.Core.Services.Implement #region Rollback - public OperationResult Rollback(int id, int versionId, string culture = "*", int userId = 0) + public OperationResult Rollback(int id, int versionId, string culture = "*", int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeBaseServiceProvider.cs b/src/Umbraco.Core/Services/Implement/ContentTypeBaseServiceProvider.cs index d867224b90..5a56dfe3bc 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeBaseServiceProvider.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeBaseServiceProvider.cs @@ -18,6 +18,7 @@ namespace Umbraco.Core.Services.Implement public IContentTypeBaseService For(IContentBase contentBase) { + if (contentBase == null) throw new ArgumentNullException(nameof(contentBase)); switch (contentBase) { case IContent _: @@ -30,5 +31,12 @@ namespace Umbraco.Core.Services.Implement throw new ArgumentException($"Invalid contentBase type: {contentBase.GetType().FullName}" , nameof(contentBase)); } } + + // note: this should be a default interface method with C# 8 + public IContentTypeComposition GetContentTypeOf(IContentBase contentBase) + { + if (contentBase == null) throw new ArgumentNullException(nameof(contentBase)); + return For(contentBase)?.Get(contentBase.ContentTypeId); + } } } diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index d4cb890953..1f1f0d9ac3 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -376,7 +376,7 @@ namespace Umbraco.Core.Services.Implement #region Save - public void Save(TItem item, int userId = 0) + public void Save(TItem item, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -414,7 +414,7 @@ namespace Umbraco.Core.Services.Implement } } - public void Save(IEnumerable items, int userId = 0) + public void Save(IEnumerable items, int userId = Constants.Security.SuperUserId) { var itemsA = items.ToArray(); @@ -460,7 +460,7 @@ namespace Umbraco.Core.Services.Implement #region Delete - public void Delete(TItem item, int userId = 0) + public void Delete(TItem item, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -514,7 +514,7 @@ namespace Umbraco.Core.Services.Implement } } - public void Delete(IEnumerable items, int userId = 0) + public void Delete(IEnumerable items, int userId = Constants.Security.SuperUserId) { var itemsA = items.ToArray(); @@ -735,7 +735,7 @@ namespace Umbraco.Core.Services.Implement protected Guid ContainerObjectType => EntityContainer.GetContainerObjectType(ContainedObjectType); - public Attempt> CreateContainer(int parentId, string name, int userId = 0) + public Attempt> CreateContainer(int parentId, string name, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -775,7 +775,7 @@ namespace Umbraco.Core.Services.Implement } } - public Attempt SaveContainer(EntityContainer container, int userId = 0) + public Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); @@ -869,7 +869,7 @@ namespace Umbraco.Core.Services.Implement } } - public Attempt DeleteContainer(int containerId, int userId = 0) + public Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -906,7 +906,7 @@ namespace Umbraco.Core.Services.Implement } } - public Attempt> RenameContainer(int id, string name, int userId = 0) + public Attempt> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) diff --git a/src/Umbraco.Core/Services/Implement/DataTypeService.cs b/src/Umbraco.Core/Services/Implement/DataTypeService.cs index 97368e9047..445daddff4 100644 --- a/src/Umbraco.Core/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Core/Services/Implement/DataTypeService.cs @@ -38,7 +38,7 @@ namespace Umbraco.Core.Services.Implement #region Containers - public Attempt> CreateContainer(int parentId, string name, int userId = 0) + public Attempt> CreateContainer(int parentId, string name, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -119,7 +119,7 @@ namespace Umbraco.Core.Services.Implement } } - public Attempt SaveContainer(EntityContainer container, int userId = 0) + public Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); @@ -153,7 +153,7 @@ namespace Umbraco.Core.Services.Implement return OperationResult.Attempt.Succeed(evtMsgs); } - public Attempt DeleteContainer(int containerId, int userId = 0) + public Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -186,7 +186,7 @@ namespace Umbraco.Core.Services.Implement return OperationResult.Attempt.Succeed(evtMsgs); } - public Attempt> RenameContainer(int id, string name, int userId = 0) + public Attempt> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -331,7 +331,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// Id of the user issuing the save - public void Save(IDataType dataType, int userId = 0) + public void Save(IDataType dataType, int userId = Constants.Security.SuperUserId) { dataType.CreatorId = userId; @@ -363,7 +363,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// Id of the user issuing the save - public void Save(IEnumerable dataTypeDefinitions, int userId = 0) + public void Save(IEnumerable dataTypeDefinitions, int userId = Constants.Security.SuperUserId) { Save(dataTypeDefinitions, userId, true); } @@ -413,7 +413,7 @@ namespace Umbraco.Core.Services.Implement /// /// to delete /// Optional Id of the user issuing the deletion - public void Delete(IDataType dataType, int userId = 0) + public void Delete(IDataType dataType, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { diff --git a/src/Umbraco.Core/Services/Implement/FileService.cs b/src/Umbraco.Core/Services/Implement/FileService.cs index d85b0ca1ba..596d033ae8 100644 --- a/src/Umbraco.Core/Services/Implement/FileService.cs +++ b/src/Umbraco.Core/Services/Implement/FileService.cs @@ -74,7 +74,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// - public void SaveStylesheet(Stylesheet stylesheet, int userId = 0) + public void SaveStylesheet(Stylesheet stylesheet, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -100,7 +100,7 @@ namespace Umbraco.Core.Services.Implement /// /// Name incl. extension of the Stylesheet to delete /// - public void DeleteStylesheet(string path, int userId = 0) + public void DeleteStylesheet(string path, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -217,7 +217,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// - public void SaveScript(Script script, int userId = 0) + public void SaveScript(Script script, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -242,7 +242,7 @@ namespace Umbraco.Core.Services.Implement /// /// Name incl. extension of the Script to delete /// - public void DeleteScript(string path, int userId = 0) + public void DeleteScript(string path, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -338,7 +338,7 @@ namespace Umbraco.Core.Services.Implement /// /// The template created /// - public Attempt> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0) + public Attempt> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = Constants.Security.SuperUserId) { var template = new Template(contentTypeName, //NOTE: We are NOT passing in the content type alias here, we want to use it's name since we don't @@ -395,7 +395,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - public ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = 0) + public ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = Constants.Security.SuperUserId) { // file might already be on disk, if so grab the content to avoid overwriting var template = new Template(name, alias) @@ -529,7 +529,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// - public void SaveTemplate(ITemplate template, int userId = 0) + public void SaveTemplate(ITemplate template, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -553,7 +553,7 @@ namespace Umbraco.Core.Services.Implement /// /// List of to save /// Optional id of the user - public void SaveTemplate(IEnumerable templates, int userId = 0) + public void SaveTemplate(IEnumerable templates, int userId = Constants.Security.SuperUserId) { var templatesA = templates.ToArray(); using (var scope = ScopeProvider.CreateScope()) @@ -579,7 +579,7 @@ namespace Umbraco.Core.Services.Implement /// /// Alias of the to delete /// - public void DeleteTemplate(string alias, int userId = 0) + public void DeleteTemplate(string alias, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -723,17 +723,17 @@ namespace Umbraco.Core.Services.Implement } } - public Attempt CreatePartialView(IPartialView partialView, string snippetName = null, int userId = 0) + public Attempt CreatePartialView(IPartialView partialView, string snippetName = null, int userId = Constants.Security.SuperUserId) { return CreatePartialViewMacro(partialView, PartialViewType.PartialView, snippetName, userId); } - public Attempt CreatePartialViewMacro(IPartialView partialView, string snippetName = null, int userId = 0) + public Attempt CreatePartialViewMacro(IPartialView partialView, string snippetName = null, int userId = Constants.Security.SuperUserId) { return CreatePartialViewMacro(partialView, PartialViewType.PartialViewMacro, snippetName, userId); } - private Attempt CreatePartialViewMacro(IPartialView partialView, PartialViewType partialViewType, string snippetName = null, int userId = 0) + private Attempt CreatePartialViewMacro(IPartialView partialView, PartialViewType partialViewType, string snippetName = null, int userId = Constants.Security.SuperUserId) { string partialViewHeader; switch (partialViewType) @@ -799,17 +799,17 @@ namespace Umbraco.Core.Services.Implement return Attempt.Succeed(partialView); } - public bool DeletePartialView(string path, int userId = 0) + public bool DeletePartialView(string path, int userId = Constants.Security.SuperUserId) { return DeletePartialViewMacro(path, PartialViewType.PartialView, userId); } - public bool DeletePartialViewMacro(string path, int userId = 0) + public bool DeletePartialViewMacro(string path, int userId = Constants.Security.SuperUserId) { return DeletePartialViewMacro(path, PartialViewType.PartialViewMacro, userId); } - private bool DeletePartialViewMacro(string path, PartialViewType partialViewType, int userId = 0) + private bool DeletePartialViewMacro(string path, PartialViewType partialViewType, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -839,17 +839,17 @@ namespace Umbraco.Core.Services.Implement return true; } - public Attempt SavePartialView(IPartialView partialView, int userId = 0) + public Attempt SavePartialView(IPartialView partialView, int userId = Constants.Security.SuperUserId) { return SavePartialView(partialView, PartialViewType.PartialView, userId); } - public Attempt SavePartialViewMacro(IPartialView partialView, int userId = 0) + public Attempt SavePartialViewMacro(IPartialView partialView, int userId = Constants.Security.SuperUserId) { return SavePartialView(partialView, PartialViewType.PartialViewMacro, userId); } - private Attempt SavePartialView(IPartialView partialView, PartialViewType partialViewType, int userId = 0) + private Attempt SavePartialView(IPartialView partialView, PartialViewType partialViewType, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { diff --git a/src/Umbraco.Core/Services/Implement/LocalizationService.cs b/src/Umbraco.Core/Services/Implement/LocalizationService.cs index 678ea10da2..251261cfc8 100644 --- a/src/Umbraco.Core/Services/Implement/LocalizationService.cs +++ b/src/Umbraco.Core/Services/Implement/LocalizationService.cs @@ -227,7 +227,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// Optional id of the user saving the dictionary item - public void Save(IDictionaryItem dictionaryItem, int userId = 0) + public void Save(IDictionaryItem dictionaryItem, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -256,7 +256,7 @@ namespace Umbraco.Core.Services.Implement /// /// to delete /// Optional id of the user deleting the dictionary item - public void Delete(IDictionaryItem dictionaryItem, int userId = 0) + public void Delete(IDictionaryItem dictionaryItem, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -356,7 +356,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// Optional id of the user saving the language - public void Save(ILanguage language, int userId = 0) + public void Save(ILanguage language, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -409,7 +409,7 @@ namespace Umbraco.Core.Services.Implement /// /// to delete /// Optional id of the user deleting the language - public void Delete(ILanguage language, int userId = 0) + public void Delete(ILanguage language, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { diff --git a/src/Umbraco.Core/Services/Implement/MacroService.cs b/src/Umbraco.Core/Services/Implement/MacroService.cs index d4f2d95bbb..a6631aae4c 100644 --- a/src/Umbraco.Core/Services/Implement/MacroService.cs +++ b/src/Umbraco.Core/Services/Implement/MacroService.cs @@ -81,7 +81,7 @@ namespace Umbraco.Core.Services.Implement /// /// to delete /// Optional id of the user deleting the macro - public void Delete(IMacro macro, int userId = 0) + public void Delete(IMacro macro, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -106,7 +106,7 @@ namespace Umbraco.Core.Services.Implement /// /// to save /// Optional Id of the user deleting the macro - public void Save(IMacro macro, int userId = 0) + public void Save(IMacro macro, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { diff --git a/src/Umbraco.Core/Services/Implement/MediaService.cs b/src/Umbraco.Core/Services/Implement/MediaService.cs index e7a42e28e4..1fa9b9fdb4 100644 --- a/src/Umbraco.Core/Services/Implement/MediaService.cs +++ b/src/Umbraco.Core/Services/Implement/MediaService.cs @@ -112,7 +112,7 @@ namespace Umbraco.Core.Services.Implement /// Alias of the /// Optional id of the user creating the media item /// - public IMedia CreateMedia(string name, Guid parentId, string mediaTypeAlias, int userId = 0) + public IMedia CreateMedia(string name, Guid parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { var parent = GetById(parentId); return CreateMedia(name, parent, mediaTypeAlias, userId); @@ -130,7 +130,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the media type. /// The optional id of the user creating the media. /// The media object. - public IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = 0) + public IMedia CreateMedia(string name, int parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { var mediaType = GetMediaType(mediaTypeAlias); if (mediaType == null) @@ -160,7 +160,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the media type. /// The optional id of the user creating the media. /// The media object. - public IMedia CreateMedia(string name, string mediaTypeAlias, int userId = 0) + public IMedia CreateMedia(string name, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { // not locking since not saving anything @@ -190,7 +190,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the media type. /// The optional id of the user creating the media. /// The media object. - public IMedia CreateMedia(string name, IMedia parent, string mediaTypeAlias, int userId = 0) + public IMedia CreateMedia(string name, IMedia parent, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { if (parent == null) throw new ArgumentNullException(nameof(parent)); @@ -219,7 +219,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the media type. /// The optional id of the user creating the media. /// The media object. - public IMedia CreateMediaWithIdentity(string name, int parentId, string mediaTypeAlias, int userId = 0) + public IMedia CreateMediaWithIdentity(string name, int parentId, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -251,7 +251,7 @@ namespace Umbraco.Core.Services.Implement /// The alias of the media type. /// The optional id of the user creating the media. /// The media object. - public IMedia CreateMediaWithIdentity(string name, IMedia parent, string mediaTypeAlias, int userId = 0) + public IMedia CreateMediaWithIdentity(string name, IMedia parent, string mediaTypeAlias, int userId = Constants.Security.SuperUserId) { if (parent == null) throw new ArgumentNullException(nameof(parent)); @@ -632,7 +632,7 @@ namespace Umbraco.Core.Services.Implement /// The to save /// Id of the User saving the Media /// Optional boolean indicating whether or not to raise events. - public Attempt Save(IMedia media, int userId = 0, bool raiseEvents = true) + public Attempt Save(IMedia media, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var evtMsgs = EventMessagesFactory.Get(); @@ -677,7 +677,7 @@ namespace Umbraco.Core.Services.Implement /// Collection of to save /// Id of the User saving the Media /// Optional boolean indicating whether or not to raise events. - public Attempt Save(IEnumerable medias, int userId = 0, bool raiseEvents = true) + public Attempt Save(IEnumerable medias, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var evtMsgs = EventMessagesFactory.Get(); var mediasA = medias.ToArray(); @@ -724,7 +724,7 @@ namespace Umbraco.Core.Services.Implement /// /// The to delete /// Id of the User deleting the Media - public Attempt Delete(IMedia media, int userId = 0) + public Attempt Delete(IMedia media, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); @@ -785,7 +785,7 @@ namespace Umbraco.Core.Services.Implement /// Id of the object to delete versions from /// Latest version date /// Optional Id of the User deleting versions of a Media object - public void DeleteVersions(int id, DateTime versionDate, int userId = 0) + public void DeleteVersions(int id, DateTime versionDate, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -809,7 +809,7 @@ namespace Umbraco.Core.Services.Implement } } - private void DeleteVersions(IScope scope, bool wlock, int id, DateTime versionDate, int userId = 0) + private void DeleteVersions(IScope scope, bool wlock, int id, DateTime versionDate, int userId = Constants.Security.SuperUserId) { var args = new DeleteRevisionsEventArgs(id, dateToRetain: versionDate); if (scope.Events.DispatchCancelable(DeletingVersions, this, args)) @@ -832,7 +832,7 @@ namespace Umbraco.Core.Services.Implement /// Id of the version to delete /// Boolean indicating whether to delete versions prior to the versionId /// Optional Id of the User deleting versions of a Media object - public void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = 0) + public void DeleteVersion(int id, int versionId, bool deletePriorVersions, int userId = Constants.Security.SuperUserId) { using (var scope = ScopeProvider.CreateScope()) { @@ -872,7 +872,7 @@ namespace Umbraco.Core.Services.Implement /// /// The to delete /// Id of the User deleting the Media - public Attempt MoveToRecycleBin(IMedia media, int userId = 0) + public Attempt MoveToRecycleBin(IMedia media, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); var moves = new List>(); @@ -916,7 +916,7 @@ namespace Umbraco.Core.Services.Implement /// The to move /// Id of the Media's new Parent /// Id of the User moving the Media - public Attempt Move(IMedia media, int parentId, int userId = 0) + public Attempt Move(IMedia media, int parentId, int userId = Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); @@ -1084,7 +1084,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// True if sorting succeeded, otherwise False - public bool Sort(IEnumerable items, int userId = 0, bool raiseEvents = true) + public bool Sort(IEnumerable items, int userId = Constants.Security.SuperUserId, bool raiseEvents = true) { var itemsA = items.ToArray(); if (itemsA.Length == 0) return true; @@ -1273,7 +1273,7 @@ namespace Umbraco.Core.Services.Implement /// /// Id of the /// Optional id of the user deleting the media - public void DeleteMediaOfTypes(IEnumerable mediaTypeIds, int userId = 0) + public void DeleteMediaOfTypes(IEnumerable mediaTypeIds, int userId = Constants.Security.SuperUserId) { // TODO: This currently this is called from the ContentTypeService but that needs to change, // if we are deleting a content type, we should just delete the data and do this operation slightly differently. @@ -1338,7 +1338,7 @@ namespace Umbraco.Core.Services.Implement /// This needs extra care and attention as its potentially a dangerous and extensive operation /// Id of the /// Optional id of the user deleting the media - public void DeleteMediaOfType(int mediaTypeId, int userId = 0) + public void DeleteMediaOfType(int mediaTypeId, int userId = Constants.Security.SuperUserId) { DeleteMediaOfTypes(new[] { mediaTypeId }, userId); } diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index 9c4c6290a9..5194a26eb5 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -100,7 +100,7 @@ namespace Umbraco.Core.Services.Implement public CompiledPackage GetCompiledPackageInfo(FileInfo packageFile) => _packageInstallation.ReadPackage(packageFile); - public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0) + public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = Constants.Security.SuperUserId) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); @@ -118,7 +118,7 @@ namespace Umbraco.Core.Services.Implement return files; } - public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0) + public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = Constants.Security.SuperUserId) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); @@ -141,7 +141,7 @@ namespace Umbraco.Core.Services.Implement return summary; } - public UninstallationSummary UninstallPackage(string packageName, int userId = 0) + public UninstallationSummary UninstallPackage(string packageName, int userId = Constants.Security.SuperUserId) { //this is ordered by descending version var allPackageVersions = GetInstalledPackageByName(packageName)?.ToList(); @@ -187,7 +187,7 @@ namespace Umbraco.Core.Services.Implement #region Created/Installed Package Repositories - public void DeleteCreatedPackage(int id, int userId = 0) + public void DeleteCreatedPackage(int id, int userId = Constants.Security.SuperUserId) { var package = GetCreatedPackageById(id); if (package == null) return; @@ -236,7 +236,7 @@ namespace Umbraco.Core.Services.Implement public bool SaveInstalledPackage(PackageDefinition definition) => _installedPackages.SavePackage(definition); - public void DeleteInstalledPackage(int packageId, int userId = 0) + public void DeleteInstalledPackage(int packageId, int userId = Constants.Security.SuperUserId) { var package = GetInstalledPackageById(packageId); if (package == null) return; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index ab663b5a24..b80d607d4f 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -55,25 +55,25 @@ - - + + 2.2.2 - 5.2.6 + 5.2.7 - 4.0.0 + 4.0.1 - - + + - 2.7.1 + 2.8.0 2.0.1 @@ -88,7 +88,7 @@ 1.0.0 - 1.0.2 + 1.0.3 2.2.2 @@ -302,6 +302,7 @@ + @@ -473,6 +474,7 @@ + diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index 1320f3b0d2..989afd8d1c 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -49,7 +49,7 @@ - + diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 5e366eef33..49de625450 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -64,23 +64,23 @@ - + - + - + - + - - + + @@ -88,7 +88,7 @@ - + @@ -100,11 +100,11 @@ - + - + diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 2354dc8147..2dbd3055cb 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -264,7 +264,7 @@ AnotherContentFinder public void Resolves_Assigned_Mappers() { var foundTypes1 = _typeLoader.GetAssignedMapperTypes(); - Assert.AreEqual(29, foundTypes1.Count()); + Assert.AreEqual(30, foundTypes1.Count()); } [Test] diff --git a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs index 5c95f1ead5..efa464a46c 100644 --- a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs +++ b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs @@ -1,22 +1,60 @@ using System; using System.Linq; +using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Composing.Composers; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; +using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.Models { [TestFixture] public class ContentExtensionsTests : UmbracoTestBase { - #region Others + private IContentTypeService _contentTypeService; + + protected override void Compose() + { + base.Compose(); + + Composition.Register(_ => Mock.Of()); + Composition.ComposeFileSystems(); + + Composition.Register(_ => Mock.Of()); + Composition.Register(_ => Mock.Of()); + + // all this is required so we can validate properties... + var editor = new TextboxPropertyEditor(Mock.Of()) { Alias = "test" }; + Composition.Register(_ => new DataEditorCollection(new[] { editor })); + Composition.Register(); + var dataType = Mock.Of(); + Mock.Get(dataType).Setup(x => x.Configuration).Returns(() => new object()); + var dataTypeService = Mock.Of(); + Mock.Get(dataTypeService) + .Setup(x => x.GetDataType(It.IsAny())) + .Returns(() => dataType); + + _contentTypeService = Mock.Of(); + var mediaTypeService = Mock.Of(); + var memberTypeService = Mock.Of(); + Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService, contentTypeBaseServiceProvider: new ContentTypeBaseServiceProvider(_contentTypeService, mediaTypeService, memberTypeService))); + } [Test] public void DirtyProperty_Reset_Clears_SavedPublishedState() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.PublishedState = PublishedState.Publishing; @@ -30,6 +68,8 @@ namespace Umbraco.Tests.Models public void DirtyProperty_OnlyIfActuallyChanged_Content() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // if you assign a content property with its value it is not dirty @@ -52,6 +92,8 @@ namespace Umbraco.Tests.Models public void DirtyProperty_OnlyIfActuallyChanged_User() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); var prop = content.Properties.First(); @@ -76,6 +118,8 @@ namespace Umbraco.Tests.Models public void DirtyProperty_UpdateDate() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); var prop = content.Properties.First(); @@ -99,6 +143,8 @@ namespace Umbraco.Tests.Models public void DirtyProperty_WasDirty_ContentProperty() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); Assert.IsFalse(content.IsDirty()); @@ -126,6 +172,8 @@ namespace Umbraco.Tests.Models public void DirtyProperty_WasDirty_ContentSortOrder() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); Assert.IsFalse(content.IsDirty()); @@ -153,6 +201,8 @@ namespace Umbraco.Tests.Models public void DirtyProperty_WasDirty_UserProperty() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); var prop = content.Properties.First(); content.ResetDirtyProperties(false); @@ -178,7 +228,5 @@ namespace Umbraco.Tests.Models //Assert.IsFalse(content.WasDirty()); // not impacted by user properties Assert.IsTrue(content.WasDirty()); // now it is! } - - #endregion } } diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index c5dd8a6aea..693f919b7a 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; @@ -28,6 +29,8 @@ namespace Umbraco.Tests.Models [TestFixture] public class ContentTests : UmbracoTestBase { + private IContentTypeService _contentTypeService; + protected override void Compose() { base.Compose(); @@ -48,19 +51,25 @@ namespace Umbraco.Tests.Models Mock.Get(dataTypeService) .Setup(x => x.GetDataType(It.IsAny())) .Returns(() => dataType); - Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService)); + + _contentTypeService = Mock.Of(); + var mediaTypeService = Mock.Of(); + var memberTypeService = Mock.Of(); + Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService, contentTypeBaseServiceProvider: new ContentTypeBaseServiceProvider(_contentTypeService, mediaTypeService, memberTypeService))); + } [Test] public void Variant_Culture_Names_Track_Dirty_Changes() { var contentType = new ContentType(-1) { Alias = "contentType" }; + contentType.Variations = ContentVariation.Culture; + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; const string langFr = "fr-FR"; - contentType.Variations = ContentVariation.Culture; - Assert.IsFalse(content.IsPropertyDirty("CultureInfos")); //hasn't been changed Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date @@ -123,6 +132,7 @@ namespace Umbraco.Tests.Models //ensure that nothing is marked as dirty contentType.ResetDirtyProperties(false); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); var content = MockedContent.CreateSimpleContent(contentType); @@ -138,6 +148,8 @@ namespace Umbraco.Tests.Models public void All_Dirty_Properties_Get_Reset() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); @@ -154,6 +166,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -167,6 +181,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -183,6 +199,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -199,6 +217,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.Id = 10; content.Key = new Guid("29181B97-CB8F-403F-86DE-5FEB497F4800"); @@ -278,6 +298,8 @@ namespace Umbraco.Tests.Models var contentType = MockedContentTypes.CreateTextPageContentType(); contentType.Id = 99; contentType.Variations = ContentVariation.Culture; + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.SetCultureName("Hello", "en-US"); @@ -387,6 +409,8 @@ namespace Umbraco.Tests.Models var contentType = MockedContentTypes.CreateTextPageContentType(); contentType.Id = 99; contentType.Variations = ContentVariation.Culture; + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.SetCultureName("Hello", "en-US"); @@ -458,6 +482,8 @@ namespace Umbraco.Tests.Models // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); contentType.Id = 99; + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); var i = 200; foreach (var property in content.Properties) @@ -509,10 +535,12 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act - content.PropertyValues(new {title = "This is the new title"}); + content.PropertyValues(new { title = "This is the new title"}); // Assert Assert.That(content.Properties.Any(), Is.True); @@ -527,6 +555,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -543,14 +573,12 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act contentType.PropertyGroups.Add(new PropertyGroup(true) { Name = "Test Group", SortOrder = 3 }); // Assert Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(3)); - Assert.That(content.PropertyGroups.Count(), Is.EqualTo(3)); } [Test] @@ -573,7 +601,6 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act contentType.PropertyGroups["Content"].PropertyTypes.Add(new PropertyType("test", ValueStorageType.Ntext, "subtitle") @@ -587,7 +614,6 @@ namespace Umbraco.Tests.Models // Assert Assert.That(contentType.PropertyGroups["Content"].PropertyTypes.Count, Is.EqualTo(3)); - Assert.That(content.PropertyGroups.First(x => x.Name == "Content").PropertyTypes.Count, Is.EqualTo(3)); } [Test] @@ -595,6 +621,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -617,6 +645,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -637,8 +667,6 @@ namespace Umbraco.Tests.Models // Assert Assert.That(content.Properties.Count, Is.EqualTo(5)); - Assert.That(content.PropertyTypes.Count(), Is.EqualTo(5)); - Assert.That(content.PropertyGroups.Count(), Is.EqualTo(3)); Assert.That(content.Properties["subtitle"].GetValue(), Is.EqualTo("Subtitle Test")); Assert.That(content.Properties["title"].GetValue(), Is.EqualTo("Textpage textpage")); } @@ -648,6 +676,8 @@ namespace Umbraco.Tests.Models { // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act - note that the PropertyType's properties like SortOrder is not updated through the Content object @@ -669,6 +699,8 @@ namespace Umbraco.Tests.Models // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -676,8 +708,6 @@ namespace Umbraco.Tests.Models // Assert Assert.That(content.Properties.Contains("author"), Is.True); - Assert.That(content.PropertyGroups.Count(), Is.EqualTo(1)); - Assert.That(content.PropertyTypes.Count(), Is.EqualTo(3)); //Note: There was 4 properties, after changing ContentType 1 has been added (no properties are deleted) Assert.That(content.Properties.Count, Is.EqualTo(5)); } @@ -688,6 +718,8 @@ namespace Umbraco.Tests.Models // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -705,6 +737,8 @@ namespace Umbraco.Tests.Models // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -723,6 +757,7 @@ namespace Umbraco.Tests.Models public void Can_Change_ContentType_On_Content_And_Clear_Old_PropertyTypes() { throw new NotImplementedException(); + //Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); //// Arrange //var contentType = MockedContentTypes.CreateTextPageContentType(); @@ -742,6 +777,8 @@ namespace Umbraco.Tests.Models public void Can_Verify_Content_Is_Published() { var contentType = MockedContentTypes.CreateTextPageContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(); @@ -811,6 +848,8 @@ namespace Umbraco.Tests.Models // Arrange var contentType = MockedContentTypes.CreateTextPageContentType(); contentType.ResetDirtyProperties(); //reset + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateTextpageContent(contentType, "test", -1); content.ResetDirtyProperties(); diff --git a/src/Umbraco.Tests/Models/Mapping/AutoMapper6Tests.cs b/src/Umbraco.Tests/Models/Mapping/AutoMapper6Tests.cs index 59c514f654..18bceaae49 100644 --- a/src/Umbraco.Tests/Models/Mapping/AutoMapper6Tests.cs +++ b/src/Umbraco.Tests/Models/Mapping/AutoMapper6Tests.cs @@ -121,16 +121,16 @@ namespace Umbraco.Tests.Models.Mapping break; case 1: map - .ForMember(dest => dest.ValueString, opt => opt.ResolveUsing(src => src.ValueString)); + .ForMember(dest => dest.ValueString, opt => opt.MapFrom(src => src.ValueString)); break; case 2: map - .ForMember(dest => dest.ValueString, opt => opt.ResolveUsing()); + .ForMember(dest => dest.ValueString, opt => opt.MapFrom()); break; case 3: // in most cases that should be perfectly enough? map - .ForMember(dest => dest.ValueString, opt => opt.ResolveUsing(source => "!!" + source.ValueString + "!!")); + .ForMember(dest => dest.ValueString, opt => opt.MapFrom(source => "!!" + source.ValueString + "!!")); break; default: throw new ArgumentOutOfRangeException(nameof(ver)); diff --git a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs index e3551921d8..1817414f69 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentWebModelMappingTests.cs @@ -4,15 +4,20 @@ using AutoMapper; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Composing.Composers; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Services; using Umbraco.Core.Dictionary; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services.Implement; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Web.Models.ContentEditing; using Umbraco.Tests.Testing; +using Umbraco.Web.PropertyEditors; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Models.Mapping @@ -21,12 +26,37 @@ namespace Umbraco.Tests.Models.Mapping [UmbracoTest(AutoMapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] public class ContentWebModelMappingTests : TestWithDatabaseBase { + private IContentTypeService _contentTypeService; + + protected override void Compose() { base.Compose(); Composition.RegisterUnique(f => Mock.Of()); - Composition.RegisterUnique(f => Mock.Of()); + + Composition.Register(_ => Mock.Of()); + Composition.ComposeFileSystems(); + + Composition.Register(_ => Mock.Of()); + Composition.Register(_ => Mock.Of()); + + // all this is required so we can validate properties... + var editor = new TextboxPropertyEditor(Mock.Of()) { Alias = "test" }; + Composition.Register(_ => new DataEditorCollection(new[] { editor })); + Composition.Register(); + var dataType = Mock.Of(); + Mock.Get(dataType).Setup(x => x.Configuration).Returns(() => new object()); + var dataTypeService = Mock.Of(); + Mock.Get(dataTypeService) + .Setup(x => x.GetDataType(It.IsAny())) + .Returns(() => dataType); + + _contentTypeService = Mock.Of(); + var mediaTypeService = Mock.Of(); + var memberTypeService = Mock.Of(); + Composition.RegisterUnique(_ => _contentTypeService); + Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService, contentTypeBaseServiceProvider: new ContentTypeBaseServiceProvider(_contentTypeService, mediaTypeService, memberTypeService))); } [DataEditor("Test.Test", "Test", "~/Test.html")] @@ -53,6 +83,8 @@ namespace Umbraco.Tests.Models.Mapping public void To_Media_Item_Simple() { var contentType = MockedContentTypes.CreateImageMediaType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedMedia.CreateMediaImage(contentType, -1); FixUsers(content); @@ -70,6 +102,8 @@ namespace Umbraco.Tests.Models.Mapping public void To_Content_Item_Simple() { var contentType = MockedContentTypes.CreateSimpleContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateSimpleContent(contentType); FixUsers(content); @@ -87,6 +121,8 @@ namespace Umbraco.Tests.Models.Mapping public void To_Content_Item_Dto() { var contentType = MockedContentTypes.CreateSimpleContentType(); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + var content = MockedContent.CreateSimpleContent(contentType); FixUsers(content); @@ -117,8 +153,8 @@ namespace Umbraco.Tests.Models.Mapping public void To_Display_Model() { var contentType = MockedContentTypes.CreateSimpleContentType(); - var contentTypeServiceMock = Mock.Get(Current.Services.ContentTypeService); - contentTypeServiceMock.Setup(x => x.Get(contentType.Id)).Returns(() => contentType); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + Mock.Get(_contentTypeService).Setup(x => x.Get(It.IsAny())).Returns(contentType); var content = MockedContent.CreateSimpleContent(contentType); @@ -127,7 +163,7 @@ namespace Umbraco.Tests.Models.Mapping // need ids for tabs var id = 1; - foreach (var g in content.PropertyGroups) + foreach (var g in contentType.CompositionPropertyGroups) g.Id = id++; var result = Mapper.Map(content); @@ -141,7 +177,7 @@ namespace Umbraco.Tests.Models.Mapping AssertDisplayProperty(invariantContent, p); } - Assert.AreEqual(content.PropertyGroups.Count(), invariantContent.Tabs.Count()); + Assert.AreEqual(contentType.CompositionPropertyGroups.Count(), invariantContent.Tabs.Count()); Assert.IsTrue(invariantContent.Tabs.First().IsActive); Assert.IsTrue(invariantContent.Tabs.Except(new[] { invariantContent.Tabs.First() }).All(x => x.IsActive == false)); } @@ -151,9 +187,8 @@ namespace Umbraco.Tests.Models.Mapping { var contentType = MockedContentTypes.CreateSimpleContentType(); contentType.PropertyGroups.Clear(); - var contentTypeServiceMock = Mock.Get(Current.Services.ContentTypeService); - contentTypeServiceMock.Setup(x => x.Get(contentType.Id)).Returns(() => contentType); - + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + Mock.Get(_contentTypeService).Setup(x => x.Get(It.IsAny())).Returns(contentType); var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 }; @@ -168,7 +203,7 @@ namespace Umbraco.Tests.Models.Mapping AssertDisplayProperty(invariantContent, p); } - Assert.AreEqual(content.PropertyGroups.Count(), invariantContent.Tabs.Count()); + Assert.AreEqual(contentType.CompositionPropertyGroups.Count(), invariantContent.Tabs.Count()); } [Test] @@ -186,8 +221,8 @@ namespace Umbraco.Tests.Models.Mapping p.Id = idSeed; idSeed++; } - var contentTypeServiceMock = Mock.Get(Current.Services.ContentTypeService); - contentTypeServiceMock.Setup(x => x.Get(contentType.Id)).Returns(() => contentType); + Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); + Mock.Get(_contentTypeService).Setup(x => x.Get(It.IsAny())).Returns(contentType); var content = MockedContent.CreateSimpleContent(contentType); @@ -200,7 +235,7 @@ namespace Umbraco.Tests.Models.Mapping } //need ids for tabs var id = 1; - foreach (var g in content.PropertyGroups) + foreach (var g in contentType.CompositionPropertyGroups) { g.Id = id; id++; @@ -221,7 +256,7 @@ namespace Umbraco.Tests.Models.Mapping AssertDisplayProperty(invariantContent, p); } - Assert.AreEqual(content.PropertyGroups.Count(), invariantContent.Tabs.Count() - 1); + Assert.AreEqual(contentType.CompositionPropertyGroups.Count(), invariantContent.Tabs.Count() - 1); Assert.IsTrue(invariantContent.Tabs.Any(x => x.Label == Current.Services.TextService.Localize("general/properties"))); Assert.AreEqual(2, invariantContent.Tabs.Where(x => x.Label == Current.Services.TextService.Localize("general/properties")).SelectMany(x => x.Properties.Where(p => p.Alias.StartsWith("_umb_") == false)).Count()); } diff --git a/src/Umbraco.Tests/Models/MemberTests.cs b/src/Umbraco.Tests/Models/MemberTests.cs index c09f2e9460..5e92ad7ccf 100644 --- a/src/Umbraco.Tests/Models/MemberTests.cs +++ b/src/Umbraco.Tests/Models/MemberTests.cs @@ -67,20 +67,7 @@ namespace Umbraco.Tests.Models Assert.AreEqual(clone.Id, member.Id); Assert.AreEqual(clone.VersionId, member.VersionId); Assert.AreEqual(clone.AdditionalData, member.AdditionalData); - Assert.AreNotSame(clone.ContentType, member.ContentType); Assert.AreEqual(clone.ContentType, member.ContentType); - Assert.AreEqual(clone.ContentType.PropertyGroups.Count, member.ContentType.PropertyGroups.Count); - for (var index = 0; index < member.ContentType.PropertyGroups.Count; index++) - { - Assert.AreNotSame(clone.ContentType.PropertyGroups[index], member.ContentType.PropertyGroups[index]); - Assert.AreEqual(clone.ContentType.PropertyGroups[index], member.ContentType.PropertyGroups[index]); - } - Assert.AreEqual(clone.ContentType.PropertyTypes.Count(), member.ContentType.PropertyTypes.Count()); - for (var index = 0; index < member.ContentType.PropertyTypes.Count(); index++) - { - Assert.AreNotSame(clone.ContentType.PropertyTypes.ElementAt(index), member.ContentType.PropertyTypes.ElementAt(index)); - Assert.AreEqual(clone.ContentType.PropertyTypes.ElementAt(index), member.ContentType.PropertyTypes.ElementAt(index)); - } Assert.AreEqual(clone.ContentTypeId, member.ContentTypeId); Assert.AreEqual(clone.CreateDate, member.CreateDate); Assert.AreEqual(clone.CreatorId, member.CreatorId); @@ -112,6 +99,9 @@ namespace Umbraco.Tests.Models Assert.AreEqual(clone.Properties[index], member.Properties[index]); } + // this can be the same, it is immutable + Assert.AreSame(clone.ContentType, member.ContentType); + //This double verifies by reflection var allProps = clone.GetType().GetProperties(); foreach (var propertyInfo in allProps) diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs index 0ccdabe928..36fb399fa7 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -227,6 +227,9 @@ namespace Umbraco.Tests.Models // now it will work contentType.Variations = ContentVariation.Culture; + // recreate content to re-capture content type variations + content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + // invariant name works content.Name = "name"; Assert.AreEqual("name", content.GetCultureName(null)); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index 459dbeb587..2c4f3f1908 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -130,10 +130,11 @@ namespace Umbraco.Tests.Persistence.Repositories var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); ServiceContext.FileService.SaveTemplate(hasPropertiesContentType.DefaultTemplate); // else, FK violation on contentType! + contentTypeRepository.Save(hasPropertiesContentType); + IContent content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType); // save = create the initial version - contentTypeRepository.Save(hasPropertiesContentType); repository.Save(content1); versions.Add(content1.VersionId); // the first version @@ -399,9 +400,10 @@ namespace Umbraco.Tests.Persistence.Repositories var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository); var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage"); ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + contentTypeRepository.Save(contentType); + IContent textpage = MockedContent.CreateSimpleContent(contentType); - contentTypeRepository.Save(contentType); repository.Save(textpage); scope.Complete(); @@ -487,9 +489,10 @@ namespace Umbraco.Tests.Persistence.Repositories var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository); var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + contentTypeRepository.Save(contentType); + var textpage = MockedContent.CreateSimpleContent(contentType); - contentTypeRepository.Save(contentType); repository.Save(textpage); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index cbd591950a..1c1b5e60f4 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -61,8 +61,9 @@ namespace Umbraco.Tests.Persistence.Repositories udb.EnableSqlCount = false; var mediaType = MockedContentTypes.CreateSimpleMediaType("umbTextpage1", "Textpage"); - var media = MockedMedia.CreateSimpleMedia(mediaType, "hello", -1); mediaTypeRepository.Save(mediaType); + + var media = MockedMedia.CreateSimpleMedia(mediaType, "hello", -1); repository.Save(media); udb.EnableSqlCount = true; @@ -271,7 +272,7 @@ namespace Umbraco.Tests.Persistence.Repositories var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); repository.Save(folder); } - + var types = new[] { 1031 }; var query = scope.SqlContext.Query().Where(x => types.Contains(x.ContentTypeId)); @@ -302,7 +303,7 @@ namespace Umbraco.Tests.Persistence.Repositories var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); repository.Save(folder); } - + var types = new[] { "Folder" }; var query = scope.SqlContext.Query().Where(x => types.Contains(x.ContentType.Alias)); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index dea15cd4ad..c46a090685 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -164,21 +164,19 @@ namespace Umbraco.Tests.Persistence.Repositories var memberType = MockedContentTypes.CreateSimpleMemberType(); memberTypeRepository.Save(memberType); - var member = MockedMember.CreateSimpleMember(memberType, "Johnny Hefty", "johnny@example.com", "123", "hefty"); repository.Save(member); - var sut = repository.Get(member.Id); - Assert.That(sut.ContentType.PropertyGroups.Count(), Is.EqualTo(2)); - Assert.That(sut.ContentType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count)); + Assert.That(memberType.CompositionPropertyGroups.Count(), Is.EqualTo(2)); + Assert.That(memberType.CompositionPropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count)); Assert.That(sut.Properties.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count)); - var grp = sut.PropertyGroups.FirstOrDefault(x => x.Name == Constants.Conventions.Member.StandardPropertiesGroupName); + var grp = memberType.CompositionPropertyGroups.FirstOrDefault(x => x.Name == Constants.Conventions.Member.StandardPropertiesGroupName); Assert.IsNotNull(grp); var aliases = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray(); - foreach (var p in sut.PropertyTypes.Where(x => aliases.Contains(x.Alias))) + foreach (var p in memberType.CompositionPropertyTypes.Where(x => aliases.Contains(x.Alias))) { Assert.AreEqual(grp.Id, p.PropertyGroupId.Value); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 8f750f9238..1d50fcac9e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -75,7 +75,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act repository.Save(user); - + // Assert Assert.That(user.HasIdentity, Is.True); @@ -96,9 +96,9 @@ namespace Umbraco.Tests.Persistence.Repositories // Act repository.Save(user1); - + repository.Save(use2); - + // Assert Assert.That(user1.HasIdentity, Is.True); @@ -117,7 +117,7 @@ namespace Umbraco.Tests.Persistence.Repositories var user = MockedUser.CreateUser(); repository.Save(user); - + // Act var resolved = repository.Get((int)user.Id); @@ -132,9 +132,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Update_On_UserRepository() { var ct = MockedContentTypes.CreateBasicContentType("test"); - var content = MockedContent.CreateBasicContent(ct); var mt = MockedContentTypes.CreateSimpleMediaType("testmedia", "TestMedia"); - var media = MockedMedia.CreateSimpleMedia(mt, "asdf", -1); // Arrange var provider = TestObjects.GetScopeProvider(Logger); @@ -147,11 +145,12 @@ namespace Umbraco.Tests.Persistence.Repositories contentTypeRepo.Save(ct); mediaTypeRepo.Save(mt); - + + var content = MockedContent.CreateBasicContent(ct); + var media = MockedMedia.CreateSimpleMedia(mt, "asdf", -1); contentRepository.Save(content); mediaRepository.Save(media); - var user = CreateAndCommitUserWithGroup(userRepository, userGroupRepository); @@ -171,7 +170,7 @@ namespace Umbraco.Tests.Persistence.Repositories resolved.Username = "newName"; userRepository.Save(resolved); - + var updatedItem = (User) userRepository.Get(user.Id); // Assert @@ -204,13 +203,13 @@ namespace Umbraco.Tests.Persistence.Repositories // Act repository.Save(user); - + var id = user.Id; var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(),TestObjects.GetGlobalSettings()); repository2.Delete(user); - + var resolved = repository2.Get((int) id); @@ -373,7 +372,7 @@ namespace Umbraco.Tests.Persistence.Repositories scope.Database.AsUmbracoDatabase().EnableSqlCount = false; } } - + } [Test] @@ -429,7 +428,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var user = MockedUser.CreateUser(); repository.Save(user); - + var group = MockedUserGroup.CreateUserGroup(); userGroupRepository.AddOrUpdateGroupWithUsers(@group, new[] { user.Id }); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs index 5f3a51f4f6..0dcc4bea99 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs @@ -195,7 +195,7 @@ namespace Umbraco.Tests.PublishedContent [Test] public void PublishedContentQueryTypedContentList() { - var query = new PublishedContentQuery(UmbracoContext.Current.ContentCache, UmbracoContext.Current.MediaCache, UmbracoContext.Current.VariationContextAccessor); + var query = new PublishedContentQuery(UmbracoContext.Current.PublishedSnapshot, UmbracoContext.Current.VariationContextAccessor); var result = query.Content(new[] { 1, 2, 4 }).ToArray(); Assert.AreEqual(2, result.Length); Assert.AreEqual(1, result[0].Id); diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 94cbf69b63..85c195e553 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -66,7 +66,7 @@ namespace Umbraco.Tests.Services ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); contentTypeService.Save(contentType); - var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", -1); + var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", Constants.System.Root); blueprint.SetValue("title", "blueprint 1"); blueprint.SetValue("bodyText", "blueprint 2"); blueprint.SetValue("keywords", "blueprint 3"); @@ -92,7 +92,7 @@ namespace Umbraco.Tests.Services ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); contentTypeService.Save(contentType); - var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", -1); + var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", Constants.System.Root); blueprint.SetValue("title", "blueprint 1"); blueprint.SetValue("bodyText", "blueprint 2"); blueprint.SetValue("keywords", "blueprint 3"); @@ -118,7 +118,7 @@ namespace Umbraco.Tests.Services ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); contentTypeService.Save(contentType); - var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", -1); + var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", Constants.System.Root); blueprint.SetValue("title", "blueprint 1"); blueprint.SetValue("bodyText", "blueprint 2"); blueprint.SetValue("keywords", "blueprint 3"); @@ -153,7 +153,7 @@ namespace Umbraco.Tests.Services for (int i = 0; i < 10; i++) { - var blueprint = MockedContent.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, -1); + var blueprint = MockedContent.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, Constants.System.Root); contentService.SaveBlueprint(blueprint); } @@ -264,7 +264,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act - var content = contentService.CreateAndSave("Test", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); content.ContentSchedule.Add(null, DateTime.Now.AddHours(2)); contentService.Save(content, Constants.Security.SuperUserId); @@ -292,7 +292,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act - var content = contentService.CreateAndSave("Test", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); for (var i = 0; i < 20; i++) { content.SetValue("bodyText", "hello world " + Guid.NewGuid()); @@ -317,7 +317,7 @@ namespace Umbraco.Tests.Services var results = new List(); for (var i = 0; i < 20; i++) { - results.Add(contentService.CreateAndSave("Test", -1, "umbTextpage", 0)); + results.Add(contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", 0)); } var sortedGet = contentService.GetByIds(new[] {results[10].Id, results[5].Id, results[12].Id}).ToArray(); @@ -337,7 +337,7 @@ namespace Umbraco.Tests.Services // Act for (int i = 0; i < 20; i++) { - contentService.CreateAndSave("Test", -1, "umbTextpage", Constants.Security.SuperUserId); + contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); } // Assert @@ -356,7 +356,7 @@ namespace Umbraco.Tests.Services // Act for (int i = 0; i < 20; i++) { - contentService.CreateAndSave("Test", -1, "umbBlah", Constants.Security.SuperUserId); + contentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); } // Assert @@ -371,7 +371,7 @@ namespace Umbraco.Tests.Services var contentTypeService = ServiceContext.ContentTypeService; var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); contentTypeService.Save(contentType); - var parent = contentService.CreateAndSave("Test", -1, "umbBlah", Constants.Security.SuperUserId); + var parent = contentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); // Act for (int i = 0; i < 20; i++) @@ -391,7 +391,7 @@ namespace Umbraco.Tests.Services var contentTypeService = ServiceContext.ContentTypeService; var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); contentTypeService.Save(contentType); - var parent = contentService.CreateAndSave("Test", -1, "umbBlah", Constants.Security.SuperUserId); + var parent = contentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); // Act IContent current = parent; @@ -425,7 +425,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act - var content = contentService.Create("Test", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); // Assert Assert.That(content, Is.Not.Null); @@ -439,7 +439,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act - var content = contentService.Create("Test", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); // Assert Assert.That(content, Is.Not.Null); @@ -453,12 +453,12 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act - var content = contentService.Create("Test", -1, "umbTextpage"); + var content = contentService.Create("Test", Constants.System.Root, "umbTextpage"); // Assert Assert.That(content, Is.Not.Null); Assert.That(content.HasIdentity, Is.False); - Assert.That(content.CreatorId, Is.EqualTo(0)); //Default to 0 (unknown) since we didn't explicitly set this in the Create call + Assert.That(content.CreatorId, Is.EqualTo(Constants.Security.SuperUserId)); //Default to -1 aka SuperUser (unknown) since we didn't explicitly set this in the Create call } [Test] @@ -472,7 +472,7 @@ namespace Umbraco.Tests.Services RawPasswordValue = "test" }; ServiceContext.UserService.Save(user); - var content = new Content("Test", -1, ServiceContext.ContentTypeService.Get("umbTextpage")); + var content = new Content("Test", Constants.System.Root, ServiceContext.ContentTypeService.Get("umbTextpage")); // Act ServiceContext.ContentService.Save(content, (int)user.Id); @@ -489,7 +489,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; // Act & Assert - Assert.Throws(() => contentService.Create("Test", -1, "umbAliasDoesntExist")); + Assert.Throws(() => contentService.Create("Test", Constants.System.Root, "umbAliasDoesntExist")); } [Test] @@ -497,7 +497,7 @@ namespace Umbraco.Tests.Services { // Arrange var contentService = ServiceContext.ContentService; - var content = new Content(string.Empty, -1, ServiceContext.ContentTypeService.Get("umbTextpage")); + var content = new Content(string.Empty, Constants.System.Root, ServiceContext.ContentTypeService.Get("umbTextpage")); // Act & Assert Assert.Throws(() => contentService.Save(content)); @@ -727,7 +727,7 @@ namespace Umbraco.Tests.Services contentType.Variations = ContentVariation.Culture; ServiceContext.ContentTypeService.Save(contentType); - IContent content = new Content("content", -1, contentType); + IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-fr", langFr.IsoCode); content.SetCultureName("content-en", langUk.IsoCode); content.PublishCulture(langFr.IsoCode); @@ -779,7 +779,7 @@ namespace Umbraco.Tests.Services ServiceContext.ContentTypeService.Save(contentType); - IContent content = new Content("content", -1, contentType); + IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-en", langGB.IsoCode); content.SetCultureName("content-fr", langFr.IsoCode); @@ -821,7 +821,7 @@ namespace Umbraco.Tests.Services contentType.Variations = ContentVariation.Culture; ServiceContext.ContentTypeService.Save(contentType); - IContent content = new Content("content", -1, contentType); + IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-fr", langFr.IsoCode); var published = ServiceContext.ContentService.SaveAndPublish(content, langFr.IsoCode); //audit log will only show that french was published @@ -852,7 +852,7 @@ namespace Umbraco.Tests.Services contentType.Variations = ContentVariation.Culture; ServiceContext.ContentTypeService.Save(contentType); - IContent content = new Content("content", -1, contentType); + IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-fr", langFr.IsoCode); content.SetCultureName("content-gb", langGB.IsoCode); var published = ServiceContext.ContentService.SaveAndPublish(content, new[] {langGB.IsoCode, langFr.IsoCode}); @@ -910,7 +910,7 @@ namespace Umbraco.Tests.Services { // Arrange var contentService = ServiceContext.ContentService; - var parent = contentService.Create("parent", -1, "umbTextpage"); + var parent = contentService.Create("parent", Constants.System.Root, "umbTextpage"); contentService.SaveAndPublish(parent); var content = contentService.Create("child", parent, "umbTextpage"); @@ -1235,7 +1235,7 @@ namespace Umbraco.Tests.Services { // Arrange var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); content.SetValue("author", "Barack Obama"); // Act @@ -1574,7 +1574,7 @@ namespace Umbraco.Tests.Services var contentType = MockedContentTypes.CreateAllTypesContentType("test", "test"); ServiceContext.ContentTypeService.Save(contentType, Constants.Security.SuperUserId); - + object obj = new { @@ -1730,7 +1730,7 @@ namespace Umbraco.Tests.Services ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! ServiceContext.ContentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType, "Simple Tags Page", -1); + var content = MockedContent.CreateSimpleContent(contentType, "Simple Tags Page", Constants.System.Root); content.AssignTags(propAlias, new[] {"hello", "world"}); contentService.Save(content); @@ -1906,7 +1906,7 @@ namespace Umbraco.Tests.Services ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! ServiceContext.ContentTypeService.Save(contentType); - var page = new Content("Page", -1, contentType) + var page = new Content("Page", Constants.System.Root, contentType) { Level = 1, SortOrder = 1, @@ -2133,7 +2133,7 @@ namespace Umbraco.Tests.Services var contentType = MockedContentTypes.CreateAllTypesContentType("allDataTypes", "All DataTypes"); contentTypeService.Save(contentType); var contentService = ServiceContext.ContentService; - var content = MockedContent.CreateAllTypesContent(contentType, "Random Content", -1); + var content = MockedContent.CreateAllTypesContent(contentType, "Random Content", Constants.System.Root); contentService.Save(content); var id = content.Id; @@ -2186,7 +2186,7 @@ namespace Umbraco.Tests.Services public void Ensure_Content_Xml_Created() { var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); content.SetValue("author", "Barack Obama"); contentService.Save(content); @@ -2208,7 +2208,7 @@ namespace Umbraco.Tests.Services public void Ensure_Preview_Xml_Created() { var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", -1, "umbTextpage", Constants.Security.SuperUserId); + var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); content.SetValue("author", "Barack Obama"); contentService.Save(content); @@ -2236,10 +2236,10 @@ namespace Umbraco.Tests.Services } long total; - var entities = service.GetPagedChildren(-1, 0, 6, out total).ToArray(); + var entities = service.GetPagedChildren(Constants.System.Root, 0, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedChildren(-1, 1, 6, out total).ToArray(); + entities = service.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); } @@ -2271,10 +2271,10 @@ namespace Umbraco.Tests.Services long total; // children in root including the folder - not the descendants in the folder - var entities = service.GetPagedChildren(-1, 0, 6, out total).ToArray(); + var entities = service.GetPagedChildren(Constants.System.Root, 0, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedChildren(-1, 1, 6, out total).ToArray(); + entities = service.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); @@ -2290,7 +2290,7 @@ namespace Umbraco.Tests.Services [Test] public void PublishingTest() { - var contentType = new ContentType(-1) + var contentType = new ContentType(Constants.System.Root) { Alias = "foo", Name = "Foo" @@ -2308,7 +2308,7 @@ namespace Umbraco.Tests.Services ServiceContext.ContentTypeService.Save(contentType); var contentService = ServiceContext.ContentService; - var content = contentService.Create("foo", -1, "foo"); + var content = contentService.Create("foo", Constants.System.Root, "foo"); contentService.Save(content); Assert.IsFalse(content.Published); @@ -2436,7 +2436,7 @@ namespace Umbraco.Tests.Services contentTypeService.Save(contentType); var contentService = ServiceContext.ContentService; - var content = new Content(null, -1, contentType); + var content = new Content(null, Constants.System.Root, contentType); content.SetCultureName("name-us", langUk.IsoCode); content.SetCultureName("name-fr", langFr.IsoCode); @@ -2471,7 +2471,7 @@ namespace Umbraco.Tests.Services var contentService = ServiceContext.ContentService; - var content = new Content(null, -1, contentType); + var content = new Content(null, Constants.System.Root, contentType); content.SetCultureName("root", langUk.IsoCode); contentService.Save(content); @@ -2513,13 +2513,13 @@ namespace Umbraco.Tests.Services var o = new[] { 2, 1, 3, 0, 4 }; // randomly different for (var i = 0; i < 5; i++) { - var contentA = new Content(null, -1, contentType); + var contentA = new Content(null, Constants.System.Root, contentType); contentA.SetCultureName("contentA" + i + "uk", langUk.IsoCode); contentA.SetCultureName("contentA" + o[i] + "fr", langFr.IsoCode); contentA.SetCultureName("contentX" + i + "da", langDa.IsoCode); contentService.Save(contentA); - var contentB = new Content(null, -1, contentType); + var contentB = new Content(null, Constants.System.Root, contentType); contentB.SetCultureName("contentB" + i + "uk", langUk.IsoCode); contentB.SetCultureName("contentB" + o[i] + "fr", langFr.IsoCode); contentB.SetCultureName("contentX" + i + "da", langDa.IsoCode); @@ -2527,7 +2527,7 @@ namespace Umbraco.Tests.Services } // get all - var list = contentService.GetPagedChildren(-1, 0, 100, out var total).ToList(); + var list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out var total).ToList(); Console.WriteLine("ALL"); WriteList(list); @@ -2537,7 +2537,7 @@ namespace Umbraco.Tests.Services Assert.AreEqual(11, list.Count); // filter - list = contentService.GetPagedChildren(-1, 0, 100, out total, + list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, SqlContext.Query().Where(x => x.Name.Contains("contentX")), Ordering.By("name", culture: langFr.IsoCode)).ToList(); @@ -2545,7 +2545,7 @@ namespace Umbraco.Tests.Services Assert.AreEqual(0, list.Count); // filter - list = contentService.GetPagedChildren(-1, 0, 100, out total, + list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, SqlContext.Query().Where(x => x.Name.Contains("contentX")), Ordering.By("name", culture: langDa.IsoCode)).ToList(); @@ -2556,7 +2556,7 @@ namespace Umbraco.Tests.Services Assert.AreEqual(10, list.Count); // filter - list = contentService.GetPagedChildren(-1, 0, 100, out total, + list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, SqlContext.Query().Where(x => x.Name.Contains("contentA")), Ordering.By("name", culture: langFr.IsoCode)).ToList(); @@ -2569,7 +2569,7 @@ namespace Umbraco.Tests.Services for (var i = 0; i < 5; i++) Assert.AreEqual("contentA" + i + "fr", list[i].GetCultureName(langFr.IsoCode)); - list = contentService.GetPagedChildren(-1, 0, 100, out total, + list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, SqlContext.Query().Where(x => x.Name.Contains("contentA")), Ordering.By("name", direction: Direction.Descending, culture: langFr.IsoCode)).ToList(); @@ -2614,7 +2614,7 @@ namespace Umbraco.Tests.Services contentTypeService.Save(contentType); var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", -1, "umbTextpage"); + var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage"); // creating content with a name but no culture - will set the invariant name // but, because that content is variant, as soon as we save, we'll need to diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 1319d00c48..7a7aad6905 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -554,7 +554,6 @@ namespace Umbraco.Tests.Services IContent contentItem = MockedContent.CreateTextpageContent(contentType1, "Testing", -1); ServiceContext.ContentService.SaveAndPublish(contentItem); var initProps = contentItem.Properties.Count; - var initPropTypes = contentItem.PropertyTypes.Count(); //remove a property contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias); @@ -563,7 +562,6 @@ namespace Umbraco.Tests.Services //re-load it from the db contentItem = ServiceContext.ContentService.GetById(contentItem.Id); - Assert.AreEqual(initPropTypes - 1, contentItem.PropertyTypes.Count()); Assert.AreEqual(initProps - 1, contentItem.Properties.Count); } diff --git a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs index 459daa3da6..5f4a87c3eb 100644 --- a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs @@ -83,7 +83,6 @@ namespace Umbraco.Tests.Services IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); ServiceContext.MemberService.Save(member); var initProps = member.Properties.Count; - var initPropTypes = member.PropertyTypes.Count(); //remove a property (NOT ONE OF THE DEFAULTS) var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); @@ -93,7 +92,6 @@ namespace Umbraco.Tests.Services //re-load it from the db member = ServiceContext.MemberService.GetById(member.Id); - Assert.AreEqual(initPropTypes - 1, member.PropertyTypes.Count()); Assert.AreEqual(initProps - 1, member.Properties.Count); } diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestProfiler.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestProfiler.cs index 0ffcfb7a3f..39cac6e24f 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestProfiler.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestProfiler.cs @@ -33,15 +33,20 @@ namespace Umbraco.Tests.TestHelpers.Stubs { if (_enabled == false) return; - MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter(); - MiniProfiler.Settings.StackMaxLength = 5000; - MiniProfiler.Start(); + //see https://miniprofiler.com/dotnet/AspDotNet + MiniProfiler.Configure(new MiniProfilerOptions + { + SqlFormatter = new SqlServerFormatter(), + StackMaxLength = 5000, + }); + + MiniProfiler.StartNew(); } public void Stop(bool discardResults = false) { if (_enabled) - MiniProfiler.Stop(discardResults); + MiniProfiler.Current.Stop(discardResults); } } } diff --git a/src/Umbraco.Tests/Testing/ContentBaseExtensions.cs b/src/Umbraco.Tests/Testing/ContentBaseExtensions.cs index 58d4dfbd7f..d33818a31b 100644 --- a/src/Umbraco.Tests/Testing/ContentBaseExtensions.cs +++ b/src/Umbraco.Tests/Testing/ContentBaseExtensions.cs @@ -1,13 +1,17 @@ using System; using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Composing; using Umbraco.Core.Models; +using Umbraco.Core.Services; namespace Umbraco.Tests.Testing { public static class ContentBaseExtensions { + /// - /// Set property values by alias with an annonymous object. + /// Set property values by alias with an anonymous object. /// /// Does not support variants. public static void PropertyValues(this IContentBase content, object value, string culture = null, string segment = null) @@ -18,26 +22,12 @@ namespace Umbraco.Tests.Testing var propertyInfos = value.GetType().GetProperties(); foreach (var propertyInfo in propertyInfos) { - //Check if a PropertyType with alias exists thus being a valid property - var propertyType = content.PropertyTypes.FirstOrDefault(x => x.Alias == propertyInfo.Name); - if (propertyType == null) + if (!content.Properties.TryGetValue(propertyInfo.Name, out var property)) throw new Exception($"The property alias {propertyInfo.Name} is not valid, because no PropertyType with this alias exists"); - //Check if a Property with the alias already exists in the collection thus being updated or inserted - var item = content.Properties.FirstOrDefault(x => x.Alias == propertyInfo.Name); - if (item != null) - { - item.SetValue(propertyInfo.GetValue(value, null), culture, segment); - //Update item with newly added value - content.Properties.Add(item); - } - else - { - //Create new Property to add to collection - var property = propertyType.CreateProperty(); - property.SetValue(propertyInfo.GetValue(value, null), culture, segment); - content.Properties.Add(property); - } + property.SetValue(propertyInfo.GetValue(value, null), culture, segment); + //Update item with newly added value + content.Properties.Add(property); } } } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 3bfc3387fe..e88aa5ae61 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -78,40 +78,39 @@ - - + + - 1.8.9 + 1.8.14 - + - - - - - - - - - - + + + + + + + + + + - - + + - - - + + + - + - - + diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index 6fe921e13f..f7b1799d63 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -110,7 +110,7 @@ namespace Umbraco.Tests.UmbracoExamine m.GetCultureName(It.IsAny()) == (string)x.Attribute("nodeName") && m.Path == (string)x.Attribute("path") && m.Properties == new PropertyCollection() && - m.ContentType == Mock.Of(mt => + m.ContentType == Mock.Of(mt => mt.Alias == (string)x.Attribute("nodeTypeAlias") && mt.Id == (int)x.Attribute("nodeType")))) .ToArray(); diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs index 37600e2f89..d0c09d3340 100644 --- a/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs @@ -43,6 +43,14 @@ namespace Umbraco.Tests.Web.Controllers [UmbracoTest(Database = UmbracoTestOptions.Database.None)] public class ContentControllerTests : TestWithDatabaseBase { + private IContentType _contentTypeForMockedContent; + + public override void SetUp() + { + base.SetUp(); + _contentTypeForMockedContent = null; + } + protected override void ComposeApplication(bool withApplication) { base.ComposeApplication(withApplication); @@ -115,23 +123,42 @@ namespace Umbraco.Tests.Web.Controllers }; } - private IContent GetMockedContent() + private IContentType GetMockedContentType() { - var content = MockedContent.CreateSimpleContent(MockedContentTypes.CreateSimpleContentType()); - content.Id = 123; - content.Path = "-1,123"; + var contentType = MockedContentTypes.CreateSimpleContentType(); //ensure things have ids var ids = 888; - foreach (var g in content.PropertyGroups) + foreach (var g in contentType.CompositionPropertyGroups) { g.Id = ids; ids++; } - foreach (var p in content.PropertyTypes) + foreach (var p in contentType.CompositionPropertyGroups) { p.Id = ids; ids++; } + + return contentType; + } + + private IContent GetMockedContent() + { + if (_contentTypeForMockedContent == null) + { + _contentTypeForMockedContent = GetMockedContentType(); + Mock.Get(Current.Services.ContentTypeService) + .Setup(x => x.Get(_contentTypeForMockedContent.Id)) + .Returns(_contentTypeForMockedContent); + Mock.Get(Current.Services.ContentTypeService) + .As() + .Setup(x => x.Get(_contentTypeForMockedContent.Id)) + .Returns(_contentTypeForMockedContent); + } + + var content = MockedContent.CreateSimpleContent(_contentTypeForMockedContent); + content.Id = 123; + content.Path = "-1,123"; return content; } @@ -229,7 +256,7 @@ namespace Umbraco.Tests.Web.Controllers Factory.GetInstance(), Factory.GetInstance(), helper); - + return controller; } @@ -251,9 +278,6 @@ namespace Umbraco.Tests.Web.Controllers { ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { - var contentServiceMock = Mock.Get(Current.Services.ContentService); - contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent()); - var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); var controller = new ContentController( propertyEditorCollection, @@ -336,15 +360,11 @@ namespace Umbraco.Tests.Web.Controllers ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { - var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => content); contentServiceMock.Setup(x => x.Save(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success - var contentTypeServiceMock = Mock.Get(Current.Services.ContentTypeService); - contentTypeServiceMock.Setup(x => x.Get(content.ContentTypeId)).Returns(() => MockedContentTypes.CreateSimpleContentType()); - var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); var controller = new ContentController( propertyEditorCollection, @@ -369,8 +389,6 @@ namespace Umbraco.Tests.Web.Controllers Assert.AreEqual(HttpStatusCode.OK, response.Item1.StatusCode); var display = JsonConvert.DeserializeObject(response.Item2); Assert.AreEqual(1, display.Variants.Count()); - Assert.AreEqual(content.PropertyGroups.Count(), display.Variants.ElementAt(0).Tabs.Count()); - Assert.AreEqual(content.PropertyTypes.Count(), display.Variants.ElementAt(0).Tabs.ElementAt(0).Properties.Count()); } [Test] @@ -380,15 +398,11 @@ namespace Umbraco.Tests.Web.Controllers ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { - var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => content); contentServiceMock.Setup(x => x.Save(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success - var contentTypeServiceMock = Mock.Get(Current.Services.ContentTypeService); - contentTypeServiceMock.Setup(x => x.Get(content.ContentTypeId)).Returns(() => MockedContentTypes.CreateSimpleContentType()); - var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); var controller = new ContentController( propertyEditorCollection, @@ -428,15 +442,11 @@ namespace Umbraco.Tests.Web.Controllers ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper) { - var contentServiceMock = Mock.Get(Current.Services.ContentService); contentServiceMock.Setup(x => x.GetById(123)).Returns(() => content); contentServiceMock.Setup(x => x.Save(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new OperationResult(OperationResultType.Success, new Core.Events.EventMessages())); //success - var contentTypeServiceMock = Mock.Get(Current.Services.ContentTypeService); - contentTypeServiceMock.Setup(x => x.Get(content.ContentTypeId)).Returns(() => MockedContentTypes.CreateSimpleContentType()); - var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); var controller = new ContentController( propertyEditorCollection, diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js index 5006087ca5..14c9878839 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js @@ -105,11 +105,6 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se return; } - if (scope.userDialog) { - closeUserDialog(); - } - - navigationService.hideSearch(); navigationService.showTree(section.alias); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 06a147969a..a043b292ef 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -3,7 +3,7 @@ function ContentNodeInfoDirective($timeout, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource, overlayService) { - function link(scope, umbVariantContentCtrl) { + function link(scope) { var evts = []; var isInfoTab = false; @@ -96,22 +96,17 @@ scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id; } - //load in the audit trail if we are currently looking at the INFO tab - if (umbVariantContentCtrl && umbVariantContentCtrl.editor) { - var activeApp = _.find(umbVariantContentCtrl.editor.content.apps, a => a.active); - if (activeApp && activeApp.alias === "umbInfo") { - isInfoTab = true; - loadAuditTrail(); - loadRedirectUrls(); - } + var activeApp = _.find(scope.node.apps, (a) => a.active); + if (activeApp.alias === "umbInfo") { + loadRedirectUrls(); + loadAuditTrail(); } } scope.auditTrailPageChange = function (pageNumber) { scope.auditTrailOptions.pageNumber = pageNumber; - auditTrailLoaded = false; - loadAuditTrail(); + loadAuditTrail(true); }; scope.openDocumentType = function (documentType) { @@ -192,10 +187,12 @@ editorService.rollback(rollback); }; - function loadAuditTrail() { + function loadAuditTrail(forceReload) { //don't load this if it's already done - if (auditTrailLoaded) { return; }; + if (auditTrailLoaded && !forceReload) { + return; + } scope.loadingAuditTrail = true; @@ -334,8 +331,7 @@ if (newValue === oldValue) { return; } if (isInfoTab) { - auditTrailLoaded = false; - loadAuditTrail(); + loadAuditTrail(true); loadRedirectUrls(); setNodePublishStatus(); updateCurrentUrls(); diff --git a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js index 1bae002df9..eabb611320 100644 --- a/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js +++ b/src/Umbraco.Web.UI.Client/src/common/interceptors/donotpostdollarvariablesrequest.interceptor.js @@ -5,11 +5,11 @@ for (var property in obj) { if (obj.hasOwnProperty(property)) { - if (property.startsWith(propertyPrefix) && obj[property]) { + if (property.startsWith(propertyPrefix) && obj[property] !== undefined) { obj[property] = undefined; } - if (typeof obj[property] == "object") { + if (typeof obj[property] === "object") { removeProperty(obj[property], propertyPrefix); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js index 9fbbad8f09..099439fa4b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypesettings/datatypesettings.controller.js @@ -10,7 +10,7 @@ (function () { "use strict"; - function DataTypeSettingsController($scope, dataTypeResource, dataTypeHelper, localizationService) { + function DataTypeSettingsController($scope, dataTypeResource, dataTypeHelper, localizationService, notificationsService, overlayService, formHelper) { var vm = this; @@ -102,7 +102,7 @@ vm.saveButtonState = "busy"; var preValues = dataTypeHelper.createPreValueProps(vm.dataType.preValues); - + dataTypeResource.save(vm.dataType, preValues, $scope.model.create).then(function(newDataType) { $scope.model.dataType = newDataType; vm.saveButtonState = "success"; @@ -110,6 +110,19 @@ if ($scope.model && $scope.model.submit) { $scope.model.submit($scope.model); } + }, function(err) { + vm.saveButtonState = "error"; + + if(err.status === 400) { + if (err.data && (err.data.ModelState)) { + + formHelper.handleServerValidation(err.data.ModelState); + + for (var e in err.data.ModelState) { + notificationsService.error("Validation", err.data.ModelState[e][0]); + } + } + } }); } @@ -120,4 +133,4 @@ angular.module("umbraco").controller("Umbraco.Editors.DataTypeSettingsController", DataTypeSettingsController); -})(); \ No newline at end of file +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js index 2a00df32dc..19057fa842 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js @@ -96,7 +96,7 @@ angular.module("umbraco") $scope.layoutConfigOverlay.rows = $scope.model.value.layouts; $scope.layoutConfigOverlay.columns = $scope.model.value.columns; $scope.layoutConfigOverlay.show = true; - + $scope.layoutConfigOverlay.submit = function(model) { $scope.layoutConfigOverlay.show = false; $scope.layoutConfigOverlay = null; @@ -218,8 +218,8 @@ angular.module("umbraco") $scope.editConfigCollectionOverlay.show = true; $scope.editConfigCollectionOverlay.submit = function(model) { - - callback(model.config) + + callback(model.config); $scope.editConfigCollectionOverlay.show = false; $scope.editConfigCollectionOverlay = null; diff --git a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.controller.js b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.controller.js index 942b79eabd..b0e0c303cf 100644 --- a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.controller.js +++ b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.controller.js @@ -1,28 +1,35 @@ -function modelsBuilderController($scope, umbRequestHelper, $log, $http, modelsBuilderResource) { +function modelsBuilderController($scope, $http, umbRequestHelper, modelsBuilderResource) { - $scope.generate = function() { - $scope.generating = true; + var vm = this; + + vm.reload = reload; + vm.generate = generate; + vm.dashboard = null; + + function generate() { + vm.generating = true; umbRequestHelper.resourcePromise( $http.post(umbRequestHelper.getApiUrl("modelsBuilderBaseUrl", "BuildModels")), 'Failed to generate.') .then(function (result) { - $scope.generating = false; - $scope.dashboard = result; + vm.generating = false; + vm.dashboard = result; }); - }; + } - $scope.reload = function () { - $scope.ready = false; + function reload() { + vm.loading = true; modelsBuilderResource.getDashboard().then(function (result) { - $scope.dashboard = result; - $scope.ready = true; + vm.dashboard = result; + vm.loading = false; }); - }; + } function init() { - modelsBuilderResource.getDashboard().then(function(result) { - $scope.dashboard = result; - $scope.ready = true; + vm.loading = true; + modelsBuilderResource.getDashboard().then(function (result) { + vm.dashboard = result; + vm.loading = false; }); } diff --git a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.htm b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.htm deleted file mode 100644 index eeca93bf3a..0000000000 --- a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.htm +++ /dev/null @@ -1,41 +0,0 @@ -
- -
- -
- -

Models Builder

- -
- Loading... -
- -
-
- -
-

Models are out-of-date. -

-
- -
-
-

Generating models will restart the application.

-
-
- -
-
-
-
-
- -
- Last generation failed with the following error: -
{{dashboard.lastError}}
-
-
- -
diff --git a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.html b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.html new file mode 100644 index 0000000000..0c10c33e39 --- /dev/null +++ b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/modelsbuilder.html @@ -0,0 +1,44 @@ +
+ + + + +
+ +
+ +

Models Builder

+ + + +
+
+ +
+

Models are out-of-date.

+
+ +
+
+

Generating models will restart the application.

+
+
+ +
+
+
+
+
+ +
+ Last generation failed with the following error: +
{{vm.dashboard.lastError}}
+
+
+ +
+
+ +
diff --git a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/package.manifest b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/package.manifest index d83523517a..5e64177046 100644 --- a/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/package.manifest +++ b/src/Umbraco.Web.UI/App_Plugins/ModelsBuilder/package.manifest @@ -1,7 +1,18 @@ { - //array of files we want to inject into the application on app_start - javascript: [ - '~/App_Plugins/ModelsBuilder/modelsbuilder.controller.js', - '~/App_Plugins/ModelsBuilder/modelsbuilder.resource.js' + // array of files we want to inject into the application + "javascript": [ + "~/App_Plugins/ModelsBuilder/modelsbuilder.controller.js", + "~/App_Plugins/ModelsBuilder/modelsbuilder.resource.js" + ], + + // models builder dashboard + "dashboards": [ + { + "alias": "settingsModelsBuilder", + "name": "Models Builder", + "view": "/App_Plugins/ModelsBuilder/modelsbuilder.html", + "sections": [ "settings" ], + "weight": 40 + } ] } \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 7c3293183d..3658ef7066 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -83,7 +83,7 @@
- + @@ -91,21 +91,21 @@ - - + + all - - - - - + + + + + - 8.0.0-alpha.36 + 8.0.0-alpha.37 @@ -141,7 +141,7 @@ Settings.settings
- + diff --git a/src/Umbraco.Web.UI/web.Template.Debug.config b/src/Umbraco.Web.UI/web.Template.Debug.config index 8c4b3bb299..ff42f098f7 100644 --- a/src/Umbraco.Web.UI/web.Template.Debug.config +++ b/src/Umbraco.Web.UI/web.Template.Debug.config @@ -25,4 +25,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index d93089fe21..f0abbfde52 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -215,23 +215,23 @@ - + - + - + - + - + @@ -239,16 +239,20 @@ - + - + + + + + diff --git a/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs b/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs deleted file mode 100644 index 44bc00cb6f..0000000000 --- a/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Umbraco.Core.Composing; -using Umbraco.Core.Dashboards; - -namespace Umbraco.Web.Dashboards -{ - [Weight(40)] - public class ModelsBuilderDashboard : IDashboard - { - public string Alias => "settingsModelsBuilder"; - - public string[] Sections => new [] { "settings" }; - - public string View => "/App_Plugins/ModelsBuilder/modelsbuilder.htm"; - - public IAccessRule[] AccessRules => Array.Empty(); - } - - -} diff --git a/src/Umbraco.Web/Editors/Binders/MemberBinder.cs b/src/Umbraco.Web/Editors/Binders/MemberBinder.cs index 393fab98a9..bceba2e04d 100644 --- a/src/Umbraco.Web/Editors/Binders/MemberBinder.cs +++ b/src/Umbraco.Web/Editors/Binders/MemberBinder.cs @@ -169,7 +169,8 @@ namespace Umbraco.Web.Editors.Binders var member = MemberService.CreateGenericMembershipProviderMember(model.Name, model.Email, model.Username, Guid.NewGuid().ToString("N")); //we'll just remove all properties here otherwise we'll end up with validation errors, we don't want to persist any property data anyways // in this case. - FilterContentTypeProperties(member.ContentType, member.ContentType.PropertyTypes.Select(x => x.Alias).ToArray()); + memberType = _services.MemberTypeService.Get(member.ContentTypeId); + FilterContentTypeProperties(memberType, memberType.PropertyTypes.Select(x => x.Alias).ToArray()); return member; } } diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index b89257307a..27d63d9d7a 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1830,8 +1830,10 @@ namespace Umbraco.Web.Editors } if (model.ParentId < 0) { - //cannot move if the content item is not allowed at the root - if (toMove.ContentType.AllowedAsRoot == false) + //cannot move if the content item is not allowed at the root unless there are + //none allowed at root (in which case all should be allowed at root) + var contentTypeService = Services.ContentTypeService; + if (toMove.ContentType.AllowedAsRoot == false && contentTypeService.GetAll().Any(ct => ct.AllowedAsRoot)) { throw new HttpResponseException( Request.CreateNotificationValidationErrorResponse( @@ -1846,8 +1848,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var contentTypeService = Services.ContentTypeBaseServices.For(parent); - var parentContentType = contentTypeService.Get(parent.ContentTypeId); + var parentContentType = Services.ContentTypeService.Get(parent.ContentTypeId); //check if the item is allowed under this one if (parentContentType.AllowedContentTypes.Select(x => x.Id).ToArray() .Any(x => x.Value == toMove.ContentType.Id) == false) diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 1f5feb8ad9..8a56c87ad9 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -393,7 +393,11 @@ namespace Umbraco.Web.Editors IEnumerable types; if (contentId == Constants.System.Root) { - types = Services.ContentTypeService.GetAll().Where(x => x.AllowedAsRoot).ToList(); + var allContentTypes = Services.ContentTypeService.GetAll().ToList(); + bool AllowedAsRoot(IContentType x) => x.AllowedAsRoot; + types = allContentTypes.Any(AllowedAsRoot) + ? allContentTypes.Where(AllowedAsRoot).ToList() + : allContentTypes; } else { @@ -403,8 +407,7 @@ namespace Umbraco.Web.Editors return Enumerable.Empty(); } - var contentTypeService = Services.ContentTypeBaseServices.For(contentItem); - var contentType = contentTypeService.Get(contentItem.ContentTypeId); + var contentType = Services.ContentTypeBaseServices.GetContentTypeOf(contentItem); var ids = contentType.AllowedContentTypes.Select(x => x.Id.Value).ToArray(); if (ids.Any() == false) return Enumerable.Empty(); diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 55604e0eb9..d89909d793 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -14,6 +14,7 @@ using System.Reflection; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using System.Web.Http.Controllers; +using System.Web.Http.ModelBinding; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; @@ -605,8 +606,7 @@ namespace Umbraco.Web.Editors } } - [HttpQueryStringFilter("queryStrings")] - public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, FormDataCollection queryStrings) + public IEnumerable GetAncestors(int id, UmbracoEntityTypes type, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings) { return GetResultForAncestors(id, type, queryStrings); } diff --git a/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs index 619bd76333..c99bc64e23 100644 --- a/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs @@ -1,10 +1,7 @@ -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Web.Http.Controllers; +using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Core.Logging; -using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Models.ContentEditing; @@ -17,21 +14,23 @@ namespace Umbraco.Web.Editors.Filters { private readonly ILogger _logger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IMemberTypeService _memberTypeService; - public MemberSaveValidationAttribute() : this(Current.Logger, Current.UmbracoContextAccessor) - { - } + public MemberSaveValidationAttribute() + : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.MemberTypeService) + { } - public MemberSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) + public MemberSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IMemberTypeService memberTypeService) { _logger = logger; _umbracoContextAccessor = umbracoContextAccessor; + _memberTypeService = memberTypeService; } public override void OnActionExecuting(HttpActionContext actionContext) { var model = (MemberSave)actionContext.ActionArguments["contentItem"]; - var contentItemValidator = new MemberValidationHelper(_logger, _umbracoContextAccessor); + var contentItemValidator = new MemberValidationHelper(_logger, _umbracoContextAccessor, _memberTypeService); //now do each validation step if (contentItemValidator.ValidateExistingContent(model, actionContext)) if (contentItemValidator.ValidateProperties(model, model, actionContext)) diff --git a/src/Umbraco.Web/Editors/Filters/MemberValidationHelper.cs b/src/Umbraco.Web/Editors/Filters/MemberValidationHelper.cs index 74fcac60ea..ac72019cdf 100644 --- a/src/Umbraco.Web/Editors/Filters/MemberValidationHelper.cs +++ b/src/Umbraco.Web/Editors/Filters/MemberValidationHelper.cs @@ -9,43 +9,23 @@ using System.Web.Security; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Editors.Filters { - //internal class ContentValidationHelper : ContentItemValidationHelper - //{ - // public ContentValidationHelper(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, umbracoContextAccessor) - // { - // } - - // /// - // /// Validates that the correct information is in the request for saving a culture variant - // /// - // /// - // /// - // /// - // protected override bool ValidateCultureVariant(ContentItemSave postedItem, HttpActionContext actionContext) - // { - // var contentType = postedItem.PersistedContent.GetContentType(); - // if (contentType.VariesByCulture() && postedItem.Culture.IsNullOrWhiteSpace()) - // { - // //we cannot save a content item that is culture variant if no culture was specified in the request! - // actionContext.Response = actionContext.Request.CreateValidationErrorResponse($"No culture found in request. Cannot save a content item that varies by culture, without a specified culture."); - // return false; - // } - // return true; - // } - //} - /// /// Custom validation helper so that we can exclude the Member.StandardPropertyTypeStubs from being validating for existence /// internal class MemberValidationHelper : ContentItemValidationHelper { - public MemberValidationHelper(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, umbracoContextAccessor) + private readonly IMemberTypeService _memberTypeService; + + public MemberValidationHelper(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IMemberTypeService memberTypeService) + : base(logger, umbracoContextAccessor) { + _memberTypeService = memberTypeService; } /// @@ -117,8 +97,9 @@ namespace Umbraco.Web.Editors.Filters //if a sensitive value is being submitted. if (UmbracoContextAccessor.UmbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false) { - var sensitiveProperties = model.PersistedContent.ContentType - .PropertyTypes.Where(x => model.PersistedContent.ContentType.IsSensitiveProperty(x.Alias)) + var contentType = _memberTypeService.Get(model.PersistedContent.ContentTypeId); + var sensitiveProperties = contentType + .PropertyTypes.Where(x => contentType.IsSensitiveProperty(x.Alias)) .ToList(); foreach (var sensitiveProperty in sensitiveProperties) diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index ee7f1cc9cd..fb6ca39289 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -870,8 +870,10 @@ namespace Umbraco.Web.Editors } if (model.ParentId < 0) { - //cannot move if the content item is not allowed at the root - if (toMove.ContentType.AllowedAsRoot == false) + //cannot move if the content item is not allowed at the root unless there are + //none allowed at root (in which case all should be allowed at root) + var mediaTypeService = Services.MediaTypeService; + if (toMove.ContentType.AllowedAsRoot == false && mediaTypeService.GetAll().Any(ct => ct.AllowedAsRoot)) { var notificationModel = new SimpleNotificationModel(); notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedAtRoot"), ""); @@ -887,7 +889,8 @@ namespace Umbraco.Web.Editors } //check if the item is allowed under this one - if (parent.ContentType.AllowedContentTypes.Select(x => x.Id).ToArray() + var parentContentType = Services.MediaTypeService.Get(parent.ContentTypeId); + if (parentContentType.AllowedContentTypes.Select(x => x.Id).ToArray() .Any(x => x.Value == toMove.ContentType.Id) == false) { var notificationModel = new SimpleNotificationModel(); diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs index d041db1862..c85ef439dd 100644 --- a/src/Umbraco.Web/Editors/MediaTypeController.cs +++ b/src/Umbraco.Web/Editors/MediaTypeController.cs @@ -230,7 +230,8 @@ namespace Umbraco.Web.Editors return Enumerable.Empty(); } - var ids = contentItem.ContentType.AllowedContentTypes.Select(x => x.Id.Value).ToArray(); + var contentType = Services.MediaTypeService.Get(contentItem.ContentTypeId); + var ids = contentType.AllowedContentTypes.Select(x => x.Id.Value).ToArray(); if (ids.Any() == false) return Enumerable.Empty(); diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 5a11f6cda9..cdc1fd3ce1 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -435,8 +435,9 @@ namespace Umbraco.Web.Editors //There's only 3 special ones we need to deal with that are part of the MemberSave instance if (Security.CurrentUser.HasAccessToSensitiveData() == false) { - var sensitiveProperties = contentItem.PersistedContent.ContentType - .PropertyTypes.Where(x => contentItem.PersistedContent.ContentType.IsSensitiveProperty(x.Alias)) + var memberType = Services.MemberTypeService.Get(contentItem.PersistedContent.ContentTypeId); + var sensitiveProperties = memberType + .PropertyTypes.Where(x => memberType.IsSensitiveProperty(x.Alias)) .ToList(); foreach (var sensitiveProperty in sensitiveProperties) diff --git a/src/Umbraco.Web/Logging/WebProfiler.cs b/src/Umbraco.Web/Logging/WebProfiler.cs index e31ef75209..14c1bb065f 100755 --- a/src/Umbraco.Web/Logging/WebProfiler.cs +++ b/src/Umbraco.Web/Logging/WebProfiler.cs @@ -11,6 +11,9 @@ namespace Umbraco.Web.Logging /// /// Implements by using the MiniProfiler framework. /// + /// + /// Profiling only runs when the app is in debug mode, see WebRuntime for how this gets created + /// internal class WebProfiler : IProfiler { private const string BootRequestItemKey = "Umbraco.Core.Logging.WebProfiler__isBootRequest"; @@ -22,10 +25,13 @@ namespace Umbraco.Web.Logging // create our own provider, which can provide a profiler even during boot _provider = new WebProfilerProvider(); - // settings - MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter(); - MiniProfiler.Settings.StackMaxLength = 5000; - MiniProfiler.Settings.ProfilerProvider = _provider; + //see https://miniprofiler.com/dotnet/AspDotNet + MiniProfiler.Configure(new MiniProfilerOptions + { + SqlFormatter = new SqlServerFormatter(), + StackMaxLength = 5000, + ProfilerProvider = _provider + }); } public void UmbracoApplicationBeginRequest(object sender, EventArgs e) @@ -68,29 +74,32 @@ namespace Umbraco.Web.Logging /// public string Render() { - return MiniProfiler.RenderIncludes(RenderPosition.Right).ToString(); + return MiniProfiler.Current.RenderIncludes(RenderPosition.Right).ToString(); } /// public IDisposable Step(string name) { - return MiniProfiler.Current.Step(name); + return MiniProfiler.Current?.Step(name); } /// public void Start() { - MiniProfiler.Start(); + MiniProfiler.StartNew(); } /// public void Stop(bool discardResults = false) { - MiniProfiler.Stop(discardResults); + MiniProfiler.Current?.Stop(discardResults); } private static Attempt TryGetRequest(object sender) { + if (sender is HttpRequest httpRequest) + return Attempt.Succeed(new HttpRequestWrapper(httpRequest)); + var app = sender as HttpApplication; if (app == null) return Attempt.Fail(); diff --git a/src/Umbraco.Web/Logging/WebProfilerProvider.cs b/src/Umbraco.Web/Logging/WebProfilerProvider.cs index 7b12c2f5bd..dbb81cf232 100755 --- a/src/Umbraco.Web/Logging/WebProfilerProvider.cs +++ b/src/Umbraco.Web/Logging/WebProfilerProvider.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Web; using StackExchange.Profiling; +using StackExchange.Profiling.Internal; namespace Umbraco.Web.Logging { @@ -13,7 +14,7 @@ namespace Umbraco.Web.Logging /// Once the boot phase is changed to BootPhase.BootRequest then the base class (default) provider will handle all /// profiling data and this sub class no longer performs any logic. /// - internal class WebProfilerProvider : WebRequestProfilerProvider + internal class WebProfilerProvider : AspNetRequestProvider { private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(); private MiniProfiler _startupProfiler; @@ -81,23 +82,16 @@ namespace Umbraco.Web.Logging /// - assuming profiling is enabled, on every BeginRequest that should be profiled, /// - except for the very first one which is the boot request. /// - public override MiniProfiler Start(string sessionName = null) + public override MiniProfiler Start(string profilerName, MiniProfilerBaseOptions options) { var first = Interlocked.Exchange(ref _first, 1) == 0; - if (first == false) return base.Start(sessionName); + if (first == false) return base.Start(profilerName, options); - _startupProfiler = new MiniProfiler("http://localhost/umbraco-startup") { Name = "StartupProfiler" }; - SetProfilerActive(_startupProfiler); + _startupProfiler = new MiniProfiler("StartupProfiler", options); + CurrentProfiler = _startupProfiler; return _startupProfiler; } - // obsolete but that's the one that's called ;-( - [Obsolete] - public override MiniProfiler Start(ProfileLevel level, string sessionName = null) - { - return Start(sessionName); - } - /// /// Gets the current profiler. /// @@ -105,23 +99,27 @@ namespace Umbraco.Web.Logging /// If the boot phase is not Booted, then this will return the startup profiler (this), otherwise /// returns the base class /// - public override MiniProfiler GetCurrentProfiler() + public override MiniProfiler CurrentProfiler { - // if not booting then just use base (fast) - // no lock, _bootPhase is volatile - if (_bootPhase == BootPhase.Booted) - return base.GetCurrentProfiler(); + get + { + // if not booting then just use base (fast) + // no lock, _bootPhase is volatile + if (_bootPhase == BootPhase.Booted) + return base.CurrentProfiler; - // else - try - { - var current = base.GetCurrentProfiler(); - return current ?? _startupProfiler; - } - catch - { - return _startupProfiler; + // else + try + { + var current = base.CurrentProfiler; + return current ?? _startupProfiler; + } + catch + { + return _startupProfiler; + } } + } } } diff --git a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs index 9c02fa040d..cc88d183b6 100644 --- a/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs +++ b/src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs @@ -199,11 +199,11 @@ namespace Umbraco.Web.Macros Key = _inner.Key; // TODO: ARGH! need to fix this - this is not good because it uses ApplicationContext.Current - CreatorName = _inner.GetCreatorProfile().Name; - WriterName = _inner.GetWriterProfile().Name; + CreatorName = _inner.GetCreatorProfile()?.Name; + WriterName = _inner.GetWriterProfile()?.Name; - var contentTypeService = Current.Services.ContentTypeBaseServices.For(_inner); - ContentType = Current.PublishedContentTypeFactory.CreateContentType(contentTypeService.Get(_inner.ContentTypeId)); + var contentType = Current.Services.ContentTypeBaseServices.GetContentTypeOf(_inner); + ContentType = Current.PublishedContentTypeFactory.CreateContentType(contentType); _properties = ContentType.PropertyTypes .Select(x => diff --git a/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs index b3f5f0374c..563935676f 100644 --- a/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/CodeFileMapperProfile.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Alias, opt => opt.MapFrom(sheet => sheet.Alias)) .ForMember(dest => dest.Key, opt => opt.MapFrom(sheet => sheet.Key)) .ForMember(dest => dest.Name, opt => opt.MapFrom(sheet => sheet.Name)) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(sheet => sheet.Path)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs index 55b1672b2b..652ac12014 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs @@ -41,53 +41,53 @@ namespace Umbraco.Web.Models.Mapping //FROM IContent TO ContentItemDisplay CreateMap() .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key))) - .ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src))) - .ForMember(dest => dest.Updater, opt => opt.ResolveUsing(src => creatorResolver.Resolve(src))) - .ForMember(dest => dest.Variants, opt => opt.ResolveUsing(variantResolver)) - .ForMember(dest => dest.ContentApps, opt => opt.ResolveUsing(contentAppResolver)) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(src => contentOwnerResolver.Resolve(src))) + .ForMember(dest => dest.Updater, opt => opt.MapFrom(src => creatorResolver.Resolve(src))) + .ForMember(dest => dest.Variants, opt => opt.MapFrom(variantResolver)) + .ForMember(dest => dest.ContentApps, opt => opt.MapFrom(contentAppResolver)) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon)) .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name)) .ForMember(dest => dest.IsContainer, opt => opt.MapFrom(src => src.ContentType.IsContainer)) .ForMember(dest => dest.IsElement, opt => opt.MapFrom(src => src.ContentType.IsElement)) .ForMember(dest => dest.IsBlueprint, opt => opt.MapFrom(src => src.Blueprint)) - .ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver)) + .ForMember(dest => dest.IsChildOfListView, opt => opt.MapFrom(childOfListViewResolver)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) - .ForMember(dest => dest.TemplateAlias, opt => opt.ResolveUsing(defaultTemplateResolver)) - .ForMember(dest => dest.Urls, opt => opt.ResolveUsing(contentUrlResolver)) + .ForMember(dest => dest.TemplateAlias, opt => opt.MapFrom(defaultTemplateResolver)) + .ForMember(dest => dest.Urls, opt => opt.MapFrom(contentUrlResolver)) .ForMember(dest => dest.AllowPreview, opt => opt.Ignore()) - .ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(contentTreeNodeUrlResolver)) + .ForMember(dest => dest.TreeNodeUrl, opt => opt.MapFrom(contentTreeNodeUrlResolver)) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Errors, opt => opt.Ignore()) - .ForMember(dest => dest.DocumentType, opt => opt.ResolveUsing(contentTypeBasicResolver)) - .ForMember(dest => dest.AllowedTemplates, opt => opt.ResolveUsing(allowedTemplatesResolver)) - .ForMember(dest => dest.AllowedActions, opt => opt.ResolveUsing(src => actionButtonsResolver.Resolve(src))) + .ForMember(dest => dest.DocumentType, opt => opt.MapFrom(contentTypeBasicResolver)) + .ForMember(dest => dest.AllowedTemplates, opt => opt.MapFrom(allowedTemplatesResolver)) + .ForMember(dest => dest.AllowedActions, opt => opt.MapFrom(src => actionButtonsResolver.Resolve(src))) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); CreateMap() .ForMember(dest => dest.PublishDate, opt => opt.MapFrom(src => src.PublishDate)) - .ForMember(dest => dest.ReleaseDate, opt => opt.ResolveUsing(schedPublishReleaseDateResolver)) - .ForMember(dest => dest.ExpireDate, opt => opt.ResolveUsing(schedPublishExpireDateResolver)) + .ForMember(dest => dest.ReleaseDate, opt => opt.MapFrom(schedPublishReleaseDateResolver)) + .ForMember(dest => dest.ExpireDate, opt => opt.MapFrom(schedPublishExpireDateResolver)) .ForMember(dest => dest.Segment, opt => opt.Ignore()) .ForMember(dest => dest.Language, opt => opt.Ignore()) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) - .ForMember(dest => dest.State, opt => opt.ResolveUsing>()) - .ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver)); + .ForMember(dest => dest.State, opt => opt.MapFrom>()) + .ForMember(dest => dest.Tabs, opt => opt.MapFrom(tabsAndPropertiesResolver)); //FROM IContent TO ContentItemBasic CreateMap>() .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key))) - .ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src))) - .ForMember(dest => dest.Updater, opt => opt.ResolveUsing(src => creatorResolver.Resolve(src))) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(src => contentOwnerResolver.Resolve(src))) + .ForMember(dest => dest.Updater, opt => opt.MapFrom(src => creatorResolver.Resolve(src))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.Alias, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) - .ForMember(dest => dest.UpdateDate, opt => opt.ResolveUsing()) - .ForMember(dest => dest.Name, opt => opt.ResolveUsing()) - .ForMember(dest => dest.State, opt => opt.ResolveUsing>()) + .ForMember(dest => dest.UpdateDate, opt => opt.MapFrom()) + .ForMember(dest => dest.Name, opt => opt.MapFrom()) + .ForMember(dest => dest.State, opt => opt.MapFrom>()) .ForMember(dest => dest.VariesByCulture, opt => opt.MapFrom(src => src.ContentType.VariesByCulture())); //FROM IContent TO ContentPropertyCollectionDto diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyMapperProfile.cs index 0b086afb2d..f9ed72fc11 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyMapperProfile.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Models.Mapping //FROM Property TO ContentPropertyBasic CreateMap>() .ForMember(tab => tab.Label, expression => expression.MapFrom(@group => @group.Name)) - .ForMember(tab => tab.IsActive, expression => expression.UseValue(true)) + .ForMember(tab => tab.IsActive, expression => expression.MapFrom(_ => true)) .ForMember(tab => tab.Properties, expression => expression.Ignore()) .ForMember(tab => tab.Alias, expression => expression.Ignore()) .ForMember(tab => tab.Expanded, expression => expression.Ignore()); diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs index 19c150e072..aa97b25260 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs @@ -30,8 +30,7 @@ namespace Umbraco.Web.Models.Mapping if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { - var contentTypeService = _contentTypeBaseServiceProvider.For(source); - var contentType = contentTypeService.Get(source.ContentTypeId); + var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source); var contentTypeBasic = Mapper.Map(contentType); return contentTypeBasic; diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs index 88bf409737..ee78c692ff 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeMapperProfile.cs @@ -153,7 +153,7 @@ namespace Umbraco.Web.Models.Mapping CreateMap() - .ConstructUsing(propertyTypeBasic => + .ConstructUsing((propertyTypeBasic, context) => { var dataType = dataTypeService.GetDataType(propertyTypeBasic.DataTypeId); if (dataType == null) throw new NullReferenceException("No data type found with id " + propertyTypeBasic.DataTypeId); @@ -168,7 +168,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.PropertyEditorAlias, opt => opt.Ignore()) .ForMember(dest => dest.DeleteDate, opt => opt.Ignore()) - .ForMember(dto => dto.Variations, opt => opt.ResolveUsing()) + .ForMember(dto => dto.Variations, opt => opt.MapFrom()) //only map if it is actually set .ForMember(dest => dest.Id, opt => opt.Condition(source => source.Id > 0)) diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs index 0e324c94b9..d05295a546 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs @@ -114,7 +114,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Errors, opt => opt.Ignore()) .ForMember(dest => dest.LockedCompositeContentTypes, opt => opt.Ignore()) - .ForMember(dest => dest.Groups, opt => opt.ResolveUsing(src => propertyGroupDisplayResolver.Resolve(src))); + .ForMember(dest => dest.Groups, opt => opt.MapFrom(src => propertyGroupDisplayResolver.Resolve(src))); } public static IMappingExpression MapBaseContentTypeEntityToDisplay( @@ -129,7 +129,7 @@ namespace Umbraco.Web.Models.Mapping var propertyTypeGroupResolver = new PropertyTypeGroupResolver(propertyEditors, dataTypeService); return mapping - .ForMember(dest => dest.Udi, opt => opt.ResolveUsing(src => contentTypeUdiResolver.Resolve(src))) + .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => contentTypeUdiResolver.Resolve(src))) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Blueprints, opt => opt.Ignore()) .ForMember(dest => dest.Errors, opt => opt.Ignore()) @@ -140,8 +140,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.AllowedContentTypes, opt => opt.MapFrom(src => src.AllowedContentTypes.Select(x => x.Id.Value))) .ForMember(dest => dest.CompositeContentTypes, opt => opt.MapFrom(src => src.ContentTypeComposition)) - .ForMember(dest => dest.LockedCompositeContentTypes, opt => opt.ResolveUsing(src => lockedCompositionsResolver.Resolve(src))) - .ForMember(dest => dest.Groups, opt => opt.ResolveUsing(src => propertyTypeGroupResolver.Resolve(src))) + .ForMember(dest => dest.LockedCompositeContentTypes, opt => opt.MapFrom(src => lockedCompositionsResolver.Resolve(src))) + .ForMember(dest => dest.Groups, opt => opt.MapFrom(src => propertyTypeGroupResolver.Resolve(src))) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); } @@ -184,7 +184,7 @@ namespace Umbraco.Web.Models.Mapping // ignore for members mapping = typeof(TDestination) == typeof(IMemberType) ? mapping.ForMember(dto => dto.Variations, opt => opt.Ignore()) - : mapping.ForMember(dto => dto.Variations, opt => opt.ResolveUsing>()); + : mapping.ForMember(dto => dto.Variations, opt => opt.MapFrom>()); mapping = mapping .ForMember( diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs index 425e447c9c..f707003ffe 100644 --- a/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs @@ -68,8 +68,8 @@ namespace Umbraco.Web.Models.Mapping CreateMap() .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.DataType, src.Key))) - .ForMember(dest => dest.AvailableEditors, opt => opt.ResolveUsing(src => availablePropertyEditorsResolver.Resolve(src))) - .ForMember(dest => dest.PreValues, opt => opt.ResolveUsing(src => configurationDisplayResolver.Resolve(src))) + .ForMember(dest => dest.AvailableEditors, opt => opt.MapFrom(src => availablePropertyEditorsResolver.Resolve(src))) + .ForMember(dest => dest.PreValues, opt => opt.MapFrom(src => configurationDisplayResolver.Resolve(src))) .ForMember(dest => dest.SelectedEditor, opt => opt.MapFrom(src => src.EditorAlias.IsNullOrWhiteSpace() ? null : src.EditorAlias)) .ForMember(dest => dest.HasPrevalues, opt => opt.Ignore()) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) @@ -92,13 +92,13 @@ namespace Umbraco.Web.Models.Mapping .ConvertUsing(src => configurationDisplayResolver.Resolve(src)); CreateMap() - .ConstructUsing(src => new DataType(propertyEditors[src.EditorAlias]) {CreateDate = DateTime.Now}) + .ConstructUsing(src => new DataType(propertyEditors[src.EditorAlias], -1) {CreateDate = DateTime.Now}) .IgnoreEntityCommonProperties() .ForMember(dest => dest.Id, opt => opt.MapFrom(src => Convert.ToInt32(src.Id))) .ForMember(dest => dest.Key, opt => opt.Ignore()) // ignore key, else resets UniqueId - U4-3911 .ForMember(dest => dest.Path, opt => opt.Ignore()) .ForMember(dest => dest.EditorAlias, opt => opt.MapFrom(src => src.EditorAlias)) - .ForMember(dest => dest.DatabaseType, opt => opt.ResolveUsing(src => databaseTypeResolver.Resolve(src))) + .ForMember(dest => dest.DatabaseType, opt => opt.MapFrom(src => databaseTypeResolver.Resolve(src))) .ForMember(dest => dest.CreatorId, opt => opt.Ignore()) .ForMember(dest => dest.Level, opt => opt.Ignore()) .ForMember(dest => dest.SortOrder, opt => opt.Ignore()) @@ -107,14 +107,14 @@ namespace Umbraco.Web.Models.Mapping //Converts a property editor to a new list of pre-value fields - used when creating a new data type or changing a data type with new pre-vals CreateMap>() - .ConvertUsing(src => + .ConvertUsing((dataEditor, configurationFieldDisplays) => { // this is a new data type, initialize default configuration // get the configuration editor, // get the configuration fields and map to UI, // get the configuration default values and map to UI - var configurationEditor = src.GetConfigurationEditor(); + var configurationEditor = dataEditor.GetConfigurationEditor(); var fields = configurationEditor.Fields.Select(Mapper.Map).ToArray(); diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs index 90e98822b1..ab3929166f 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapperProfile.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Models.Mapping var contentTypeUdiResolver = new ContentTypeUdiResolver(); CreateMap() - .ForMember(dest => dest.Name, opt => opt.ResolveUsing()) + .ForMember(dest => dest.Name, opt => opt.MapFrom()) .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(ObjectTypes.GetUdiType(src.NodeObjectType), src.Key))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => GetContentTypeIcon(src))) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) @@ -42,17 +42,17 @@ namespace Umbraco.Web.Models.Mapping CreateMap() .ForMember(dest => dest.Udi, opt => opt.Ignore()) - .ForMember(dest => dest.Icon, opt => opt.UseValue("icon-box")) - .ForMember(dest => dest.Path, opt => opt.UseValue("")) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(_ => "icon-box")) + .ForMember(dest => dest.Path, opt => opt.MapFrom(_ => "")) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); CreateMap() .ForMember(dest => dest.Udi, opt => opt.Ignore()) - .ForMember(dest => dest.Icon, opt => opt.UseValue("icon-tab")) - .ForMember(dest => dest.Path, opt => opt.UseValue("")) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(_ => "icon-tab")) + .ForMember(dest => dest.Path, opt => opt.MapFrom(_ => "")) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) //in v6 the 'alias' is it's lower cased name so we'll stick to that. .ForMember(dest => dest.Alias, opt => opt.MapFrom(src => src.Name.ToLowerInvariant())) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) @@ -60,18 +60,18 @@ namespace Umbraco.Web.Models.Mapping CreateMap() .ForMember(dest => dest.Udi, opt => opt.Ignore()) - .ForMember(dest => dest.Icon, opt => opt.UseValue("icon-user")) - .ForMember(dest => dest.Path, opt => opt.UseValue("")) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(_ => "icon-user")) + .ForMember(dest => dest.Path, opt => opt.MapFrom(_ => "")) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Alias, opt => opt.MapFrom(src => src.Username)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); CreateMap() .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.Template, src.Key))) - .ForMember(dest => dest.Icon, opt => opt.UseValue("icon-layout")) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(_ => "icon-layout")) .ForMember(dest => dest.Path, opt => opt.MapFrom(src => src.Path)) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()); @@ -80,7 +80,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.SortOrder, opt => opt.Ignore()); CreateMap() - .ForMember(dest => dest.Udi, opt => opt.ResolveUsing(src => contentTypeUdiResolver.Resolve(src))) + .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => contentTypeUdiResolver.Resolve(src))) .ForMember(dest => dest.Path, opt => opt.MapFrom(src => src.Path)) .ForMember(dest => dest.ParentId, opt => opt.MapFrom(src => src.ParentId)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs index 13c6af2fda..a838180622 100644 --- a/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/LanguageMapperProfile.cs @@ -17,7 +17,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Name, opt => opt.MapFrom(x => x.CultureName)) .ForMember(dest => dest.Key, opt => opt.MapFrom(x => x.Key)) .ForMember(dest => dest.Alias, opt => opt.MapFrom(x => x.IsoCode)) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.Ignore()) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs index be1bcdefdc..3e0f6c7337 100644 --- a/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs @@ -19,9 +19,9 @@ namespace Umbraco.Web.Models.Mapping //FROM IMacro TO EntityBasic CreateMap() .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Macro, content.Key))) - .ForMember(entityBasic => entityBasic.Icon, expression => expression.UseValue("icon-settings-alt")) - .ForMember(dto => dto.ParentId, expression => expression.UseValue(-1)) - .ForMember(dto => dto.Path, expression => expression.ResolveUsing(macro => "-1," + macro.Id)) + .ForMember(entityBasic => entityBasic.Icon, expression => expression.MapFrom(_ => "icon-settings-alt")) + .ForMember(dto => dto.ParentId, expression => expression.MapFrom(_ => -1)) + .ForMember(dto => dto.Path, expression => expression.MapFrom(macro => "-1," + macro.Id)) .ForMember(dto => dto.Trashed, expression => expression.Ignore()) .ForMember(dto => dto.AdditionalData, expression => expression.Ignore()); diff --git a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs index 7a8706edf2..f5182f0b3b 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs @@ -35,37 +35,37 @@ namespace Umbraco.Web.Models.Mapping //FROM IMedia TO MediaItemDisplay CreateMap() .ForMember(dest => dest.Udi, opt => opt.MapFrom(content => Udi.Create(Constants.UdiEntityType.Media, content.Key))) - .ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => mediaOwnerResolver.Resolve(src))) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(src => mediaOwnerResolver.Resolve(src))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(content => content.ContentType.Icon)) .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(content => content.ContentType.Alias)) - .ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver)) + .ForMember(dest => dest.IsChildOfListView, opt => opt.MapFrom(childOfListViewResolver)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(content => content.Trashed)) .ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(content => content.ContentType.Name)) .ForMember(dest => dest.Properties, opt => opt.Ignore()) - .ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(contentTreeNodeUrlResolver)) + .ForMember(dest => dest.TreeNodeUrl, opt => opt.MapFrom(contentTreeNodeUrlResolver)) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Errors, opt => opt.Ignore()) - .ForMember(dest => dest.State, opt => opt.UseValue(null)) + .ForMember(dest => dest.State, opt => opt.MapFrom(_ => null)) .ForMember(dest => dest.Edited, opt => opt.Ignore()) .ForMember(dest => dest.Updater, opt => opt.Ignore()) .ForMember(dest => dest.Alias, opt => opt.Ignore()) .ForMember(dest => dest.IsContainer, opt => opt.Ignore()) - .ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver)) + .ForMember(dest => dest.Tabs, opt => opt.MapFrom(tabsAndPropertiesResolver)) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) - .ForMember(dest => dest.ContentType, opt => opt.ResolveUsing(mediaTypeBasicResolver)) - .ForMember(dest => dest.MediaLink, opt => opt.ResolveUsing(content => string.Join(",", content.GetUrls(Current.Configs.Settings().Content, logger)))) - .ForMember(dest => dest.ContentApps, opt => opt.ResolveUsing(mediaAppResolver)) + .ForMember(dest => dest.ContentType, opt => opt.MapFrom(mediaTypeBasicResolver)) + .ForMember(dest => dest.MediaLink, opt => opt.MapFrom(content => string.Join(",", content.GetUrls(Current.Configs.Settings().Content, logger)))) + .ForMember(dest => dest.ContentApps, opt => opt.MapFrom(mediaAppResolver)) .ForMember(dest => dest.VariesByCulture, opt => opt.MapFrom(src => src.ContentType.VariesByCulture())); //FROM IMedia TO ContentItemBasic CreateMap>() .ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.Media, src.Key))) - .ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => mediaOwnerResolver.Resolve(src))) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(src => mediaOwnerResolver.Resolve(src))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon)) .ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed)) .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) - .ForMember(dest => dest.State, opt => opt.UseValue(null)) + .ForMember(dest => dest.State, opt => opt.MapFrom(_ => null)) .ForMember(dest => dest.Edited, opt => opt.Ignore()) .ForMember(dest => dest.Updater, opt => opt.Ignore()) .ForMember(dest => dest.Alias, opt => opt.Ignore()) @@ -76,7 +76,7 @@ namespace Umbraco.Web.Models.Mapping //FROM IMedia TO ContentItemDto CreateMap(); //.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.Media, src.Key))) - //.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => mediaOwnerResolver.Resolve(src))) + //.ForMember(dest => dest.Owner, opt => opt.MapFrom(src => mediaOwnerResolver.Resolve(src))) //.ForMember(dest => dest.Published, opt => opt.Ignore()) //.ForMember(dest => dest.Edited, opt => opt.Ignore()) //.ForMember(dest => dest.Updater, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/MemberBasicPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/MemberBasicPropertiesResolver.cs index fbd14876ea..e1ee0631a9 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberBasicPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberBasicPropertiesResolver.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using AutoMapper; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Mapping @@ -13,10 +14,12 @@ namespace Umbraco.Web.Models.Mapping internal class MemberBasicPropertiesResolver : IValueResolver> { private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IMemberTypeService _memberTypeService; - public MemberBasicPropertiesResolver(IUmbracoContextAccessor umbracoContextAccessor) + public MemberBasicPropertiesResolver(IUmbracoContextAccessor umbracoContextAccessor, IMemberTypeService memberTypeService) { - _umbracoContextAccessor = umbracoContextAccessor ?? throw new System.ArgumentNullException(nameof(umbracoContextAccessor)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); } public IEnumerable Resolve(IMember source, MemberBasic destination, IEnumerable destMember, ResolutionContext context) @@ -29,7 +32,7 @@ namespace Umbraco.Web.Models.Mapping source.Properties.OrderBy(prop => prop.PropertyType.SortOrder)) .ToList(); - var memberType = source.ContentType; + var memberType = _memberTypeService.Get(source.ContentTypeId); //now update the IsSensitive value foreach (var prop in result) diff --git a/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs index af894bee5e..a721714a14 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs @@ -64,24 +64,24 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO MemberDisplay CreateMap() .ForMember(dest => dest.Udi, opt => opt.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) - .ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => memberOwnerResolver.Resolve(src))) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(src => memberOwnerResolver.Resolve(src))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon)) .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name)) .ForMember(dest => dest.Properties, opt => opt.Ignore()) - .ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver)) - .ForMember(dest => dest.MemberProviderFieldMapping, opt => opt.ResolveUsing(src => memberProfiderFieldMappingResolver.Resolve(src))) - .ForMember(dest => dest.MembershipScenario, opt => opt.ResolveUsing(src => membershipScenarioMappingResolver.Resolve(src))) + .ForMember(dest => dest.Tabs, opt => opt.MapFrom(tabsAndPropertiesResolver)) + .ForMember(dest => dest.MemberProviderFieldMapping, opt => opt.MapFrom(src => memberProfiderFieldMappingResolver.Resolve(src))) + .ForMember(dest => dest.MembershipScenario, opt => opt.MapFrom(src => membershipScenarioMappingResolver.Resolve(src))) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Errors, opt => opt.Ignore()) - .ForMember(dest => dest.State, opt => opt.UseValue(null)) + .ForMember(dest => dest.State, opt => opt.MapFrom(_ => null)) .ForMember(dest => dest.Edited, opt => opt.Ignore()) .ForMember(dest => dest.Updater, opt => opt.Ignore()) .ForMember(dest => dest.Alias, opt => opt.Ignore()) .ForMember(dest => dest.IsChildOfListView, opt => opt.Ignore()) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.IsContainer, opt => opt.Ignore()) - .ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(memberTreeNodeUrlResolver)) + .ForMember(dest => dest.TreeNodeUrl, opt => opt.MapFrom(memberTreeNodeUrlResolver)) .ForMember(dest => dest.VariesByCulture, opt => opt.Ignore()); //FROM IMember TO MemberBasic @@ -89,17 +89,17 @@ namespace Umbraco.Web.Models.Mapping //we're giving this entity an ID of int.MaxValue - this is kind of a hack to force angular to use the Key instead of the Id in list views .ForMember(dest => dest.Id, opt => opt.MapFrom(src => int.MaxValue)) .ForMember(dest => dest.Udi, opt => opt.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) - .ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => memberOwnerResolver.Resolve(src))) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(src => memberOwnerResolver.Resolve(src))) .ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon)) .ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias)) .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)) .ForMember(dest => dest.Username, opt => opt.MapFrom(src => src.Username)) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) - .ForMember(dest => dest.State, opt => opt.UseValue(null)) + .ForMember(dest => dest.State, opt => opt.MapFrom(_ => null)) .ForMember(dest => dest.Edited, opt => opt.Ignore()) .ForMember(dest => dest.Updater, opt => opt.Ignore()) .ForMember(dest => dest.Alias, opt => opt.Ignore()) - .ForMember(dto => dto.Properties, expression => expression.ResolveUsing(memberBasicPropertiesResolver)) + .ForMember(dto => dto.Properties, expression => expression.MapFrom(memberBasicPropertiesResolver)) .ForMember(dest => dest.VariesByCulture, opt => opt.Ignore()); //FROM MembershipUser TO MemberBasic @@ -110,8 +110,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.CreateDate, opt => opt.MapFrom(src => src.CreationDate)) .ForMember(dest => dest.UpdateDate, opt => opt.MapFrom(src => src.LastActivityDate)) .ForMember(dest => dest.Key, opt => opt.MapFrom(src => src.ProviderUserKey.TryConvertTo().Result.ToString("N"))) - .ForMember(dest => dest.Owner, opt => opt.UseValue(new UserProfile {Name = "Admin", UserId = -1 })) - .ForMember(dest => dest.Icon, opt => opt.UseValue("icon-user")) + .ForMember(dest => dest.Owner, opt => opt.MapFrom(_ => new UserProfile {Name = "Admin", UserId = -1 })) + .ForMember(dest => dest.Icon, opt => opt.MapFrom(_ => "icon-user")) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.UserName)) .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)) .ForMember(dest => dest.Username, opt => opt.MapFrom(src => src.UserName)) @@ -120,7 +120,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Path, opt => opt.Ignore()) .ForMember(dest => dest.SortOrder, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) - .ForMember(dest => dest.State, opt => opt.UseValue(ContentSavedState.Draft)) + .ForMember(dest => dest.State, opt => opt.MapFrom(_ => ContentSavedState.Draft)) .ForMember(dest => dest.Edited, opt => opt.Ignore()) .ForMember(dest => dest.Updater, opt => opt.Ignore()) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) @@ -131,14 +131,14 @@ namespace Umbraco.Web.Models.Mapping //FROM IMember TO ContentItemDto CreateMap() //.ForMember(dest => dest.Udi, opt => opt.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key))) - //.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => memberOwnerResolver.Resolve(src))) + //.ForMember(dest => dest.Owner, opt => opt.MapFrom(src => memberOwnerResolver.Resolve(src))) //.ForMember(dest => dest.Published, opt => opt.Ignore()) //.ForMember(dest => dest.Edited, opt => opt.Ignore()) //.ForMember(dest => dest.Updater, opt => opt.Ignore()) //.ForMember(dest => dest.Icon, opt => opt.Ignore()) //.ForMember(dest => dest.Alias, opt => opt.Ignore()) //do no map the custom member properties (currently anyways, they were never there in 6.x) - .ForMember(dest => dest.Properties, opt => opt.ResolveUsing(src => memberDtoPropertiesResolver.Resolve(src))); + .ForMember(dest => dest.Properties, opt => opt.MapFrom(src => memberDtoPropertiesResolver.Resolve(src))); //FROM IMemberGroup TO MemberGroupDisplay CreateMap() diff --git a/src/Umbraco.Web/Models/Mapping/MemberTabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/MemberTabsAndPropertiesResolver.cs index 6134275c76..517889277c 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberTabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberTabsAndPropertiesResolver.cs @@ -25,16 +25,18 @@ namespace Umbraco.Web.Models.Mapping { private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ILocalizedTextService _localizedTextService; + private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; private readonly IUserService _userService; - public MemberTabsAndPropertiesResolver(IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService localizedTextService, IMemberService memberService, IUserService userService) + public MemberTabsAndPropertiesResolver(IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService localizedTextService, IMemberService memberService, IUserService userService, IMemberTypeService memberTypeService) : base(localizedTextService) { - _umbracoContextAccessor = umbracoContextAccessor ?? throw new System.ArgumentNullException(nameof(umbracoContextAccessor)); - _localizedTextService = localizedTextService ?? throw new System.ArgumentNullException(nameof(localizedTextService)); - _memberService = memberService ?? throw new System.ArgumentNullException(nameof(memberService)); - _userService = userService ?? throw new System.ArgumentNullException(nameof(userService)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); + _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); + _userService = userService ?? throw new ArgumentNullException(nameof(userService)); + _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); } /// @@ -43,7 +45,9 @@ namespace Umbraco.Web.Models.Mapping { var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); - IgnoreProperties = source.PropertyTypes + var memberType = _memberTypeService.Get(source.ContentTypeId); + + IgnoreProperties = memberType.CompositionPropertyTypes .Where(x => x.HasIdentity == false) .Select(x => x.Alias) .ToArray(); @@ -176,7 +180,7 @@ namespace Umbraco.Web.Models.Mapping { var result = base.MapProperties(content, properties, context); var member = (IMember)content; - var memberType = member.ContentType; + var memberType = _memberTypeService.Get(member.ContentTypeId); var umbracoContext = _umbracoContextAccessor.UmbracoContext; diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index e8d7fb38b2..dc3cc9e74f 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -27,21 +27,6 @@ namespace Umbraco.Web.Models.Mapping IgnoreProperties = ignoreProperties ?? throw new ArgumentNullException(nameof(ignoreProperties)); } - // TODO: This should deserialize to ListViewConfiguration - private static int GetTabNumberFromConfig(IDictionary listViewConfig) - { - if (!listViewConfig.TryGetValue("displayAtTabNumber", out var displayTabNum)) - return -1; - switch (displayTabNum) - { - case int i: - return i; - case string s when int.TryParse(s, out var parsed): - return parsed; - } - return -1; - } - /// /// Returns a collection of custom generic properties that exist on the generic properties tab /// @@ -58,7 +43,7 @@ namespace Umbraco.Web.Models.Mapping /// /// /// - /// The generic properties tab is responsible for + /// The generic properties tab is responsible for /// setting up the properties such as Created date, updated date, template selected, etc... /// protected virtual void MapGenericProperties(IContentBase content, List> tabs, ResolutionContext context) @@ -98,7 +83,7 @@ namespace Umbraco.Web.Models.Mapping //re-assign genericProps.Properties = contentProps; - //Show or hide properties tab based on whether it has or not any properties + //Show or hide properties tab based on whether it has or not any properties if (genericProps.Properties.Any() == false) { //loop through the tabs, remove the one with the id of zero and exit the loop @@ -145,11 +130,13 @@ namespace Umbraco.Web.Models.Mapping { var tabs = new List>(); + var contentType = Current.Services.ContentTypeBaseServices.GetContentTypeOf(source); + // add the tabs, for properties that belong to a tab // need to aggregate the tabs, as content.PropertyGroups contains all the composition tabs, // and there might be duplicates (content does not work like contentType and there is no // content.CompositionPropertyGroups). - var groupsGroupsByName = source.PropertyGroups.OrderBy(x => x.SortOrder).GroupBy(x => x.Name); + var groupsGroupsByName = contentType.CompositionPropertyGroups.OrderBy(x => x.SortOrder).GroupBy(x => x.Name); foreach (var groupsByName in groupsGroupsByName) { var properties = new List(); diff --git a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs index 6f3af3b812..84660d2602 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapperProfile.cs @@ -99,7 +99,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.LastLockoutDate, opt => opt.Ignore()) .ForMember(dest => dest.FailedPasswordAttempts, opt => opt.Ignore()) //all invited users will not be approved, completing the invite will approve the user - .ForMember(user => user.IsApproved, opt => opt.UseValue(false)) + .ForMember(user => user.IsApproved, opt => opt.MapFrom(_ => false)) .AfterMap((invite, user) => { user.ClearGroups(); @@ -119,7 +119,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Udi, opt => opt.Ignore()) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id)) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) .AfterMap((group, display) => @@ -134,7 +134,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Udi, opt => opt.Ignore()) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id)) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) .AfterMap((group, display) => @@ -148,9 +148,9 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Trashed, opt => opt.Ignore()) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) .ForMember(dest => dest.Id, opt => opt.MapFrom(group => group.Id)) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id)) - .ForMember(dest => dest.DefaultPermissions, opt => opt.ResolveUsing(src => userGroupDefaultPermissionsResolver.Resolve(src))) + .ForMember(dest => dest.DefaultPermissions, opt => opt.MapFrom(src => userGroupDefaultPermissionsResolver.Resolve(src))) //these will be manually mapped and by default they are null .ForMember(dest => dest.AssignedPermissions, opt => opt.Ignore()) .AfterMap((group, display) => @@ -182,11 +182,11 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Udi, opt => opt.Ignore()) .ForMember(dest => dest.Trashed, opt => opt.Ignore()) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id)) .ForMember(dest => dest.AdditionalData, opt => opt.Ignore()) .ForMember(dest => dest.Users, opt => opt.Ignore()) - .ForMember(dest => dest.DefaultPermissions, opt => opt.ResolveUsing(src => userGroupDefaultPermissionsResolver.Resolve(src))) + .ForMember(dest => dest.DefaultPermissions, opt => opt.MapFrom(src => userGroupDefaultPermissionsResolver.Resolve(src))) .ForMember(dest => dest.AssignedPermissions, opt => opt.Ignore()) .AfterMap((group, display) => { @@ -276,7 +276,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember( dest => dest.EmailHash, opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().GenerateHash())) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(user => "-1," + user.Id)) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.Udi, opt => opt.Ignore()) @@ -302,7 +302,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember( dest => dest.EmailHash, opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5())) - .ForMember(dest => dest.ParentId, opt => opt.UseValue(-1)) + .ForMember(dest => dest.ParentId, opt => opt.MapFrom(_ => -1)) .ForMember(dest => dest.Path, opt => opt.MapFrom(user => "-1," + user.Id)) .ForMember(dest => dest.Notifications, opt => opt.Ignore()) .ForMember(dest => dest.IsCurrentUser, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/PropertyEditors/GridConfigurationEditor.cs b/src/Umbraco.Web/PropertyEditors/GridConfigurationEditor.cs index fe86bb9a6e..902cd5b41b 100644 --- a/src/Umbraco.Web/PropertyEditors/GridConfigurationEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridConfigurationEditor.cs @@ -1,4 +1,9 @@ -using Umbraco.Core.PropertyEditors; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Newtonsoft.Json; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors { @@ -6,5 +11,45 @@ namespace Umbraco.Web.PropertyEditors /// Represents the configuration for the grid value editor. /// public class GridConfigurationEditor : ConfigurationEditor - { } + { + public GridConfigurationEditor() + { + var items = Fields.First(x => x.Key == "items"); + + items.Validators.Add(new GridValidator()); + } + } + + public class GridValidator : IValueValidator + { + public IEnumerable Validate(object rawValue, string valueType, object dataTypeConfiguration) + { + if (rawValue == null) + yield break; + + var model = JsonConvert.DeserializeObject(rawValue.ToString()); + + if (model.Templates.Any(t => t.Sections.Sum(s => s.Grid) > model.Columns)) + { + yield return new ValidationResult("Columns must be at least the same size as the largest layout", new[] { nameof(model.Columns) }); + } + + } + } + + public class GridEditorModel + { + public GridEditorTemplateModel[] Templates { get; set; } + public int Columns { get; set; } + } + + public class GridEditorTemplateModel + { + public GridEditorSectionModel[] Sections { get; set; } + } + + public class GridEditorSectionModel + { + public int Grid { get; set; } + } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 8feb337bc7..9845becb45 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -1231,9 +1231,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var cultureData = new Dictionary(); // sanitize - names should be ok but ... never knows - var contentTypeService = _contentTypeBaseServiceProvider.For(content); - var contentType = contentTypeService.Get(content.ContentTypeId); - if (contentType.VariesByCulture()) + if (content.ContentType.VariesByCulture()) { var infos = content is IContent document ? (published diff --git a/src/Umbraco.Web/PublishedContentQuery.cs b/src/Umbraco.Web/PublishedContentQuery.cs index 2c4d08502e..61180580cb 100644 --- a/src/Umbraco.Web/PublishedContentQuery.cs +++ b/src/Umbraco.Web/PublishedContentQuery.cs @@ -2,41 +2,31 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; using System.Xml.XPath; using Examine; using Examine.Search; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; using Umbraco.Core.Xml; using Umbraco.Examine; using Umbraco.Web.PublishedCache; namespace Umbraco.Web { - using Examine = global::Examine; - /// /// A class used to query for published content, media items /// public class PublishedContentQuery : IPublishedContentQuery { - private readonly IPublishedContentCache _contentCache; - private readonly IPublishedMediaCache _mediaCache; + private readonly IPublishedSnapshot _publishedSnapshot; private readonly IVariationContextAccessor _variationContextAccessor; /// - /// Constructor used to return results from the caches + /// Initializes a new instance of the class. /// - /// - /// - /// - public PublishedContentQuery(IPublishedContentCache contentCache, IPublishedMediaCache mediaCache, IVariationContextAccessor variationContextAccessor) + public PublishedContentQuery(IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor) { - _contentCache = contentCache ?? throw new ArgumentNullException(nameof(contentCache)); - _mediaCache = mediaCache ?? throw new ArgumentNullException(nameof(mediaCache)); + _publishedSnapshot = publishedSnapshot ?? throw new ArgumentNullException(nameof(publishedSnapshot)); _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); } @@ -44,48 +34,48 @@ namespace Umbraco.Web public IPublishedContent Content(int id) { - return ItemById(id, _contentCache); + return ItemById(id, _publishedSnapshot.Content); } public IPublishedContent Content(Guid id) { - return ItemById(id, _contentCache); + return ItemById(id, _publishedSnapshot.Content); } public IPublishedContent Content(Udi id) { if (!(id is GuidUdi udi)) return null; - return ItemById(udi.Guid, _contentCache); + return ItemById(udi.Guid, _publishedSnapshot.Content); } public IPublishedContent ContentSingleAtXPath(string xpath, params XPathVariable[] vars) { - return ItemByXPath(xpath, vars, _contentCache); + return ItemByXPath(xpath, vars, _publishedSnapshot.Content); } public IEnumerable Content(IEnumerable ids) { - return ItemsByIds(_contentCache, ids); + return ItemsByIds(_publishedSnapshot.Content, ids); } public IEnumerable Content(IEnumerable ids) { - return ItemsByIds(_contentCache, ids); + return ItemsByIds(_publishedSnapshot.Content, ids); } public IEnumerable ContentAtXPath(string xpath, params XPathVariable[] vars) { - return ItemsByXPath(xpath, vars, _contentCache); + return ItemsByXPath(xpath, vars, _publishedSnapshot.Content); } public IEnumerable ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars) { - return ItemsByXPath(xpath, vars, _contentCache); + return ItemsByXPath(xpath, vars, _publishedSnapshot.Content); } public IEnumerable ContentAtRoot() { - return ItemsAtRoot(_contentCache); + return ItemsAtRoot(_publishedSnapshot.Content); } #endregion @@ -94,33 +84,33 @@ namespace Umbraco.Web public IPublishedContent Media(int id) { - return ItemById(id, _mediaCache); + return ItemById(id, _publishedSnapshot.Media); } public IPublishedContent Media(Guid id) { - return ItemById(id, _mediaCache); + return ItemById(id, _publishedSnapshot.Media); } public IPublishedContent Media(Udi id) { if (!(id is GuidUdi udi)) return null; - return ItemById(udi.Guid, _mediaCache); + return ItemById(udi.Guid, _publishedSnapshot.Media); } public IEnumerable Media(IEnumerable ids) { - return ItemsByIds(_mediaCache, ids); + return ItemsByIds(_publishedSnapshot.Media, ids); } public IEnumerable Media(IEnumerable ids) { - return ItemsByIds(_mediaCache, ids); + return ItemsByIds(_publishedSnapshot.Media, ids); } public IEnumerable MediaAtRoot() { - return ItemsAtRoot(_mediaCache); + return ItemsAtRoot(_publishedSnapshot.Media); } @@ -224,7 +214,7 @@ namespace Umbraco.Web totalRecords = results.TotalItemCount; - return new CultureContextualSearchResults(results.ToPublishedSearchResults(_contentCache), _variationContextAccessor, culture); + return new CultureContextualSearchResults(results.ToPublishedSearchResults(_publishedSnapshot.Content), _variationContextAccessor, culture); } /// @@ -241,7 +231,7 @@ namespace Umbraco.Web : query.Execute(maxResults: skip + take); totalRecords = results.TotalItemCount; - return results.ToPublishedSearchResults(_contentCache); + return results.ToPublishedSearchResults(_publishedSnapshot.Content); } /// diff --git a/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs index 382ee6fe12..e3cad25c6f 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs @@ -13,7 +13,6 @@ namespace Umbraco.Web.Routing /// public class ContentFinderByConfigured404 : IContentLastChanceFinder { - private readonly ILogger _logger; private readonly IEntityService _entityService; private readonly IContentSection _contentConfigSection; @@ -63,7 +62,7 @@ namespace Umbraco.Web.Routing var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId( _contentConfigSection.Error404Collection.ToArray(), _entityService, - new PublishedContentQuery(frequest.UmbracoContext.ContentCache, frequest.UmbracoContext.MediaCache, frequest.UmbracoContext.VariationContextAccessor), + new PublishedContentQuery(frequest.UmbracoContext.PublishedSnapshot, frequest.UmbracoContext.VariationContextAccessor), errorCulture); IPublishedContent content = null; diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs b/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs index 1130f0880f..75ab4ad613 100644 --- a/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs +++ b/src/Umbraco.Web/Routing/RedirectTrackingComposer.cs @@ -12,6 +12,6 @@ namespace Umbraco.Web.Routing /// recycle bin = moving to and from does nothing: to = the node is gone, where would we redirect? from = same /// [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - public class RedirectTrackingComposer : ComponentComposer, ICoreComposer + public class RedirectTrackingComposer : ComponentComposer, ICoreComposer { } } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 0f17c19bdb..3afe6aa397 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -91,7 +91,7 @@ namespace Umbraco.Web.Runtime composition.Register(factory => { var umbCtx = factory.GetInstance(); - return new PublishedContentQuery(umbCtx.UmbracoContext.ContentCache, umbCtx.UmbracoContext.MediaCache, factory.GetInstance()); + return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetInstance()); }, Lifetime.Request); composition.Register(Lifetime.Request); diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index 8de42fc12b..83a0b15b82 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -171,14 +171,16 @@ namespace Umbraco.Web.Security member.Name = model.Name; } + var memberType = _memberTypeService.Get(member.ContentTypeId); + if (model.MemberProperties != null) { foreach (var property in model.MemberProperties //ensure the property they are posting exists - .Where(p => member.ContentType.PropertyTypeExists(p.Alias)) + .Where(p => memberType.PropertyTypeExists(p.Alias)) .Where(property => member.Properties.Contains(property.Alias)) //needs to be editable - .Where(p => member.ContentType.MemberCanEditProperty(p.Alias))) + .Where(p => memberType.MemberCanEditProperty(p.Alias))) { member.Properties[property.Alias].SetValue(property.Value); } @@ -409,7 +411,7 @@ namespace Umbraco.Web.Security model.LastPasswordChangedDate = membershipUser.LastPasswordChangedDate; - var memberType = member.ContentType; + var memberType = _memberTypeService.Get(member.ContentTypeId); var builtIns = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray(); diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 68d7fbb3fd..162d001e96 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; @@ -50,8 +49,7 @@ namespace Umbraco.Web.Trees /// /// Tree use. /// - [HttpQueryStringFilter("queryStrings")] - public async Task GetApplicationTrees(string application, string tree, FormDataCollection queryStrings, TreeUse use = TreeUse.Main) + public async Task GetApplicationTrees(string application, string tree, [System.Web.Http.ModelBinding.ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings, TreeUse use = TreeUse.Main) { application = application.CleanForXss(); diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index ca2f2031bb..e521deca40 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -14,6 +14,7 @@ using Umbraco.Web.Models.Trees; using Umbraco.Web.WebApi.Filters; using System.Globalization; using Umbraco.Core.Models.Entities; +using System.Web.Http.ModelBinding; using Umbraco.Web.Actions; using Umbraco.Web.Composing; @@ -30,8 +31,7 @@ namespace Umbraco.Web.Trees /// /// /// - [HttpQueryStringFilter("queryStrings")] - public TreeNode GetTreeNode(string id, FormDataCollection queryStrings) + public TreeNode GetTreeNode(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings) { int asInt; Guid asGuid = Guid.Empty; diff --git a/src/Umbraco.Web/Trees/MemberTreeController.cs b/src/Umbraco.Web/Trees/MemberTreeController.cs index 430c5d2111..6107540c0c 100644 --- a/src/Umbraco.Web/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberTreeController.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http; using System.Net.Http.Formatting; using System.Web.Http; +using System.Web.Http.ModelBinding; using System.Web.Security; using Umbraco.Core; using Umbraco.Core.Models; @@ -49,8 +50,7 @@ namespace Umbraco.Web.Trees /// /// /// - [HttpQueryStringFilter("queryStrings")] - public TreeNode GetTreeNode(string id, FormDataCollection queryStrings) + public TreeNode GetTreeNode(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings) { var node = GetSingleTreeNode(id, queryStrings); diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs index e3946ce532..f7c2b2460e 100644 --- a/src/Umbraco.Web/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.Linq; using System.Net.Http.Formatting; +using System.Web.Http.ModelBinding; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; @@ -45,7 +46,7 @@ namespace Umbraco.Web.Trees /// We are allowing an arbitrary number of query strings to be passed in so that developers are able to persist custom data from the front-end /// to the back end to be used in the query for model data. /// - protected abstract TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings); + protected abstract TreeNodeCollection GetTreeNodes(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings); /// /// Returns the menu structure for the node @@ -53,7 +54,7 @@ namespace Umbraco.Web.Trees /// /// /// - protected abstract MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings); + protected abstract MenuItemCollection GetMenuForNode(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings); /// /// The name to display on the root node @@ -86,8 +87,7 @@ namespace Umbraco.Web.Trees /// /// /// - [HttpQueryStringFilter("queryStrings")] - public TreeNode GetRootNode(FormDataCollection queryStrings) + public TreeNode GetRootNode([ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings) { if (queryStrings == null) queryStrings = new FormDataCollection(""); var node = CreateRootNode(queryStrings); @@ -126,8 +126,7 @@ namespace Umbraco.Web.Trees /// We are allowing an arbitrary number of query strings to be passed in so that developers are able to persist custom data from the front-end /// to the back end to be used in the query for model data. /// - [HttpQueryStringFilter("queryStrings")] - public TreeNodeCollection GetNodes(string id, FormDataCollection queryStrings) + public TreeNodeCollection GetNodes(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings) { if (queryStrings == null) queryStrings = new FormDataCollection(""); var nodes = GetTreeNodes(id, queryStrings); @@ -158,8 +157,7 @@ namespace Umbraco.Web.Trees /// /// /// - [HttpQueryStringFilter("queryStrings")] - public MenuItemCollection GetMenu(string id, FormDataCollection queryStrings) + public MenuItemCollection GetMenu(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormDataCollection queryStrings) { if (queryStrings == null) queryStrings = new FormDataCollection(""); var menu = GetMenuForNode(id, queryStrings); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f9fa29f7db..8699540e4b 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -60,32 +60,32 @@ - + - + 2.6.2.25 - + - - - - - - - - - + + + + + + + + + - + @@ -130,7 +130,6 @@ - @@ -284,6 +283,7 @@ + @@ -1058,7 +1058,6 @@ - diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 962d181d7b..d2da4d1646 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -73,7 +73,7 @@ namespace Umbraco.Web #endregion // ensures that we can return the specified value - T Ensure(T o) where T : class => o ?? throw new InvalidOperationException(""); // fixme + T Ensure(T o) where T : class => o ?? throw new InvalidOperationException("This UmbracoHelper instance has not been initialized."); private IUmbracoComponentRenderer ComponentRenderer => Ensure(_componentRenderer); private ICultureDictionaryFactory CultureDictionaryFactory => Ensure(_cultureDictionaryFactory); diff --git a/src/Umbraco.Web/WebApi/Filters/HttpQueryStringFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/HttpQueryStringFilterAttribute.cs deleted file mode 100644 index eea4ef7e67..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/HttpQueryStringFilterAttribute.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http.Formatting; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Allows an Action to execute with an arbitrary number of QueryStrings - /// - /// - /// Just like you can POST an arbitrary number of parameters to an Action, you can't GET an arbitrary number - /// but this will allow you to do it - /// - public sealed class HttpQueryStringFilterAttribute : ActionFilterAttribute - { - public string ParameterName { get; private set; } - - public HttpQueryStringFilterAttribute(string parameterName) - { - if (string.IsNullOrEmpty(parameterName)) - throw new ArgumentException("ParameterName is required."); - ParameterName = parameterName; - } - - public override void OnActionExecuting(HttpActionContext actionContext) - { - //get the query strings from the request properties - if (actionContext.Request.Properties.ContainsKey("MS_QueryNameValuePairs")) - { - var queryStrings = actionContext.Request.Properties["MS_QueryNameValuePairs"] as IEnumerable>; - if (queryStrings == null) return; - - var formData = new FormDataCollection(queryStrings); - - actionContext.ActionArguments[ParameterName] = formData; - } - - base.OnActionExecuting(actionContext); - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/HttpQueryStringModelBinder.cs b/src/Umbraco.Web/WebApi/Filters/HttpQueryStringModelBinder.cs new file mode 100644 index 0000000000..6ffbb239f8 --- /dev/null +++ b/src/Umbraco.Web/WebApi/Filters/HttpQueryStringModelBinder.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Net.Http.Formatting; +using System.Web.Http.Controllers; +using System.Web.Http.ModelBinding; + +namespace Umbraco.Web.WebApi.Filters +{ + /// + /// Allows an Action to execute with an arbitrary number of QueryStrings + /// + /// + /// Just like you can POST an arbitrary number of parameters to an Action, you can't GET an arbitrary number + /// but this will allow you to do it + /// + public sealed class HttpQueryStringModelBinder : IModelBinder + { + public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) + { + //get the query strings from the request properties + if (actionContext.Request.Properties.ContainsKey("MS_QueryNameValuePairs")) + { + if (actionContext.Request.Properties["MS_QueryNameValuePairs"] is IEnumerable> queryStrings) + { + var formData = new FormDataCollection(queryStrings); + bindingContext.Model = formData; + return true; + } + } + return false; + } + } +} \ No newline at end of file