From ed82bd05c66d8098a1c02d4dc67966e5e607ebe9 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 8 Nov 2019 14:27:27 +0100 Subject: [PATCH] AB3649 - Abstracted IPropertyType, IProperty and IPropertyValue --- src/Umbraco.Abstractions/Models/IProperty.cs | 100 ++++++++++++++++++ .../Models/IPropertyType.cs | 43 ++++++++ .../Models/IPropertyValue.cs | 34 ++++++ .../ConfigurationFieldAttribute.cs | 0 .../PropertyEditors/GridEditor.cs | 35 +++--- .../PropertyEditors/IConfigurationEditor.cs | 0 .../CompositionExtensions_Essentials.cs | 2 + .../ContentVariationExtensions.cs | 12 +-- src/Umbraco.Core/IO/IMediaFileSystem.cs | 4 +- src/Umbraco.Core/IO/MediaFileSystem.cs | 4 +- .../Manifest/DataEditorConverter.cs | 26 ++++- .../Manifest/ManifestDashboard.cs | 8 +- src/Umbraco.Core/Manifest/ManifestParser.cs | 15 ++- src/Umbraco.Core/Models/IDataValueEditor.cs | 8 +- src/Umbraco.Core/Models/Property.cs | 36 +++---- src/Umbraco.Core/Models/PropertyType.cs | 6 +- .../ConfigurationFieldsExtensions.cs | 34 ------ .../PropertyEditors/DataValueEditor.cs | 15 +-- .../Services/PropertyValidationService.cs | 6 +- src/Umbraco.Core/Umbraco.Core.csproj | 19 ++-- .../Umbraco.ModelsBuilder.Embedded.csproj | 4 +- src/Umbraco.Tests/App.config | 4 + src/Umbraco.Tests/Models/PropertyTypeTests.cs | 10 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 + src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 +- .../PropertyEditors/DateValueEditor.cs | 2 +- .../PropertyEditors/GridPropertyEditor.cs | 2 +- .../ImageCropperPropertyValueEditor.cs | 4 +- .../MultiUrlPickerValueEditor.cs | 2 +- .../MultipleTextStringPropertyEditor.cs | 2 +- .../PropertyEditors/MultipleValueEditor.cs | 2 +- .../NestedContentPropertyEditor.cs | 4 +- .../PropertyEditors/RichTextPropertyEditor.cs | 2 +- .../PropertyEditors/TextOnlyValueEditor.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 3 +- 36 files changed, 311 insertions(+), 146 deletions(-) create mode 100644 src/Umbraco.Abstractions/Models/IProperty.cs create mode 100644 src/Umbraco.Abstractions/Models/IPropertyType.cs create mode 100644 src/Umbraco.Abstractions/Models/IPropertyValue.cs rename src/{Umbraco.Core => Umbraco.Abstractions}/PropertyEditors/ConfigurationFieldAttribute.cs (100%) rename src/{Umbraco.Core => Umbraco.Abstractions}/PropertyEditors/GridEditor.cs (68%) rename src/{Umbraco.Core => Umbraco.Abstractions}/PropertyEditors/IConfigurationEditor.cs (100%) delete mode 100644 src/Umbraco.Core/PropertyEditors/ConfigurationFieldsExtensions.cs diff --git a/src/Umbraco.Abstractions/Models/IProperty.cs b/src/Umbraco.Abstractions/Models/IProperty.cs new file mode 100644 index 0000000000..308f4ae851 --- /dev/null +++ b/src/Umbraco.Abstractions/Models/IProperty.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Models.Entities; + +namespace Umbraco.Core.Models +{ + public interface IProperty + { + /// + /// Returns the PropertyType, which this Property is based on + /// + IPropertyType PropertyType { get; } + + /// + /// Gets the list of values. + /// + IReadOnlyCollection Values { get; set; } + + /// + /// Returns the Alias of the PropertyType, which this Property is based on + /// + string Alias { get; } + + /// + int Id { get; set; } + + /// + Guid Key { get; set; } + + /// + DateTime CreateDate { get; set; } + + /// + DateTime UpdateDate { get; set; } + + /// + DateTime? DeleteDate { get; set; } // no change tracking - not persisted + + /// + bool HasIdentity { get; } + + /// + /// Gets the value. + /// + object GetValue(string culture = null, string segment = null, bool published = false); + + /// + /// Sets a value. + /// + void SetValue(object value, string culture = null, string segment = null); + + /// + /// Resets the entity identity. + /// + void ResetIdentity(); + + bool Equals(EntityBase other); + bool Equals(object obj); + int GetHashCode(); + object DeepClone(); + + /// + bool IsDirty(); + + /// + bool IsPropertyDirty(string propertyName); + + /// + IEnumerable GetDirtyProperties(); + + /// + /// Saves dirty properties so they can be checked with WasDirty. + void ResetDirtyProperties(); + + /// + bool WasDirty(); + + /// + bool WasPropertyDirty(string propertyName); + + /// + void ResetWereDirtyProperties(); + + /// + void ResetDirtyProperties(bool rememberDirty); + + /// + IEnumerable GetWereDirtyProperties(); + + /// + /// Disables change tracking. + /// + void DisableChangeTracking(); + + /// + /// Enables change tracking. + /// + void EnableChangeTracking(); + } +} diff --git a/src/Umbraco.Abstractions/Models/IPropertyType.cs b/src/Umbraco.Abstractions/Models/IPropertyType.cs new file mode 100644 index 0000000000..4447a858ab --- /dev/null +++ b/src/Umbraco.Abstractions/Models/IPropertyType.cs @@ -0,0 +1,43 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Models.Entities; + +namespace Umbraco.Core.Models +{ + public interface IPropertyType : IEntity + { + [DataMember] + string Name { get; } + [DataMember] + string Alias { get; } + [DataMember] + string Description { get; } + [DataMember] + int DataTypeId { get; } + [DataMember] + Guid DataTypeKey { get; } + [DataMember] + string PropertyEditorAlias { get; } + [DataMember] + ValueStorageType ValueStorageType { get; } + [DataMember] + Lazy PropertyGroupId { get; } + [DataMember] + bool Mandatory { get; } + [DataMember] + int SortOrder { get; } + [DataMember] + string ValidationRegExp { get; } + + bool SupportsPublishing { get; } + + ContentVariation Variations { get; } + + + + bool SupportsVariation(string culture, string segment, bool wildcards = false); + object ConvertAssignedValue(object value); + + + } +} diff --git a/src/Umbraco.Abstractions/Models/IPropertyValue.cs b/src/Umbraco.Abstractions/Models/IPropertyValue.cs new file mode 100644 index 0000000000..abc459a72f --- /dev/null +++ b/src/Umbraco.Abstractions/Models/IPropertyValue.cs @@ -0,0 +1,34 @@ +namespace Umbraco.Core.Models +{ + public interface IPropertyValue + { + /// + /// Gets or sets the culture of the property. + /// + /// The culture is either null (invariant) or a non-empty string. If the property is + /// set with an empty or whitespace value, its value is converted to null. + string Culture { get; set; } + + /// + /// Gets or sets the segment of the property. + /// + /// The segment is either null (neutral) or a non-empty string. If the property is + /// set with an empty or whitespace value, its value is converted to null. + string Segment { get; set; } + + /// + /// Gets or sets the edited value of the property. + /// + object EditedValue { get; set; } + + /// + /// Gets or sets the published value of the property. + /// + object PublishedValue { get; set; } + + /// + /// Clones the property value. + /// + IPropertyValue Clone(); + } +} diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationFieldAttribute.cs b/src/Umbraco.Abstractions/PropertyEditors/ConfigurationFieldAttribute.cs similarity index 100% rename from src/Umbraco.Core/PropertyEditors/ConfigurationFieldAttribute.cs rename to src/Umbraco.Abstractions/PropertyEditors/ConfigurationFieldAttribute.cs diff --git a/src/Umbraco.Core/PropertyEditors/GridEditor.cs b/src/Umbraco.Abstractions/PropertyEditors/GridEditor.cs similarity index 68% rename from src/Umbraco.Core/PropertyEditors/GridEditor.cs rename to src/Umbraco.Abstractions/PropertyEditors/GridEditor.cs index 388e79675c..7af72cf5ea 100644 --- a/src/Umbraco.Core/PropertyEditors/GridEditor.cs +++ b/src/Umbraco.Abstractions/PropertyEditors/GridEditor.cs @@ -1,48 +1,37 @@ using System.Collections.Generic; -using Newtonsoft.Json; -using Umbraco.Core.Composing; +using System.Runtime.Serialization; using Umbraco.Core.Configuration.Grid; -using Umbraco.Core.IO; namespace Umbraco.Core.PropertyEditors { + + [DataContract] public class GridEditor : IGridEditorConfig { - private string _view; - private string _render; - public GridEditor() { Config = new Dictionary(); } - [JsonProperty("name", Required = Required.Always)] + [DataMember(Name = "name", IsRequired = true)] public string Name { get; set; } - [JsonProperty("nameTemplate")] + [DataMember(Name = "nameTemplate")] public string NameTemplate { get; set; } - [JsonProperty("alias", Required = Required.Always)] + [DataMember(Name = "alias", IsRequired = true)] public string Alias { get; set; } - [JsonProperty("view", Required = Required.Always)] - public string View - { - get => _view; - set => _view = Current.IOHelper.ResolveVirtualUrl(value); - } + [DataMember(Name = "view", IsRequired = true)] + public string View{ get; set; } - [JsonProperty("render")] - public string Render - { - get => _render; - set => _render = Current.IOHelper.ResolveVirtualUrl(value); - } + [DataMember(Name = "render")] + public string Render { get; set; } - [JsonProperty("icon", Required = Required.Always)] + [DataMember(Name = "icon", IsRequired = true)] public string Icon { get; set; } - [JsonProperty("config")] + [DataMember(Name = "config")] public IDictionary Config { get; set; } protected bool Equals(GridEditor other) diff --git a/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs b/src/Umbraco.Abstractions/PropertyEditors/IConfigurationEditor.cs similarity index 100% rename from src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs rename to src/Umbraco.Abstractions/PropertyEditors/IConfigurationEditor.cs diff --git a/src/Umbraco.Core/CompositionExtensions_Essentials.cs b/src/Umbraco.Core/CompositionExtensions_Essentials.cs index b85479716c..34c9492072 100644 --- a/src/Umbraco.Core/CompositionExtensions_Essentials.cs +++ b/src/Umbraco.Core/CompositionExtensions_Essentials.cs @@ -1,5 +1,6 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -30,6 +31,7 @@ namespace Umbraco.Core composition.RegisterUnique(factory => factory.GetInstance().SqlContext); composition.RegisterUnique(typeLoader); composition.RegisterUnique(state); + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Core/ContentVariationExtensions.cs b/src/Umbraco.Core/ContentVariationExtensions.cs index 5b157307ab..bdcf300f3f 100644 --- a/src/Umbraco.Core/ContentVariationExtensions.cs +++ b/src/Umbraco.Core/ContentVariationExtensions.cs @@ -50,18 +50,18 @@ namespace Umbraco.Core /// Determines whether the property type varies by culture. /// /// And then it could also vary by segment. - public static bool VariesByCulture(this PropertyType propertyType) => propertyType.Variations.VariesByCulture(); + public static bool VariesByCulture(this IPropertyType propertyType) => propertyType.Variations.VariesByCulture(); /// /// Determines whether the property type varies by segment. /// /// And then it could also vary by culture. - public static bool VariesBySegment(this PropertyType propertyType) => propertyType.Variations.VariesBySegment(); + public static bool VariesBySegment(this IPropertyType propertyType) => propertyType.Variations.VariesBySegment(); /// /// Determines whether the property type varies by culture and segment. /// - public static bool VariesByCultureAndSegment(this PropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment(); + public static bool VariesByCultureAndSegment(this IPropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment(); /// /// Determines whether the content type is invariant. @@ -161,13 +161,13 @@ namespace Umbraco.Core if (variation.VariesByCulture()) { // varies by culture - // in exact mode, the culture cannot be null + // in exact mode, the culture cannot be null if (exact && culture == null) { if (throwIfInvalid) throw new NotSupportedException($"Culture may not be null because culture variation is enabled."); return false; - } + } } else { @@ -180,7 +180,7 @@ namespace Umbraco.Core throw new NotSupportedException($"Culture \"{culture}\" is invalid because culture variation is disabled."); return false; } - } + } // if it does not vary by segment // the segment cannot have a value diff --git a/src/Umbraco.Core/IO/IMediaFileSystem.cs b/src/Umbraco.Core/IO/IMediaFileSystem.cs index ed88516135..8ed0ba60ca 100644 --- a/src/Umbraco.Core/IO/IMediaFileSystem.cs +++ b/src/Umbraco.Core/IO/IMediaFileSystem.cs @@ -52,7 +52,7 @@ namespace Umbraco.Core.IO /// If an is provided then that file (and associated thumbnails if any) is deleted /// before the new file is saved, and depending on the media path scheme, the folder may be reused for the new file. /// - string StoreFile(IContentBase content, PropertyType propertyType, string filename, Stream filestream, string oldpath); + string StoreFile(IContentBase content, IPropertyType propertyType, string filename, Stream filestream, string oldpath); /// /// Copies a media file as a new media file, associated to a property of a content item. @@ -61,6 +61,6 @@ namespace Umbraco.Core.IO /// The property type owning the copy of the media file. /// The filesystem-relative path to the source media file. /// The filesystem-relative path to the copy of the media file. - string CopyFile(IContentBase content, PropertyType propertyType, string sourcepath); + string CopyFile(IContentBase content, IPropertyType propertyType, string sourcepath); } } diff --git a/src/Umbraco.Core/IO/MediaFileSystem.cs b/src/Umbraco.Core/IO/MediaFileSystem.cs index 2de7bc2f81..edcbfadf0d 100644 --- a/src/Umbraco.Core/IO/MediaFileSystem.cs +++ b/src/Umbraco.Core/IO/MediaFileSystem.cs @@ -88,7 +88,7 @@ namespace Umbraco.Core.IO #region Associated Media Files /// - public string StoreFile(IContentBase content, PropertyType propertyType, string filename, Stream filestream, string oldpath) + public string StoreFile(IContentBase content, IPropertyType propertyType, string filename, Stream filestream, string oldpath) { if (content == null) throw new ArgumentNullException(nameof(content)); if (propertyType == null) throw new ArgumentNullException(nameof(propertyType)); @@ -107,7 +107,7 @@ namespace Umbraco.Core.IO } /// - public string CopyFile(IContentBase content, PropertyType propertyType, string sourcepath) + public string CopyFile(IContentBase content, IPropertyType propertyType, string sourcepath) { if (content == null) throw new ArgumentNullException(nameof(content)); if (propertyType == null) throw new ArgumentNullException(nameof(propertyType)); diff --git a/src/Umbraco.Core/Manifest/DataEditorConverter.cs b/src/Umbraco.Core/Manifest/DataEditorConverter.cs index 86982e17f2..86347d3894 100644 --- a/src/Umbraco.Core/Manifest/DataEditorConverter.cs +++ b/src/Umbraco.Core/Manifest/DataEditorConverter.cs @@ -1,6 +1,8 @@ using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; @@ -13,13 +15,15 @@ namespace Umbraco.Core.Manifest internal class DataEditorConverter : JsonReadConverter { private readonly ILogger _logger; + private readonly IIOHelper _ioHelper; /// /// Initializes a new instance of the class. /// - public DataEditorConverter(ILogger logger) + public DataEditorConverter(ILogger logger, IIOHelper ioHelper) { _logger = logger; + _ioHelper = ioHelper; } /// @@ -62,11 +66,11 @@ namespace Umbraco.Core.Manifest PrepareForPropertyEditor(jobject, dataEditor); else PrepareForParameterEditor(jobject, dataEditor); - + base.Deserialize(jobject, target, serializer); } - private static void PrepareForPropertyEditor(JObject jobject, DataEditor target) + private void PrepareForPropertyEditor(JObject jobject, DataEditor target) { if (jobject["editor"] == null) throw new InvalidOperationException("Missing 'editor' value."); @@ -86,6 +90,9 @@ namespace Umbraco.Core.Manifest if (jobject["editor"]["validation"] is JObject validation) jobject["editor"]["validation"] = RewriteValidators(validation); + if(jobject["editor"]["view"] is JValue view) + jobject["editor"]["view"] = RewriteVirtualUrl(view); + if (jobject["prevalues"] is JObject config) { // explicitly assign a configuration editor of type ConfigurationEditor @@ -100,6 +107,9 @@ namespace Umbraco.Core.Manifest { if (field["validation"] is JObject fvalidation) field["validation"] = RewriteValidators(fvalidation); + + if(field["view"] is JValue fview) + field["view"] = RewriteVirtualUrl(fview); } } @@ -118,7 +128,12 @@ namespace Umbraco.Core.Manifest } } - private static void PrepareForParameterEditor(JObject jobject, DataEditor target) + private string RewriteVirtualUrl(JValue view) + { + return _ioHelper.ResolveVirtualUrl(view.Value as string); + } + + private void PrepareForParameterEditor(JObject jobject, DataEditor target) { // in a manifest, a parameter editor looks like: // @@ -148,6 +163,9 @@ namespace Umbraco.Core.Manifest jobject["defaultConfig"] = config; jobject.Remove("config"); } + + if(jobject["editor"]?["view"] is JValue view) // We need to null check, if view do not exists, then editor do not exists + jobject["editor"]["view"] = RewriteVirtualUrl(view); } private static JArray RewriteValidators(JObject validation) diff --git a/src/Umbraco.Core/Manifest/ManifestDashboard.cs b/src/Umbraco.Core/Manifest/ManifestDashboard.cs index 33af12e3cd..2642ca3646 100644 --- a/src/Umbraco.Core/Manifest/ManifestDashboard.cs +++ b/src/Umbraco.Core/Manifest/ManifestDashboard.cs @@ -9,8 +9,6 @@ namespace Umbraco.Core.Manifest { public class ManifestDashboard : IDashboard { - private string _view; - [JsonProperty("alias", Required = Required.Always)] public string Alias { get; set; } @@ -19,11 +17,7 @@ namespace Umbraco.Core.Manifest public int Weight { get; set; } [JsonProperty("view", Required = Required.Always)] - public string View - { - get => _view; - set => _view = Current.IOHelper.ResolveVirtualUrl(value); - } + public string View { get; set; } [JsonProperty("sections")] public string[] Sections { get; set; } = Array.Empty(); diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index 7f2a1825b4..bf70def9dc 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -163,7 +163,7 @@ namespace Umbraco.Core.Manifest throw new ArgumentNullOrEmptyException(nameof(text)); var manifest = JsonConvert.DeserializeObject(text, - new DataEditorConverter(_logger), + new DataEditorConverter(_logger, _ioHelper), new ValueValidatorConverter(_validators), new DashboardAccessRuleConverter()); @@ -172,6 +172,19 @@ namespace Umbraco.Core.Manifest manifest.Scripts[i] = _ioHelper.ResolveVirtualUrl(manifest.Scripts[i]); for (var i = 0; i < manifest.Stylesheets.Length; i++) manifest.Stylesheets[i] = _ioHelper.ResolveVirtualUrl(manifest.Stylesheets[i]); + foreach (var contentApp in manifest.ContentApps) + { + contentApp.View = _ioHelper.ResolveVirtualUrl(contentApp.View); + } + foreach (var dashboard in manifest.Dashboards) + { + dashboard.View = _ioHelper.ResolveVirtualUrl(dashboard.View); + } + foreach (var gridEditor in manifest.GridEditors) + { + gridEditor.View = _ioHelper.ResolveVirtualUrl(gridEditor.View); + gridEditor.Render = _ioHelper.ResolveVirtualUrl(gridEditor.Render); + } // add property editors that are also parameter editors, to the parameter editors list // (the manifest format is kinda legacy) diff --git a/src/Umbraco.Core/Models/IDataValueEditor.cs b/src/Umbraco.Core/Models/IDataValueEditor.cs index cb68531cc7..5a1c6fd29d 100644 --- a/src/Umbraco.Core/Models/IDataValueEditor.cs +++ b/src/Umbraco.Core/Models/IDataValueEditor.cs @@ -59,12 +59,12 @@ namespace Umbraco.Core.PropertyEditors /// /// Converts a property value to a value for the editor. /// - object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null); + object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null); // TODO: / deal with this when unplugging the xml cache // why property vs propertyType? services should be injected! etc... - IEnumerable ConvertDbToXml(Property property, IDataTypeService dataTypeService, ILocalizationService localizationService, bool published); - XNode ConvertDbToXml(PropertyType propertyType, object value, IDataTypeService dataTypeService); - string ConvertDbToString(PropertyType propertyType, object value, IDataTypeService dataTypeService); + IEnumerable ConvertDbToXml(IProperty property, IDataTypeService dataTypeService, ILocalizationService localizationService, bool published); + XNode ConvertDbToXml(IPropertyType propertyType, object value, IDataTypeService dataTypeService); + string ConvertDbToString(IPropertyType propertyType, object value, IDataTypeService dataTypeService); } } diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index 76349823ac..9b2cda67c1 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -13,16 +13,16 @@ namespace Umbraco.Core.Models /// [Serializable] [DataContract(IsReference = true)] - public class Property : EntityBase + public class Property : EntityBase, IProperty { // _values contains all property values, including the invariant-neutral value - private List _values = new List(); + private List _values = new List(); // _pvalue contains the invariant-neutral property value - private PropertyValue _pvalue; + private IPropertyValue _pvalue; // _vvalues contains the (indexed) variant property values - private Dictionary _vvalues; + private Dictionary _vvalues; /// /// Initializes a new instance of the class. @@ -50,7 +50,7 @@ namespace Umbraco.Core.Models /// /// Represents a property value. /// - public class PropertyValue + public class PropertyValue : IPropertyValue { // TODO: Either we allow change tracking at this class level, or we add some special change tracking collections to the Property // class to deal with change tracking which variants have changed @@ -66,7 +66,7 @@ namespace Umbraco.Core.Models public string Culture { get => _culture; - internal set => _culture = value.IsNullOrWhiteSpace() ? null : value.ToLowerInvariant(); + set => _culture = value.IsNullOrWhiteSpace() ? null : value.ToLowerInvariant(); } /// @@ -77,23 +77,23 @@ namespace Umbraco.Core.Models public string Segment { get => _segment; - internal set => _segment = value?.ToLowerInvariant(); + set => _segment = value?.ToLowerInvariant(); } /// /// Gets or sets the edited value of the property. /// - public object EditedValue { get; internal set; } + public object EditedValue { get; set; } /// /// Gets or sets the published value of the property. /// - public object PublishedValue { get; internal set; } + public object PublishedValue { get; set; } /// /// Clones the property value. /// - public PropertyValue Clone() + public IPropertyValue Clone() => new PropertyValue { _culture = _culture, _segment = _segment, PublishedValue = PublishedValue, EditedValue = EditedValue }; } @@ -121,13 +121,13 @@ namespace Umbraco.Core.Models /// Returns the PropertyType, which this Property is based on /// [IgnoreDataMember] - public PropertyType PropertyType { get; private set; } + public IPropertyType PropertyType { get; private set; } /// /// Gets the list of values. /// [DataMember] - public IReadOnlyCollection Values + public IReadOnlyCollection Values { get => _values; set @@ -180,7 +180,7 @@ namespace Umbraco.Core.Models : null; } - private object GetPropertyValue(PropertyValue pvalue, bool published) + private object GetPropertyValue(IPropertyValue pvalue, bool published) { if (pvalue == null) return null; @@ -240,7 +240,7 @@ namespace Umbraco.Core.Models UnpublishValue(pvalue); } - private void PublishValue(PropertyValue pvalue) + private void PublishValue(IPropertyValue pvalue) { if (pvalue == null) return; @@ -251,7 +251,7 @@ namespace Umbraco.Core.Models DetectChanges(pvalue.EditedValue, origValue, nameof(Values), PropertyValueComparer, false); } - private void UnpublishValue(PropertyValue pvalue) + private void UnpublishValue(IPropertyValue pvalue) { if (pvalue == null) return; @@ -294,7 +294,7 @@ namespace Umbraco.Core.Models pvalue.EditedValue = value; } - private (PropertyValue, bool) GetPValue(bool create) + private (IPropertyValue, bool) GetPValue(bool create) { var change = false; if (_pvalue == null) @@ -307,7 +307,7 @@ namespace Umbraco.Core.Models return (_pvalue, change); } - private (PropertyValue, bool) GetPValue(string culture, string segment, bool create) + private (IPropertyValue, bool) GetPValue(string culture, string segment, bool create) { if (culture == null && segment == null) return GetPValue(create); @@ -316,7 +316,7 @@ namespace Umbraco.Core.Models if (_vvalues == null) { if (!create) return (null, false); - _vvalues = new Dictionary(); + _vvalues = new Dictionary(); change = true; } var k = new CompositeNStringNStringKey(culture, segment); diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 40af478ab8..1448e099be 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Models [Serializable] [DataContract(IsReference = true)] [DebuggerDisplay("Id: {Id}, Name: {Name}, Alias: {Alias}")] - public class PropertyType : EntityBase, IEquatable + public class PropertyType : EntityBase, IPropertyType, IEquatable { private readonly bool _forceValueStorageType; private string _name; @@ -160,7 +160,7 @@ namespace Umbraco.Core.Models /// Gets or sets the database type for storing value for this property type. /// [DataMember] - internal ValueStorageType ValueStorageType + public ValueStorageType ValueStorageType { get => _valueStorageType; set @@ -175,7 +175,7 @@ namespace Umbraco.Core.Models /// /// For generic properties, the value is null. [DataMember] - internal Lazy PropertyGroupId + public Lazy PropertyGroupId { get => _propertyGroupId; set => SetPropertyValueAndDetectChanges(value, ref _propertyGroupId, nameof(PropertyGroupId)); diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationFieldsExtensions.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationFieldsExtensions.cs deleted file mode 100644 index 25fba622d5..0000000000 --- a/src/Umbraco.Core/PropertyEditors/ConfigurationFieldsExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.PropertyEditors -{ - public static partial class ConfigurationFieldsExtensions - { - /// - /// Adds a configuration field. - /// - /// The list of configuration fields. - /// The key (alias) of the field. - /// The name (label) of the field. - /// The description for the field. - /// The path to the editor view to be used for the field. - /// Optional configuration used for field's editor. - public static void Add( - this List fields, - string key, - string name, - string description, - string view, - IDictionary config = null) - { - fields.Add(new ConfigurationField - { - Key = key, - Name = name, - Description = description, - View = view, - Config = config, - }); - } - } -} diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs index a9ce27d964..396d32c833 100644 --- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs @@ -7,7 +7,6 @@ using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.Composing; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; @@ -72,11 +71,7 @@ namespace Umbraco.Core.PropertyEditors /// folder, or (3) a view name which maps to views/propertyeditors/{view}/{view}.html. /// [JsonProperty("view", Required = Required.Always)] - public string View - { - get => _view; - set => _view = Current.IOHelper.ResolveVirtualUrl(value); - } + public string View { get; set; } /// /// The value type which reflects how it is validated and stored in the database @@ -237,7 +232,7 @@ namespace Umbraco.Core.PropertyEditors /// The object returned will automatically be serialized into json notation. For most property editors /// the value returned is probably just a string but in some cases a json structure will be returned. /// - public virtual object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public virtual object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null) return string.Empty; @@ -288,7 +283,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Converts a property to Xml fragments. /// - public IEnumerable ConvertDbToXml(Property property, IDataTypeService dataTypeService, ILocalizationService localizationService, bool published) + public IEnumerable ConvertDbToXml(IProperty property, IDataTypeService dataTypeService, ILocalizationService localizationService, bool published) { published &= property.PropertyType.SupportsPublishing; @@ -322,7 +317,7 @@ namespace Umbraco.Core.PropertyEditors /// Returns an XText or XCData instance which must be wrapped in a element. /// If the value is empty we will not return as CDATA since that will just take up more space in the file. /// - public XNode ConvertDbToXml(PropertyType propertyType, object value, IDataTypeService dataTypeService) + public XNode ConvertDbToXml(IPropertyType propertyType, object value, IDataTypeService dataTypeService) { //check for null or empty value, we don't want to return CDATA if that is the case if (value == null || value.ToString().IsNullOrWhiteSpace()) @@ -348,7 +343,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Converts a property value to a string. /// - public virtual string ConvertDbToString(PropertyType propertyType, object value, IDataTypeService dataTypeService) + public virtual string ConvertDbToString(IPropertyType propertyType, object value, IDataTypeService dataTypeService) { if (value == null) return string.Empty; diff --git a/src/Umbraco.Core/Services/PropertyValidationService.cs b/src/Umbraco.Core/Services/PropertyValidationService.cs index a037a83920..f619e5f47e 100644 --- a/src/Umbraco.Core/Services/PropertyValidationService.cs +++ b/src/Umbraco.Core/Services/PropertyValidationService.cs @@ -74,7 +74,7 @@ namespace Umbraco.Core.Services culture = culture.NullOrWhiteSpaceAsNull(); segment = segment.NullOrWhiteSpaceAsNull(); - Property.PropertyValue pvalue = null; + IPropertyValue pvalue = null; // if validating invariant/neutral, and it is supported, validate // (including ensuring that the value exists, if mandatory) @@ -120,7 +120,7 @@ namespace Umbraco.Core.Services /// /// /// True is property value is valid, otherwise false - private bool IsValidPropertyValue(Property property, object value) + private bool IsValidPropertyValue(IProperty property, object value) { return IsPropertyValueValid(property.PropertyType, value); } @@ -128,7 +128,7 @@ namespace Umbraco.Core.Services /// /// Determines whether a value is valid for this property type. /// - private bool IsPropertyValueValid(PropertyType propertyType, object value) + private bool IsPropertyValueValid(IPropertyType propertyType, object value) { var editor = _propertyEditors[propertyType.PropertyEditorAlias]; if (editor == null) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f22a29075f..45e25d9a8f 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -36,7 +36,6 @@ - @@ -65,11 +64,14 @@ all - 1.3.0 + 1.4.0 1.0.0 + + 4.6.0 + 1.0.5 runtime; build; native; contentfiles; analyzers @@ -91,19 +93,19 @@ - 2.8.0 + 2.9.0 2.0.1 - 3.0.0 + 3.1.0 2.0.0 - 1.0.0 + 1.1.0 1.0.3 @@ -112,7 +114,7 @@ 2.2.2 - 4.0.0 + 4.1.0 @@ -270,7 +272,6 @@ - @@ -282,8 +283,6 @@ - - @@ -483,7 +482,6 @@ - @@ -1000,7 +998,6 @@ - diff --git a/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj b/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj index 67919834ac..eb61e2a2c8 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj +++ b/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj @@ -34,7 +34,6 @@ - @@ -97,6 +96,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + 4.6.0 + diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 91047ba6a2..9eeb93384d 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -94,6 +94,10 @@ + + + + diff --git a/src/Umbraco.Tests/Models/PropertyTypeTests.cs b/src/Umbraco.Tests/Models/PropertyTypeTests.cs index 1bc99162af..b4d14e7bb5 100644 --- a/src/Umbraco.Tests/Models/PropertyTypeTests.cs +++ b/src/Umbraco.Tests/Models/PropertyTypeTests.cs @@ -54,7 +54,15 @@ namespace Umbraco.Tests.Models var allProps = clone.GetType().GetProperties(); foreach (var propertyInfo in allProps) { - Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(pt, null)); + var expected = propertyInfo.GetValue(pt, null); + var actual = propertyInfo.GetValue(clone, null); + if (propertyInfo.PropertyType == typeof(Lazy)) + { + expected = ((Lazy) expected).Value; + actual = ((Lazy) actual).Value; + } + + Assert.AreEqual(expected, actual, $"Value of propery: '{propertyInfo.Name}': {expected} != {actual}"); } } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index b9fd0f6640..149d48032b 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -219,6 +219,7 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); + Composition.RegisterUnique(); // register back office sections in the order we want them rendered Composition.WithCollectionBuilder().Append() diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index de76b94ff1..1292d2da2e 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -56,7 +56,6 @@ - @@ -107,6 +106,7 @@ + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index f2976716bb..a2ce0f95f7 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -70,7 +70,6 @@ - @@ -110,6 +109,7 @@ runtime; build; native; contentfiles; analyzers all + @@ -432,4 +432,4 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/DateValueEditor.cs b/src/Umbraco.Web/PropertyEditors/DateValueEditor.cs index a03ad4aa00..657e2b2b49 100644 --- a/src/Umbraco.Web/PropertyEditors/DateValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DateValueEditor.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.PropertyEditors Validators.Add(new DateTimeValidator()); } - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture= null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture= null, string segment = null) { var date = property.GetValue(culture, segment).TryConvertTo(); if (date.Success == false || date.Result == null) diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 24e2fc29a5..5964964ab7 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -115,7 +115,7 @@ namespace Umbraco.Web.PropertyEditors /// /// /// - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null) return string.Empty; diff --git a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs index 4aac8f54aa..fdeb726902 100644 --- a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.PropertyEditors /// This is called to merge in the prevalue crops with the value that is saved - similar to the property value converter for the front-end /// - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null) return null; @@ -161,7 +161,7 @@ namespace Umbraco.Web.PropertyEditors } - public override string ConvertDbToString(PropertyType propertyType, object value, IDataTypeService dataTypeService) + public override string ConvertDbToString(IPropertyType propertyType, object value, IDataTypeService dataTypeService) { if (value == null || string.IsNullOrEmpty(value.ToString())) return null; diff --git a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs index aa8fa73c7a..c2ad58a101 100644 --- a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs @@ -28,7 +28,7 @@ namespace Umbraco.Web.PropertyEditors _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var value = property.GetValue(culture, segment)?.ToString(); diff --git a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs index fa82bc555c..23ceb0f22a 100644 --- a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -95,7 +95,7 @@ namespace Umbraco.Web.PropertyEditors /// /// The legacy property editor saved this data as new line delimited! strange but we have to maintain that. /// - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); return val?.ToString().Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries) diff --git a/src/Umbraco.Web/PropertyEditors/MultipleValueEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleValueEditor.cs index bbeaff184e..4c59a8e3c5 100644 --- a/src/Umbraco.Web/PropertyEditors/MultipleValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultipleValueEditor.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.PropertyEditors /// /// /// - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var json = base.ToEditor(property, dataTypeService, culture, segment).ToString(); return JsonConvert.DeserializeObject(json) ?? Array.Empty(); diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs index f511a97cac..778b69d9db 100644 --- a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs @@ -92,7 +92,7 @@ namespace Umbraco.Web.PropertyEditors #region DB to String - public override string ConvertDbToString(PropertyType propertyType, object propertyValue, IDataTypeService dataTypeService) + public override string ConvertDbToString(IPropertyType propertyType, object propertyValue, IDataTypeService dataTypeService) { if (propertyValue == null || string.IsNullOrWhiteSpace(propertyValue.ToString())) return string.Empty; @@ -152,7 +152,7 @@ namespace Umbraco.Web.PropertyEditors // note: there is NO variant support here - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null || string.IsNullOrWhiteSpace(val.ToString())) diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs index 5743e9c1d5..03345bee3c 100644 --- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs @@ -92,7 +92,7 @@ namespace Umbraco.Web.PropertyEditors /// /// /// - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null) diff --git a/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs b/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs index 754cef1f31..f925daba30 100644 --- a/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.PropertyEditors /// /// The object returned will always be a string and if the database type is not a valid string type an exception is thrown /// - public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + public override object ToEditor(IProperty property, IDataTypeService dataTypeService, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 317786b970..bede1a1a6d 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -41,7 +41,6 @@ - @@ -1282,4 +1281,4 @@ - \ No newline at end of file +