diff --git a/src/Umbraco.Core/Components/CompositionExtensions.cs b/src/Umbraco.Core/Components/CompositionExtensions.cs
index dedbc9c3fc..7e94e4dc2b 100644
--- a/src/Umbraco.Core/Components/CompositionExtensions.cs
+++ b/src/Umbraco.Core/Components/CompositionExtensions.cs
@@ -67,8 +67,8 @@ namespace Umbraco.Core.Components
/// Gets the validators collection builder.
///
/// The composition.
- internal static ManifestValidatorCollectionBuilder Validators(this Composition composition)
- => composition.Container.GetInstance();
+ internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition)
+ => composition.Container.GetInstance();
///
/// Gets the post-migrations collection builder.
diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs
index b1f5810206..f462c1b6ea 100644
--- a/src/Umbraco.Core/Composing/Current.cs
+++ b/src/Umbraco.Core/Composing/Current.cs
@@ -117,8 +117,8 @@ namespace Umbraco.Core.Composing
public static ParameterEditorCollection ParameterEditors
=> Container.GetInstance();
- internal static ManifestValidatorCollection ManifestValidators
- => Container.GetInstance();
+ internal static ManifestValueValidatorCollection ManifestValidators
+ => Container.GetInstance();
internal static PackageActionCollection PackageActions
=> Container.GetInstance();
diff --git a/src/Umbraco.Core/Manifest/DataEditorConverter.cs b/src/Umbraco.Core/Manifest/DataEditorConverter.cs
index dad31aa62e..20efee1607 100644
--- a/src/Umbraco.Core/Manifest/DataEditorConverter.cs
+++ b/src/Umbraco.Core/Manifest/DataEditorConverter.cs
@@ -74,7 +74,7 @@ namespace Umbraco.Core.Manifest
// explicitely assign a value editor of type ValueEditor
// (else the deserializer will try to read it before setting it)
// (and besides it's an interface)
- target.ValueEditor = new DataValueEditor();
+ target.ExplicitValueEditor = new DataValueEditor();
// in the manifest, validators are a simple dictionary eg
// {
@@ -91,7 +91,7 @@ namespace Umbraco.Core.Manifest
// explicitely assign a configuration editor of type ConfigurationEditor
// (else the deserializer will try to read it before setting it)
// (and besides it's an interface)
- target.ConfigurationEditor = new ConfigurationEditor();
+ target.ExplicitConfigurationEditor = new ConfigurationEditor();
// see note about validators, above - same applies to field validators
if (config["fields"] is JArray jarray)
@@ -135,7 +135,7 @@ namespace Umbraco.Core.Manifest
if (jobject.Property("view") != null)
{
// explicitely assign a value editor of type ParameterValueEditor
- target.ValueEditor = new DataValueEditor();
+ target.ExplicitValueEditor = new DataValueEditor();
// move the 'view' property
jobject["editor"] = new JObject { ["view"] = jobject["view"] };
@@ -157,8 +157,8 @@ namespace Umbraco.Core.Manifest
foreach (var v in validation)
{
var key = v.Key;
- var val = v.Value?.Type == JTokenType.Boolean ? string.Empty : v.Value;
- var jo = new JObject { { "type", key }, { "config", val } };
+ var val = v.Value;
+ var jo = new JObject { { "type", key }, { "configuration", val } };
jarray.Add(jo);
}
diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs
index 11e4b18e44..32070b3542 100644
--- a/src/Umbraco.Core/Manifest/ManifestParser.cs
+++ b/src/Umbraco.Core/Manifest/ManifestParser.cs
@@ -21,21 +21,21 @@ namespace Umbraco.Core.Manifest
private readonly IRuntimeCacheProvider _cache;
private readonly ILogger _logger;
- private readonly ManifestValidatorCollection _validators;
+ private readonly ManifestValueValidatorCollection _validators;
private string _path;
///
/// Initializes a new instance of the class.
///
- public ManifestParser(IRuntimeCacheProvider cache, ManifestValidatorCollection validators, ILogger logger)
+ public ManifestParser(IRuntimeCacheProvider cache, ManifestValueValidatorCollection validators, ILogger logger)
: this(cache, validators, "~/App_Plugins", logger)
{ }
///
/// Initializes a new instance of the class.
///
- private ManifestParser(IRuntimeCacheProvider cache, ManifestValidatorCollection validators, string path, ILogger logger)
+ private ManifestParser(IRuntimeCacheProvider cache, ManifestValueValidatorCollection validators, string path, ILogger logger)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_validators = validators ?? throw new ArgumentNullException(nameof(validators));
@@ -141,7 +141,7 @@ namespace Umbraco.Core.Manifest
var manifest = JsonConvert.DeserializeObject(text,
new DataEditorConverter(_logger),
- new ManifestValidatorConverter(_validators));
+ new ValueValidatorConverter(_validators));
// scripts and stylesheets are raw string, must process here
for (var i = 0; i < manifest.Scripts.Length; i++)
diff --git a/src/Umbraco.Core/Manifest/ManifestValidatorConverter.cs b/src/Umbraco.Core/Manifest/ManifestValidatorConverter.cs
deleted file mode 100644
index d58a66e7b4..0000000000
--- a/src/Umbraco.Core/Manifest/ManifestValidatorConverter.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using Newtonsoft.Json.Linq;
-using Umbraco.Core.PropertyEditors;
-using Umbraco.Core.Serialization;
-
-namespace Umbraco.Core.Manifest
-{
- ///
- /// Implements a json read converter for .
- ///
- internal class ManifestValidatorConverter : JsonReadConverter
- {
- private readonly ManifestValidatorCollection _validators;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ManifestValidatorConverter(ManifestValidatorCollection validators)
- {
- _validators = validators;
- }
-
- protected override IValueValidator Create(Type objectType, string path, JObject jObject)
- {
- // all validators coming from manifests are ManifestPropertyValidator instances
- return new ManifestValueValidator(_validators);
- }
- }
-}
diff --git a/src/Umbraco.Core/Manifest/ValueValidatorConverter.cs b/src/Umbraco.Core/Manifest/ValueValidatorConverter.cs
new file mode 100644
index 0000000000..75b0b2573b
--- /dev/null
+++ b/src/Umbraco.Core/Manifest/ValueValidatorConverter.cs
@@ -0,0 +1,34 @@
+using System;
+using Newtonsoft.Json.Linq;
+using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.Serialization;
+
+namespace Umbraco.Core.Manifest
+{
+ ///
+ /// Implements a json read converter for .
+ ///
+ internal class ValueValidatorConverter : JsonReadConverter
+ {
+ private readonly ManifestValueValidatorCollection _validators;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ValueValidatorConverter(ManifestValueValidatorCollection validators)
+ {
+ _validators = validators;
+ }
+
+ protected override IValueValidator Create(Type objectType, string path, JObject jObject)
+ {
+ var type = jObject["type"].Value();
+ if (string.IsNullOrWhiteSpace(type))
+ throw new InvalidOperationException("Could not get the type of the validator.");
+
+ return _validators.Create(type);
+
+ // jObject["configuration"] is going to be deserialized in a Configuration property, if any
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
index 66f07b121b..484b761661 100644
--- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
+++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
@@ -153,7 +153,7 @@ namespace Umbraco.Core.Migrations.Install
private void CreateUser2UserGroupData()
{
- _database.Insert(new User2UserGroupDto { UserGroupId = 1, UserId = 0 });
+ _database.Insert(new User2UserGroupDto { UserGroupId = 1, UserId = Constants.Security.SuperId });
}
private void CreateUserGroup2AppData()
diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs
index 8b0e7d5327..9668864588 100644
--- a/src/Umbraco.Core/Models/DataType.cs
+++ b/src/Umbraco.Core/Models/DataType.cs
@@ -57,7 +57,7 @@ namespace Umbraco.Core.Models
var configuration = Configuration;
var json = JsonConvert.SerializeObject(configuration);
_editor = value;
- Configuration = _editor.ConfigurationEditor.FromDatabase(json);
+ Configuration = _editor.GetConfigurationEditor().FromDatabase(json);
}
}
@@ -85,7 +85,7 @@ namespace Umbraco.Core.Models
if (_hasConfiguration) return _configuration;
- _configuration = _editor.ConfigurationEditor.FromDatabase(_configurationJson);
+ _configuration = _editor.GetConfigurationEditor().FromDatabase(_configurationJson);
_hasConfiguration = true;
_configurationJson = null;
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Models
throw new ArgumentException("Configurations are kinda non-mutable. Do not reassign the same object.", nameof(value));
// validate configuration type
- if (!_editor.ConfigurationEditor.IsConfiguration(value))
+ if (!_editor.GetConfigurationEditor().IsConfiguration(value))
throw new ArgumentException($"Value of type {value.GetType().Name} cannot be a configuration for editor {_editor.Alias}, expecting.", nameof(value));
// extract database type from configuration object, if appropriate
@@ -167,7 +167,7 @@ namespace Umbraco.Core.Models
// else, create a Lazy de-serializer
var capturedConfiguration = _configurationJson;
var capturedEditor = _editor;
- return new Lazy
public bool IsPropertyValueValid(object value)
{
- var stringValue = Mandatory || !string.IsNullOrWhiteSpace(ValidationRegExp)
- ? value?.ToString()
- : null;
-
- // validate mandatory property value
- if (Mandatory && string.IsNullOrWhiteSpace(stringValue))
- return false;
-
- // validate regular expression if appropriate (have a regex and a string value)
- if (!string.IsNullOrWhiteSpace(ValidationRegExp) && !string.IsNullOrWhiteSpace(stringValue))
- {
- try
- {
- return new Regex(ValidationRegExp).IsMatch(stringValue);
- }
- catch
- {
- throw new Exception($"Invalid validation expression on property {Alias}.");
- }
- }
-
- // fixme - todo
- // ensure that the property value complies with the value storage type, ie can be saved
- // plug PropertyEditor validation - when it's a thing
-
- return true;
+ var editor = Current.PropertyEditors[_propertyEditorAlias]; // fixme inject?
+ var configuration = Current.Services.DataTypeService.GetDataType(_dataTypeId).Configuration; // fixme inject?
+ var valueEditor = editor.GetValueEditor(configuration);
+ return !valueEditor.Validate(value, Mandatory, ValidationRegExp).Any();
}
///
diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs
index 44335b2f74..2ec9f43a53 100644
--- a/src/Umbraco.Core/Models/UserExtensions.cs
+++ b/src/Umbraco.Core/Models/UserExtensions.cs
@@ -37,10 +37,10 @@ namespace Umbraco.Core.Models
///
/// Determines whether this user belongs to the administrators group.
///
+ /// The 'super' user does not automatically belongs to the administrators group.
public static bool IsAdmin(this IUser user)
{
if (user == null) throw new ArgumentNullException(nameof(user));
- // fixme should super always be admin?
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.AdminGroupAlias);
}
diff --git a/src/Umbraco.Core/Models/Validation/RequiredForPersistenceAttribute.cs b/src/Umbraco.Core/Models/Validation/RequiredForPersistenceAttribute.cs
index d978d86556..c75b0496f3 100644
--- a/src/Umbraco.Core/Models/Validation/RequiredForPersistenceAttribute.cs
+++ b/src/Umbraco.Core/Models/Validation/RequiredForPersistenceAttribute.cs
@@ -1,17 +1,31 @@
using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Reflection;
+using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Models.Validation
{
///
- /// A custom validation attribute which adds additional metadata to the property to indicate that
- /// the value is required to be persisted.
+ /// Specifies that a data field value is required in order to persist an object.
///
///
- /// In Umbraco, we persist content even if it is invalid, however there are some properties that are absolutely required
- /// in order to be persisted such as the Name of the content item. This attribute is re-usable to check for these types of
- /// properties over any sort of model.
+ /// There are two levels of validation in Umbraco. (1) value validation is performed by
+ /// instances; it can prevent a content item from being published, but not from being saved. (2) required validation
+ /// of properties marked with ; it does prevent an object from being saved
+ /// and is used for properties that are absolutely mandatory, such as the name of a content item.
///
public class RequiredForPersistenceAttribute : RequiredAttribute
{
+ ///
+ /// Determines whether an object has all required values for persistence.
+ ///
+ internal static bool HasRequiredValuesForPersistence(object model)
+ {
+ return model.GetType().GetProperties().All(x =>
+ {
+ var a = x.GetCustomAttribute();
+ return a == null || a.IsValid(x.GetValue(model));
+ });
+ }
}
}
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
index bfa32bd06e..ae48d51a52 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
@@ -167,13 +167,7 @@ namespace Umbraco.Core.PropertyEditors
return json?.PropertyName ?? property.Name;
}
- var dictionary = ObjectExtensions.ToObjectDictionary(configuration, FieldNamer);
-
- if (configuration is ConfigurationWithAdditionalData withAdditionalData)
- foreach (var kv in withAdditionalData.GetAdditionalValues())
- dictionary[kv.Key] = kv.Value;
-
- return dictionary;
+ return ObjectExtensions.ToObjectDictionary(configuration, FieldNamer);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationWithAdditionalData.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationWithAdditionalData.cs
deleted file mode 100644
index f9c2afec95..0000000000
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationWithAdditionalData.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Umbraco.Core.PropertyEditors
-{
- ///
- /// Provides a base class for configurations that support additional data.
- ///
- public abstract class ConfigurationWithAdditionalData
- {
- private Dictionary _values;
-
- // note: this class should NOT define ANY property, so that configuration
- // classes that inherit from it, can do what they want with properties
-
- ///
- /// Gets an additional value.
- ///
- /// No value exists for the key.
- public object GetAdditionalValue(string key)
- {
- if (_values != null && _values.TryGetValue(key, out var obj))
- return obj;
- throw new KeyNotFoundException($"No value exists for key \"{key}\".");
- }
-
- ///
- /// Sets an additional value.
- ///
- public void SetAdditionalValue(string key, object value)
- {
- if (value == null)
- {
- if (_values == null) return;
- _values.Remove(key);
- }
- else
- {
- if (_values == null) _values = new Dictionary();
- _values[key] = value;
- }
- }
-
- ///
- /// Removes an additional value.
- ///
- public void RemoveAdditionalValue(string key)
- {
- _values?.Remove(key);
- }
-
- ///
- /// Determines whether the configuration contains a additional value.
- ///
- ///
- ///
- public bool ContainsAdditionalKey(string key)
- => _values != null && _values.ContainsKey(key);
-
- ///
- /// Tries to get an additional value.
- ///
- public bool TryGetAdditionalValue(string key, out object obj)
- {
- obj = null;
- return _values != null && _values.TryGetValue(key, out obj);
- }
-
- ///
- /// Determines whether the configuration has additional values.
- ///
- ///
- public bool HasAdditionalValues()
- => _values != null && _values.Count > 0;
-
- ///
- /// Gets additional values.
- ///
- public IEnumerable> GetAdditionalValues()
- => _values ?? Enumerable.Empty>();
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/DataEditor.cs b/src/Umbraco.Core/PropertyEditors/DataEditor.cs
index 732250da00..5aba2a5e0e 100644
--- a/src/Umbraco.Core/PropertyEditors/DataEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/DataEditor.cs
@@ -20,7 +20,6 @@ namespace Umbraco.Core.PropertyEditors
{
private IDictionary _defaultConfiguration;
private IDataValueEditor _valueEditorAssigned;
- private IConfigurationEditor _configurationEditorAssigned;
///
/// Initializes a new instance of the class.
@@ -82,50 +81,68 @@ namespace Umbraco.Core.PropertyEditors
///
///
- /// If an instance of a value editor is assigned to the property,
- /// then this instance is returned when getting the property value. Otherwise, a
- /// new instance is created by CreateValueEditor.
+ /// If an explicit value editor has been assigned, then this explicit
+ /// instance is returned. Otherwise, a new instance is created by CreateValueEditor.
/// The instance created by CreateValueEditor is not cached, i.e.
/// a new instance is created each time the property value is retrieved. The
/// property editor is a singleton, and the value editor cannot be a singleton
/// since it depends on the datatype configuration.
/// Technically, it could be cached by datatype but let's keep things
/// simple enough for now.
- /// The property is *not* marked with json ObjectCreationHandling = ObjectCreationHandling.Replace,
- /// so by default the deserializer will first try to read it before assigning it, which is why
- /// all deserialization *should* set the property before anything (see manifest deserializer).
///
- [JsonProperty("editor")]
- public IDataValueEditor ValueEditor
- {
- // create a new value editor each time - the property editor can be a
- // singleton, but the value editor will get a configuration which depends
- // on the datatype, so it cannot be a singleton really
- get => CreateValueEditor();
- set => _valueEditorAssigned = value;
- }
+ // fixme point of that one? shouldn't we always configure?
+ public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? CreateValueEditor();
///
///
- /// If an instance of a configuration editor is assigned to the property,
- /// then this instance is returned when getting the property value. Otherwise, a
- /// new instance is created by CreateConfigurationEditor.
- /// The instance created by CreateConfigurationEditor is not cached, i.e.
+ /// If an explicit value editor has been assigned, then this explicit
+ /// instance is returned. Otherwise, a new instance is created by CreateValueEditor,
+ /// and configured with the configuration.
+ /// The instance created by CreateValueEditor is not cached, i.e.
/// a new instance is created each time the property value is retrieved. The
- /// property editor is a singleton, and although the configuration editor could
- /// technically be a singleton too, we'd rather not keep configuration editor
- /// cached.
- /// The property is *not* marked with json ObjectCreationHandling = ObjectCreationHandling.Replace,
- /// so by default the deserializer will first try to read it before assigning it, which is why
- /// all deserialization *should* set the property before anything (see manifest deserializer).
+ /// property editor is a singleton, and the value editor cannot be a singleton
+ /// since it depends on the datatype configuration.
+ /// Technically, it could be cached by datatype but let's keep things
+ /// simple enough for now.
///
- [JsonProperty("config")]
- public IConfigurationEditor ConfigurationEditor
+ public IDataValueEditor GetValueEditor(object configuration)
{
- get => CreateConfigurationEditor();
- set => _configurationEditorAssigned = value;
+ // if an explicit value editor has been set (by the manifest parser)
+ // then return it, and ignore the configuration, which is going to be
+ // empty anyways
+ if (ExplicitValueEditor != null)
+ return ExplicitValueEditor;
+
+ var editor = CreateValueEditor();
+ ((DataValueEditor) editor).Configuration = configuration; // fixme casting is bad
+ return editor;
}
+ ///
+ /// Gets or sets an explicit value editor.
+ ///
+ /// Used for manifest data editors.
+ [JsonProperty("editor")]
+ public IDataValueEditor ExplicitValueEditor { get; set; }
+
+ ///
+ ///
+ /// If an explicit configuration editor has been assigned, then this explicit
+ /// instance is returned. Otherwise, a new instance is created by CreateConfigurationEditor.
+ /// The instance created by CreateConfigurationEditor is not cached, i.e.
+ /// a new instance is created each time. The property editor is a singleton, and although the
+ /// configuration editor could technically be a singleton too, we'd rather not keep configuration editor
+ /// cached.
+ ///
+ public IConfigurationEditor GetConfigurationEditor() => ExplicitConfigurationEditor ?? CreateConfigurationEditor();
+
+ ///
+ /// Gets or sets an explicit configuration editor.
+ ///
+ /// Used for manifest data editors.
+ [JsonProperty("config")]
+ public IConfigurationEditor ExplicitConfigurationEditor { get; set; }
+
///
[JsonProperty("defaultConfig")]
public IDictionary DefaultConfiguration
@@ -133,7 +150,7 @@ namespace Umbraco.Core.PropertyEditors
// for property value editors, get the ConfigurationEditor.DefaultConfiguration
// else fallback to a default, empty dictionary
- get => _defaultConfiguration ?? ((Type & EditorType.PropertyValue) > 0 ? ConfigurationEditor.DefaultConfiguration : (_defaultConfiguration = new Dictionary()));
+ get => _defaultConfiguration ?? ((Type & EditorType.PropertyValue) > 0 ? GetConfigurationEditor().DefaultConfiguration : (_defaultConfiguration = new Dictionary()));
set => _defaultConfiguration = value;
}
@@ -158,37 +175,9 @@ namespace Umbraco.Core.PropertyEditors
///
protected virtual IConfigurationEditor CreateConfigurationEditor()
{
- // handle assigned editor
- if (_configurationEditorAssigned != null)
- return _configurationEditorAssigned;
-
- // else return an empty one
return new ConfigurationEditor();
}
- // fixme why are we implementing equality here?
-
- protected bool Equals(DataEditor other)
- {
- return string.Equals(Alias, other.Alias);
- }
-
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != GetType()) return false;
- return Equals((DataEditor) obj);
- }
-
- public override int GetHashCode()
- {
- // an internal setter is required for de-serialization from manifests
- // but we are never going to change the alias once the editor exists
- // ReSharper disable once NonReadonlyMemberInGetHashCode
- return Alias.GetHashCode();
- }
-
///
/// Provides a summary of the PropertyEditor for use with the .
///
diff --git a/src/Umbraco.Core/PropertyEditors/DataEditorAttribute.cs b/src/Umbraco.Core/PropertyEditors/DataEditorAttribute.cs
index d7b57c7560..9a9a105ca8 100644
--- a/src/Umbraco.Core/PropertyEditors/DataEditorAttribute.cs
+++ b/src/Umbraco.Core/PropertyEditors/DataEditorAttribute.cs
@@ -88,7 +88,7 @@ namespace Umbraco.Core.PropertyEditors
public string Name { get; }
///
- /// Gets the view to use to render the editor. fixme - but that's for the VALUE really?
+ /// Gets the view to use to render the editor.
///
public string View { get; }
diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs
index c0221ebcfe..6ae55d94cb 100644
--- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Globalization;
+using System.Linq;
using System.Xml.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
@@ -116,35 +118,48 @@ namespace Umbraco.Core.PropertyEditors
[JsonProperty("valueType")]
public string ValueType { get; set; }
+ ///
+ public IEnumerable Validate(object value, bool required, string format)
+ {
+ List results = null;
+ var r = Validators.SelectMany(v => v.Validate(value, ValueType, Configuration)).ToList();
+ if (r.Any()) { results = r; }
+
+ // mandatory and regex validators cannot be part of valueEditor.Validators because they
+ // depend on values that are not part of the configuration, .Mandatory and .ValidationRegEx,
+ // so they have to be explicitely invoked here.
+
+ if (required)
+ {
+ r = RequiredValidator.ValidateRequired(value, ValueType).ToList();
+ if (r.Any()) { if (results == null) results = r; else results.AddRange(r); }
+ }
+
+ var stringValue = value?.ToString();
+ if (!string.IsNullOrWhiteSpace(format) && !string.IsNullOrWhiteSpace(stringValue))
+ {
+ r = FormatValidator.ValidateFormat(value, ValueType, format).ToList();
+ if (r.Any()) { if (results == null) results = r; else results.AddRange(r); }
+ }
+
+ return results ?? Enumerable.Empty();
+ }
+
///
/// A collection of validators for the pre value editor
///
[JsonProperty("validation")]
public List Validators { get; private set; }
- // fixme - need to explain and understand these two + what is "overridable pre-values"
+ ///
+ /// Gets the validator used to validate the special property type -level "required".
+ ///
+ public virtual IValueRequiredValidator RequiredValidator => new RequiredValidator();
///
- /// Returns the validator used for the required field validation which is specified on the PropertyType
+ /// Gets the validator used to validate the special property type -level "format".
///
- ///
- /// This will become legacy as soon as we implement overridable pre-values.
- ///
- /// The default validator used is the RequiredValueValidator but this can be overridden by property editors
- /// if they need to do some custom validation, or if the value being validated is a json object.
- ///
- public virtual ManifestValidator RequiredValidator => new RequiredManifestValueValidator();
-
- ///
- /// Returns the validator used for the regular expression field validation which is specified on the PropertyType
- ///
- ///
- /// This will become legacy as soon as we implement overridable pre-values.
- ///
- /// The default validator used is the RegexValueValidator but this can be overridden by property editors
- /// if they need to do some custom validation, or if the value being validated is a json object.
- ///
- public virtual ManifestValidator RegexValidator => new RegexValidator();
+ public virtual IValueFormatValidator FormatValidator => new RegexValidator();
///
/// If this is is true than the editor will be displayed full width without a label
@@ -229,7 +244,7 @@ namespace Umbraco.Core.PropertyEditors
/// If overridden then the object returned must match the type supplied in the ValueType, otherwise persisting the
/// value to the DB will fail when it tries to validate the value type.
///
- public virtual object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
+ public virtual object FromEditor(ContentPropertyData editorValue, object currentValue)
{
//if it's json but it's empty json, then return null
if (ValueType.InvariantEquals(ValueTypes.Json) && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson())
@@ -257,7 +272,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 ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public virtual object ToEditor(Property property, IDataTypeService dataTypeService)
{
if (property.GetValue() == null) return string.Empty;
diff --git a/src/Umbraco.Core/PropertyEditors/IDataEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataEditor.cs
index 48a1428358..8137101826 100644
--- a/src/Umbraco.Core/PropertyEditors/IDataEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/IDataEditor.cs
@@ -44,9 +44,14 @@ namespace Umbraco.Core.PropertyEditors
bool IsDeprecated { get; }
///
- /// Gets the value editor.
+ /// Gets a value editor.
///
- IDataValueEditor ValueEditor { get; } // fixme should be a method - but, deserialization?
+ IDataValueEditor GetValueEditor(); // fixme - should be configured?!
+
+ ///
+ /// Gets a configured value editor.
+ ///
+ IDataValueEditor GetValueEditor(object configuration);
///
/// Gets the configuration for the value editor.
@@ -54,9 +59,11 @@ namespace Umbraco.Core.PropertyEditors
IDictionary DefaultConfiguration { get; }
///
- /// Gets the editor to edit the value editor configuration.
+ /// Gets an editor to edit the value editor configuration.
///
- /// Is expected to throw if the editor does not support being configured, e.g. for most parameter editors.
- IConfigurationEditor ConfigurationEditor { get; } // fixme should be a method - but, deserialization?
+ ///
+ /// Is expected to throw if the editor does not support being configured, e.g. for most parameter editors.
+ ///
+ IConfigurationEditor GetConfigurationEditor();
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs
index 07a684486a..5b419d0ec8 100644
--- a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
@@ -33,19 +34,37 @@ namespace Umbraco.Core.PropertyEditors
///
bool HideLabel { get; }
+ ///
+ /// Validates a property value.
+ ///
+ /// The property value.
+ /// A value indicating whether the property value is required.
+ /// A specific format (regex) that the property value must respect.
+ IEnumerable Validate(object value, bool required, string format);
+
///
/// Gets the validators to use to validate the edited value.
///
+ ///
+ /// Use this property to add validators, not to validate. Use instead.
+ /// fixme replace with AddValidator? WithValidator?
+ ///
List Validators { get; }
- // fixme what are these?
- ManifestValidator RequiredValidator { get; }
- ManifestValidator RegexValidator { get; }
+ ///
+ /// Converts a value posted by the editor to a property value.
+ ///
+ object FromEditor(ContentPropertyData editorValue, object currentValue);
- // fixme services should be injected!
- // fixme document
- object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue);
- object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService);
+ // fixme - editing - services should be injected
+
+ ///
+ /// Converts a property value to a value for the editor.
+ ///
+ object ToEditor(Property property, IDataTypeService dataTypeService);
+
+ // fixme - editing - document or remove these
+ // 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);
diff --git a/src/Umbraco.Core/PropertyEditors/IManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/IManifestValueValidator.cs
new file mode 100644
index 0000000000..559ea08bb7
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/IManifestValueValidator.cs
@@ -0,0 +1,14 @@
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Defines a value validator that can be referenced in a manifest.
+ ///
+ /// If the manifest can be configured, then it should expose a Configuration property.
+ public interface IManifestValueValidator : IValueValidator
+ {
+ ///
+ /// Gets the name of the validator.
+ ///
+ string ValidationName { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs b/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs
new file mode 100644
index 0000000000..3e4aea4385
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Defines a value format validator.
+ ///
+ public interface IValueFormatValidator
+ {
+ ///
+ /// Validates a value.
+ ///
+ /// The value to validate.
+ /// The value type.
+ /// A format definition.
+ /// Validation results.
+ ///
+ /// The is expected to be a valid regular expression.
+ /// This is used to validate values against the property type validation regular expression.
+ ///
+ IEnumerable ValidateFormat(object value, string valueType, string format);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs b/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs
new file mode 100644
index 0000000000..f8e62788c8
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Defines a required value validator.
+ ///
+ public interface IValueRequiredValidator
+ {
+ ///
+ /// Validates a value.
+ ///
+ /// The value to validate.
+ /// The value type.
+ /// Validation results.
+ ///
+ /// This is used to validate values when the property type specifies that a value is required.
+ ///
+ IEnumerable ValidateRequired(object value, string valueType);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/IValueValidator.cs b/src/Umbraco.Core/PropertyEditors/IValueValidator.cs
index 0a82e44dd0..5c9bae71b5 100644
--- a/src/Umbraco.Core/PropertyEditors/IValueValidator.cs
+++ b/src/Umbraco.Core/PropertyEditors/IValueValidator.cs
@@ -12,8 +12,8 @@ namespace Umbraco.Core.PropertyEditors
/// Validates a value.
///
/// The value to validate.
- /// The expected .
- /// The datatype configuration.
+ /// The value type.
+ /// A datatype configuration.
/// Validation results.
///
/// The value can be a string, a Json structure (JObject, JArray...)... corresponding to what was posted by an editor.
diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs b/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs
deleted file mode 100644
index a0d4252fe3..0000000000
--- a/src/Umbraco.Core/PropertyEditors/ManifestValidator.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-
-namespace Umbraco.Core.PropertyEditors
-{
- ///
- /// Represents a value validator that implements a named validation for manifets.
- ///
- public abstract class ManifestValidator
- {
- ///
- /// Gets the validation name of this validator.
- ///
- public abstract string ValidationName { get; }
-
- ///
- /// Validates a value.
- ///
- /// The value to validate.
- /// The expected .
- /// The datatype configuration.
- /// The validator configuration, defined in the manifest.
- /// Validation results.
- ///
- /// The value can be a string, a Json structure (JObject, JArray...)... corresponding to what was posted by an editor.
- ///
- public abstract IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration);
- }
-}
diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValidatorCollection.cs b/src/Umbraco.Core/PropertyEditors/ManifestValidatorCollection.cs
deleted file mode 100644
index 84fd35d1d0..0000000000
--- a/src/Umbraco.Core/PropertyEditors/ManifestValidatorCollection.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Umbraco.Core.Composing;
-
-namespace Umbraco.Core.PropertyEditors
-{
- public class ManifestValidatorCollection : BuilderCollectionBase
- {
- public ManifestValidatorCollection(IEnumerable items)
- : base(items)
- { }
-
- public ManifestValidator this[string name] => this.FirstOrDefault(x => x.ValidationName.InvariantEquals(name));
- }
-}
diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValidatorCollectionBuilder.cs b/src/Umbraco.Core/PropertyEditors/ManifestValidatorCollectionBuilder.cs
deleted file mode 100644
index 87c3844971..0000000000
--- a/src/Umbraco.Core/PropertyEditors/ManifestValidatorCollectionBuilder.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using LightInject;
-using Umbraco.Core.Composing;
-
-namespace Umbraco.Core.PropertyEditors
-{
- internal class ManifestValidatorCollectionBuilder : LazyCollectionBuilderBase
- {
- public ManifestValidatorCollectionBuilder(IServiceContainer container)
- : base(container)
- { }
-
- protected override ManifestValidatorCollectionBuilder This => this;
- }
-}
diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/ManifestValueValidator.cs
deleted file mode 100644
index 708cd3191f..0000000000
--- a/src/Umbraco.Core/PropertyEditors/ManifestValueValidator.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using Newtonsoft.Json;
-
-namespace Umbraco.Core.PropertyEditors
-{
- ///
- /// Represents a validator referenced in a package manifest.
- ///
- internal class ManifestValueValidator : IValueValidator
- {
- private readonly ManifestValidatorCollection _validators;
- private ManifestValidator _validator;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ManifestValueValidator(ManifestValidatorCollection validators)
- {
- _validators = validators;
- }
-
- ///
- /// Gets or sets the name of the validation.
- ///
- [JsonProperty("type", Required = Required.Always)]
- public string ValidationName { get; set; }
-
- ///
- /// The configuration defined for this validator in the manifest.
- ///
- ///
- /// This has nothing to do with datatype configuration.
- /// The value is deserialized Json, can be a string or a Json thing (JObject...).
- ///
- [JsonProperty("config")]
- public object Config { get; set; }
-
- ///
- public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
- {
- if (_validator == null)
- {
- _validator = _validators[ValidationName];
- if (_validator == null)
- throw new InvalidOperationException($"No manifest validator exists for validation name \"{ValidationName}\".");
- }
-
- // validates the value, using the manifest validator
- return _validator.Validate(value, valueType, Config, dataTypeConfiguration);
- }
- }
-}
diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValueValidatorCollection.cs b/src/Umbraco.Core/PropertyEditors/ManifestValueValidatorCollection.cs
new file mode 100644
index 0000000000..d16ed4bd62
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/ManifestValueValidatorCollection.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ public class ManifestValueValidatorCollection : BuilderCollectionBase
+ {
+ public ManifestValueValidatorCollection(IEnumerable items)
+ : base(items)
+ { }
+
+ public IManifestValueValidator Create(string name)
+ {
+ var v = this.FirstOrDefault(x => x.ValidationName.InvariantEquals(name));
+ if (v == null)
+ throw new InvalidOperationException($"Could not find a validator named \"{name}\".");
+
+ // FIXME
+ // we cannot return this instance, need to clone it?
+ return (IManifestValueValidator) Activator.CreateInstance(v.GetType()); // ouch
+ }
+ }
+}
diff --git a/src/Umbraco.Core/PropertyEditors/ManifestValueValidatorCollectionBuilder.cs b/src/Umbraco.Core/PropertyEditors/ManifestValueValidatorCollectionBuilder.cs
new file mode 100644
index 0000000000..d616ecf715
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/ManifestValueValidatorCollectionBuilder.cs
@@ -0,0 +1,14 @@
+using LightInject;
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ internal class ManifestValueValidatorCollectionBuilder : LazyCollectionBuilderBase
+ {
+ public ManifestValueValidatorCollectionBuilder(IServiceContainer container)
+ : base(container)
+ { }
+
+ protected override ManifestValueValidatorCollectionBuilder This => this;
+ }
+}
diff --git a/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs
deleted file mode 100644
index a89a4ec97f..0000000000
--- a/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
-using Umbraco.Core.Models;
-
-namespace Umbraco.Core.PropertyEditors
-{
- ///
- /// A validator that validates that the value is not null or empty (if it is a string)
- ///
- internal sealed class RequiredManifestValueValidator : ManifestValidator
- {
- ///
- public override string ValidationName => "Required";
-
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
- {
- //TODO: localize these!
-
- if (value == null)
- {
- yield return new ValidationResult("Value cannot be null", new[] {"value"});
- }
- else
- {
- var asString = value.ToString();
-
- if (valueType.InvariantEquals(ValueTypes.Json))
- {
- if (asString.DetectIsEmptyJson())
- {
- yield return new ValidationResult("Value cannot be empty", new[] { "value" });
- }
- }
-
- if (asString.IsNullOrWhiteSpace())
- {
- yield return new ValidationResult("Value cannot be empty", new[] { "value" });
- }
- }
-
-
- }
- }
-}
diff --git a/src/Umbraco.Core/PropertyEditors/Validators/DecimalValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/DecimalValidator.cs
index ba9b37abb9..86db995566 100644
--- a/src/Umbraco.Core/PropertyEditors/Validators/DecimalValidator.cs
+++ b/src/Umbraco.Core/PropertyEditors/Validators/DecimalValidator.cs
@@ -6,16 +6,10 @@ namespace Umbraco.Core.PropertyEditors.Validators
///
/// A validator that validates that the value is a valid decimal
///
- internal sealed class DecimalValidator : ManifestValidator, IValueValidator
+ internal sealed class DecimalValidator : IManifestValueValidator
{
///
- public override string ValidationName => "Decimal";
-
- ///
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
- {
- return Validate(value, valueType, dataTypeConfiguration);
- }
+ public string ValidationName => "Decimal";
///
public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
diff --git a/src/Umbraco.Core/PropertyEditors/Validators/DelimitedManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/DelimitedValueValidator.cs
similarity index 80%
rename from src/Umbraco.Core/PropertyEditors/Validators/DelimitedManifestValueValidator.cs
rename to src/Umbraco.Core/PropertyEditors/Validators/DelimitedValueValidator.cs
index 4b7405fc53..3891d7952b 100644
--- a/src/Umbraco.Core/PropertyEditors/Validators/DelimitedManifestValueValidator.cs
+++ b/src/Umbraco.Core/PropertyEditors/Validators/DelimitedValueValidator.cs
@@ -10,20 +10,25 @@ namespace Umbraco.Core.PropertyEditors.Validators
///
/// A validator that validates a delimited set of values against a common regex
///
- internal sealed class DelimitedManifestValueValidator : ManifestValidator
+ internal sealed class DelimitedValueValidator : IManifestValueValidator
{
///
- public override string ValidationName => "Delimited";
+ public string ValidationName => "Delimited";
+
+ ///
+ /// Gets or sets the configuration, when parsed as .
+ ///
+ public JObject Configuration { get; set; }
///
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
+ public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
{
//TODO: localize these!
if (value != null)
{
var delimiter = ",";
Regex regex = null;
- if (validatorConfiguration is JObject jobject)
+ if (Configuration is JObject jobject)
{
if (jobject["delimiter"] != null)
{
@@ -56,7 +61,6 @@ namespace Umbraco.Core.PropertyEditors.Validators
}
}
}
-
}
}
}
diff --git a/src/Umbraco.Core/PropertyEditors/Validators/EmailValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/EmailValidator.cs
index d97eacbbb7..762b6dd7dd 100644
--- a/src/Umbraco.Core/PropertyEditors/Validators/EmailValidator.cs
+++ b/src/Umbraco.Core/PropertyEditors/Validators/EmailValidator.cs
@@ -6,16 +6,10 @@ namespace Umbraco.Core.PropertyEditors.Validators
///
/// A validator that validates an email address
///
- internal sealed class EmailValidator : ManifestValidator, IValueValidator
+ internal sealed class EmailValidator : IManifestValueValidator
{
///
- public override string ValidationName => "Email";
-
- ///
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
- {
- return Validate(value, valueType, dataTypeConfiguration);
- }
+ public string ValidationName => "Email";
///
public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
diff --git a/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs
index 2db3fa68c2..335ddf7724 100644
--- a/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs
+++ b/src/Umbraco.Core/PropertyEditors/Validators/IntegerValidator.cs
@@ -6,16 +6,12 @@ namespace Umbraco.Core.PropertyEditors.Validators
///
/// A validator that validates that the value is a valid integer
///
- internal sealed class IntegerValidator : ManifestValidator, IValueValidator
+ internal sealed class IntegerValidator : IManifestValueValidator
{
///
- public override string ValidationName => "Integer";
-
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
- {
- return Validate(value, valueType, dataTypeConfiguration);
- }
+ public string ValidationName => "Integer";
+ ///
public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
{
if (value != null && value.ToString() != string.Empty)
diff --git a/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs
index ead56641a7..0727c0d24f 100644
--- a/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs
+++ b/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs
@@ -2,59 +2,71 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
+using Umbraco.Core.Exceptions;
namespace Umbraco.Core.PropertyEditors.Validators
{
///
- /// A validator that validates that the value against a Regex expression
+ /// A validator that validates that the value against a regular expression.
///
- internal sealed class RegexValidator : ManifestValidator, IValueValidator
+ internal sealed class RegexValidator : IValueFormatValidator, IManifestValueValidator
{
- private readonly string _regex;
+ private string _regex;
- ///
- public override string ValidationName => "Regex";
+ ///
+ public string ValidationName => "Regex";
///
- /// Normally used when configured as a ManifestValueValidator
+ /// Initializes a new instance of the class.
///
+ /// Use this constructor when the validator is used as an ,
+ /// and the regular expression is supplied at validation time. This constructor is also used when
+ /// the validator is used as an and the regular expression
+ /// is supplied via the method.
public RegexValidator()
{ }
///
- /// Normally used when configured as an IPropertyValidator
+ /// Initializes a new instance of the class.
///
- ///
+ /// Use this constructor when the validator is used as an ,
+ /// and the regular expression must be supplied when the validator is created.
public RegexValidator(string regex)
{
- _regex = regex ?? throw new ArgumentNullException(nameof(regex));
+ if (string.IsNullOrWhiteSpace(regex))
+ throw new ArgumentNullOrEmptyException(nameof(regex));
+ _regex = regex;
}
- ///
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
+ ///
+ /// Gets or sets the configuration, when parsed as .
+ ///
+ public string Configuration
{
- //TODO: localize these!
- if (validatorConfiguration is string regexSource && !string.IsNullOrWhiteSpace(regexSource) && value != null)
+ get => _regex;
+ set
{
- var asString = value.ToString();
-
- var regex = new Regex(regexSource);
-
- if (regex.IsMatch(asString) == false)
- {
- yield return new ValidationResult("Value is invalid, it does not match the correct pattern", new[] { "value" });
- }
+ if (string.IsNullOrWhiteSpace(value))
+ throw new ArgumentNullOrEmptyException(nameof(value));
+ _regex = value;
}
}
- ///
+ ///
public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
{
if (_regex == null)
- {
- throw new InvalidOperationException("This validator is not configured as a " + typeof(IValueValidator));
- }
- return Validate(value, valueType, dataTypeConfiguration, _regex);
+ throw new InvalidOperationException("The validator has not been configured.");
+
+ return ValidateFormat(value, valueType, _regex);
+ }
+
+ ///
+ public IEnumerable ValidateFormat(object value, string valueType, string format)
+ {
+ if (string.IsNullOrWhiteSpace(format)) throw new ArgumentNullOrEmptyException(nameof(format));
+ if (value == null || !new Regex(format).IsMatch(value.ToString()))
+ yield return new ValidationResult("Value is invalid, it does not match the correct pattern", new[] { "value" });
}
}
}
diff --git a/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs
new file mode 100644
index 0000000000..bc3cf66caa
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Umbraco.Core.PropertyEditors.Validators
+{
+ ///
+ /// A validator that validates that the value is not null or empty (if it is a string)
+ ///
+ internal sealed class RequiredValidator : IValueRequiredValidator, IManifestValueValidator
+ {
+ ///
+ public string ValidationName => "Required";
+
+ ///
+ public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration)
+ {
+ return ValidateRequired(value, valueType);
+ }
+
+ ///
+ public IEnumerable ValidateRequired(object value, string valueType)
+ {
+ if (value == null)
+ {
+ yield return new ValidationResult("Value cannot be null", new[] {"value"});
+ yield break;
+ }
+
+ if (valueType.InvariantEquals(ValueTypes.Json))
+ {
+ if (value.ToString().DetectIsEmptyJson())
+ yield return new ValidationResult("Value cannot be empty", new[] { "value" });
+ yield break;
+ }
+
+ if (value.ToString().IsNullOrWhiteSpace())
+ {
+ yield return new ValidationResult("Value cannot be empty", new[] { "value" });
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs
index d9a56df9e2..243dccaf0f 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs
@@ -34,7 +34,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
public override bool IsConverter(PublishedPropertyType propertyType)
{
return _propertyEditors.TryGet(propertyType.EditorAlias, out var editor)
- && editor.ValueEditor.ValueType.InvariantEquals(ValueTypes.Json);
+ && editor.GetValueEditor().ValueType.InvariantEquals(ValueTypes.Json);
}
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs
index 6ef0cef08a..6a5a3f4dc0 100644
--- a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs
+++ b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs
@@ -59,10 +59,10 @@ namespace Umbraco.Core.Runtime
composition.Container.RegisterSingleton();
// register our predefined validators
- composition.Container.RegisterCollectionBuilder()
- .Add()
+ composition.Container.RegisterCollectionBuilder()
+ .Add()
.Add()
- .Add()
+ .Add()
.Add()
.Add()
.Add();
diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs
index 681b91f772..fa299ed54d 100644
--- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs
+++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs
@@ -447,7 +447,7 @@ namespace Umbraco.Core.Services
var propertyEditor = Current.PropertyEditors[propertyType.PropertyEditorAlias];
return propertyEditor == null
? Array.Empty()
- : propertyEditor.ValueEditor.ConvertDbToXml(property, dataTypeService, localizationService, published);
+ : propertyEditor.GetValueEditor().ConvertDbToXml(property, dataTypeService, localizationService, published);
}
// exports an IContent item descendants.
diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs
index 67c6249357..ea698fc8c9 100644
--- a/src/Umbraco.Core/Services/Implement/PackagingService.cs
+++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs
@@ -918,7 +918,7 @@ namespace Umbraco.Core.Services.Implement
var configurationAttributeValue = dataTypeElement.Attribute("Configuration")?.Value;
if (!string.IsNullOrWhiteSpace(configurationAttributeValue))
- dataType.Configuration = editor.ConfigurationEditor.FromDatabase(configurationAttributeValue);
+ dataType.Configuration = editor.GetConfigurationEditor().FromDatabase(configurationAttributeValue);
dataTypes.Add(dataType);
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 154c0a273a..94db77d6fe 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -333,7 +333,6 @@
-
@@ -341,6 +340,9 @@
+
+
+
@@ -515,7 +517,7 @@
-
+
@@ -1186,15 +1188,13 @@
-
+
-
-
@@ -1207,10 +1207,10 @@
-
+
-
-
+
+
diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
index 65c7427e38..607d34c56d 100644
--- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
+++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
@@ -9,6 +9,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.PropertyEditors.Validators;
namespace Umbraco.Tests.Manifest
{
@@ -21,7 +22,12 @@ namespace Umbraco.Tests.Manifest
[SetUp]
public void Setup()
{
- _parser = new ManifestParser(NullCacheProvider.Instance, new ManifestValidatorCollection(Enumerable.Empty()), Mock.Of());
+ var validators = new IManifestValueValidator[]
+ {
+ new RequiredValidator(),
+ new RegexValidator()
+ };
+ _parser = new ManifestParser(NullCacheProvider.Instance, new ManifestValueValidatorCollection(validators), Mock.Of());
}
[Test]
@@ -170,7 +176,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
Assert.AreEqual("Test 1", editor.Name);
Assert.IsFalse((editor.Type & EditorType.MacroParameter) > 0);
- var valueEditor = editor.ValueEditor;
+ var valueEditor = editor.GetValueEditor();
Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html", valueEditor.View);
Assert.AreEqual("int", valueEditor.ValueType);
Assert.IsTrue(valueEditor.HideLabel);
@@ -182,21 +188,20 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
var validators = valueEditor.Validators;
Assert.AreEqual(2, validators.Count);
var validator = validators[0];
- var v = validator as ManifestValueValidator;
- Assert.IsNotNull(v);
- Assert.AreEqual("required", v.ValidationName);
- Assert.AreEqual("", v.Config);
+ var v1 = validator as RequiredValidator;
+ Assert.IsNotNull(v1);
+ Assert.AreEqual("Required", v1.ValidationName);
validator = validators[1];
- v = validator as ManifestValueValidator;
- Assert.IsNotNull(v);
- Assert.AreEqual("Regex", v.ValidationName);
- Assert.AreEqual("\\d*", v.Config);
+ var v2 = validator as RegexValidator;
+ Assert.IsNotNull(v2);
+ Assert.AreEqual("Regex", v2.ValidationName);
+ Assert.AreEqual("\\d*", v2.Configuration);
// this is not part of the manifest
- var preValues = editor.ConfigurationEditor.DefaultConfiguration;
+ var preValues = editor.GetConfigurationEditor().DefaultConfiguration;
Assert.IsEmpty(preValues);
- var preValueEditor = editor.ConfigurationEditor;
+ var preValueEditor = editor.GetConfigurationEditor();
Assert.IsNotNull(preValueEditor);
Assert.IsNotNull(preValueEditor.Fields);
Assert.AreEqual(2, preValueEditor.Fields.Count);
@@ -208,10 +213,9 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
var fvalidators = f.Validators;
Assert.IsNotNull(fvalidators);
Assert.AreEqual(1, fvalidators.Count);
- var fv = fvalidators[0] as ManifestValueValidator;
+ var fv = fvalidators[0] as RequiredValidator;
Assert.IsNotNull(fv);
- Assert.AreEqual("required", fv.ValidationName);
- Assert.AreEqual("", fv.Config);
+ Assert.AreEqual("Required", fv.ValidationName);
f = preValueEditor.Fields[1];
Assert.AreEqual("key2", f.Key);
@@ -257,13 +261,13 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
Assert.IsTrue(config.ContainsKey("key1"));
Assert.AreEqual("some config val", config["key1"]);
- var valueEditor = editor.ValueEditor;
+ var valueEditor = editor.GetValueEditor();
Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html", valueEditor.View);
editor = manifest.ParameterEditors[2];
Assert.Throws(() =>
{
- var _ = editor.ValueEditor;
+ var _ = editor.GetValueEditor();
});
}
diff --git a/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs b/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs
index 599cf1af10..23a9eafe76 100644
--- a/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs
+++ b/src/Umbraco.Tests/Models/Mapping/AutoMapperTests.cs
@@ -23,7 +23,7 @@ namespace Umbraco.Tests.Models.Mapping
var manifestBuilder = new ManifestParser(
CacheHelper.CreateDisabledCacheHelper().RuntimeCache,
- new ManifestValidatorCollection(Enumerable.Empty()),
+ new ManifestValueValidatorCollection(Enumerable.Empty()),
Logger)
{
Path = TestHelper.CurrentAssemblyDirectory
diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs
index b797b0c4be..890d917ad3 100644
--- a/src/Umbraco.Tests/Models/VariationTests.cs
+++ b/src/Umbraco.Tests/Models/VariationTests.cs
@@ -1,13 +1,18 @@
using System;
+using LightInject;
+using Moq;
using NUnit.Framework;
+using Umbraco.Core.Cache;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
using Umbraco.Core.Models;
+using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.PropertyEditors.Validators;
+using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Models
{
- // fixme - need to reorg our tests!
- // fixme - test IsDirty on properties
-
[TestFixture]
public class VariationTests
{
@@ -16,6 +21,42 @@ namespace Umbraco.Tests.Models
{
// annoying, but content type wants short string helper ;(
SettingsForTests.Reset();
+
+ // well, this is also annoying, but...
+ // validating a value is performed by its data editor,
+ // based upon the configuration in the data type, so we
+ // need to be able to retrieve them all...
+
+ Current.Reset();
+ var container = Mock.Of();
+ Current.Container = container;
+
+ var dataEditors = new DataEditorCollection(new IDataEditor[]
+ {
+ new DataEditor(Mock.Of()) { Alias = "editor", ExplicitValueEditor = new DataValueEditor("view") }
+ });
+ var propertyEditors = new PropertyEditorCollection(dataEditors);
+
+ var dataType = Mock.Of();
+ Mock.Get(dataType)
+ .Setup(x => x.Configuration)
+ .Returns(null);
+
+ var dataTypeService = Mock.Of();
+ Mock.Get(dataTypeService)
+ .Setup(x => x.GetDataType(It.IsAny()))
+ .Returns(x => dataType);
+
+ var serviceContext = new ServiceContext(dataTypeService: dataTypeService);
+
+ Mock.Get(container)
+ .Setup(x => x.GetInstance(It.IsAny()))
+ .Returns(x =>
+ {
+ if (x == typeof(PropertyEditorCollection)) return propertyEditors;
+ if (x == typeof(ServiceContext)) return serviceContext;
+ throw new Exception("oops");
+ });
}
[Test]
diff --git a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs
index fb39ffb87b..80c0868dfa 100644
--- a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs
+++ b/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs
@@ -63,7 +63,9 @@ namespace Umbraco.Tests.PropertyEditors
var prop = new Property(1, new PropertyType(dataType));
prop.SetValue("1234,4567,8910");
- var result = dataType.Editor.ValueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
+ var valueEditor = dataType.Editor.GetValueEditor();
+ ((DataValueEditor) valueEditor).Configuration = dataType.Configuration;
+ var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
Assert.AreEqual("Value 1,Value 2,Value 3", result);
}
@@ -90,7 +92,7 @@ namespace Umbraco.Tests.PropertyEditors
var prop = new Property(1, new PropertyType(dataType));
prop.SetValue("1234");
- var result = dataType.Editor.ValueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
+ var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
Assert.AreEqual("Value 2", result);
}
diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs
index 98ea6253f3..ff2ee0aebd 100644
--- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs
+++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs
@@ -48,7 +48,7 @@ namespace Umbraco.Tests.PropertyEditors
ValueType = ValueTypes.String
};
- var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object);
+ var result = valueEditor.ToEditor(prop, new Mock().Object);
Assert.AreEqual(isOk, !(result is string));
}
@@ -138,7 +138,7 @@ namespace Umbraco.Tests.PropertyEditors
ValueType = valueType
};
- var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object);
+ var result = valueEditor.ToEditor(prop, new Mock().Object);
Assert.AreEqual(expected, result);
}
@@ -154,7 +154,7 @@ namespace Umbraco.Tests.PropertyEditors
var prop = new Property(1, new PropertyType("test", ValueStorageType.Decimal));
prop.SetValue(value);
- var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object);
+ var result = valueEditor.ToEditor(prop, new Mock().Object);
Assert.AreEqual("12.34", result);
}
@@ -169,7 +169,7 @@ namespace Umbraco.Tests.PropertyEditors
var prop = new Property(1, new PropertyType("test", ValueStorageType.Decimal));
prop.SetValue(string.Empty);
- var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object);
+ var result = valueEditor.ToEditor(prop, new Mock().Object);
Assert.AreEqual(string.Empty, result);
}
@@ -185,7 +185,7 @@ namespace Umbraco.Tests.PropertyEditors
var prop = new Property(1, new PropertyType("test", ValueStorageType.Date));
prop.SetValue(now);
- var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object);
+ var result = valueEditor.ToEditor(prop, new Mock().Object);
Assert.AreEqual(now.ToIsoString(), result);
}
}
diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs
index 3694e13877..5dd11b2812 100644
--- a/src/Umbraco.Tests/Services/ContentServiceTests.cs
+++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs
@@ -1848,7 +1848,7 @@ namespace Umbraco.Tests.Services
editorGroup.StartContentId = content1.Id;
ServiceContext.UserService.Save(editorGroup);
- var admin = ServiceContext.UserService.GetUserById(0);
+ var admin = ServiceContext.UserService.GetUserById(Constants.Security.SuperId);
admin.StartContentIds = new[] {content1.Id};
ServiceContext.UserService.Save(admin);
@@ -1865,7 +1865,7 @@ namespace Umbraco.Tests.Services
}));
Assert.IsTrue(ServiceContext.PublicAccessService.AddRule(content1, "test2", "test2").Success);
- var user = ServiceContext.UserService.GetUserById(0);
+ var user = ServiceContext.UserService.GetUserById(Constants.Security.SuperId);
var userGroup = ServiceContext.UserService.GetUserGroupByAlias(user.Groups.First().Alias);
Assert.IsNotNull(ServiceContext.NotificationService.CreateNotification(user, content1, "X"));
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index 5a6f253151..7dd8061bf7 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -302,7 +302,7 @@ namespace Umbraco.Tests.Testing
Container.RegisterSingleton();
// somehow property editor ends up wanting this
- Container.RegisterCollectionBuilder();
+ Container.RegisterCollectionBuilder();
Container.RegisterSingleton();
// note - don't register collections, use builders
diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
index 17f7610a33..51996955b1 100644
--- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
@@ -10,7 +10,9 @@ using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
+using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Querying;
+using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.ControllerTesting;
@@ -96,6 +98,28 @@ namespace Umbraco.Tests.Web.Controllers
}
}
+ private void MockForGetPagedUsers()
+ {
+ Mock.Get(Current.SqlContext)
+ .Setup(x => x.Query())
+ .Returns(new Query(Current.SqlContext));
+
+ var syntax = new SqlCeSyntaxProvider();
+
+ Mock.Get(Current.SqlContext)
+ .Setup(x => x.SqlSyntax)
+ .Returns(syntax);
+
+ var mappers = new MapperCollection(new []
+ {
+ new UserMapper()
+ });
+
+ Mock.Get(Current.SqlContext)
+ .Setup(x => x.Mappers)
+ .Returns(mappers);
+ }
+
[Test]
public async System.Threading.Tasks.Task GetPagedUsers_Empty()
{
@@ -110,6 +134,8 @@ namespace Umbraco.Tests.Web.Controllers
return usersController;
}
+ MockForGetPagedUsers();
+
var runner = new TestRunner(Factory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
@@ -140,6 +166,8 @@ namespace Umbraco.Tests.Web.Controllers
return usersController;
}
+ MockForGetPagedUsers();
+
var runner = new TestRunner(Factory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs
index 16e2d3e36b..b819046a9a 100644
--- a/src/Umbraco.Web/Composing/Current.cs
+++ b/src/Umbraco.Web/Composing/Current.cs
@@ -226,7 +226,7 @@ namespace Umbraco.Web.Composing
public static ParameterEditorCollection ParameterEditors => CoreCurrent.ParameterEditors;
- internal static ManifestValidatorCollection ManifestValidators => CoreCurrent.ManifestValidators;
+ internal static ManifestValueValidatorCollection ManifestValidators => CoreCurrent.ManifestValidators;
internal static PackageActionCollection PackageActions => CoreCurrent.PackageActions;
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index c7569aa4eb..f8bf6b083c 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -24,6 +24,8 @@ using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Web.PublishedCache;
using Umbraco.Core.Events;
+using Umbraco.Core.Models.Validation;
+using Umbraco.Web._Legacy.Actions;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Editors
@@ -546,7 +548,7 @@ namespace Umbraco.Web.Editors
// a message indicating this
if (ModelState.IsValid == false)
{
- if (ValidationHelper.ModelHasRequiredForPersistenceErrors(contentItem) && IsCreatingAction(contentItem.Action))
+ if (!RequiredForPersistenceAttribute.HasRequiredValuesForPersistence(contentItem) && IsCreatingAction(contentItem.Action))
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
// add the modelstate to the outgoing object and throw a validation message
diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs
index e4194b4b6c..a020de1468 100644
--- a/src/Umbraco.Web/Editors/ContentControllerBase.cs
+++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs
@@ -82,7 +82,7 @@ namespace Umbraco.Web.Editors
// get the value editor
// nothing to save/map if it is readonly
- var valueEditor = propertyDto.PropertyEditor.ValueEditor;
+ var valueEditor = propertyDto.PropertyEditor.GetValueEditor();
if (valueEditor.IsReadOnly) continue;
// get the property
@@ -102,7 +102,7 @@ namespace Umbraco.Web.Editors
};
// let the editor convert the value that was received, deal with files, etc
- var value = valueEditor.ConvertEditorToDb(data, property.GetValue());
+ var value = valueEditor.FromEditor(data, property.GetValue());
// set the value - tags are special
var tagAttribute = propertyDto.PropertyEditor.GetTagAttribute();
diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs
index e7a72fb462..10a05069e9 100644
--- a/src/Umbraco.Web/Editors/ContentTypeController.cs
+++ b/src/Umbraco.Web/Editors/ContentTypeController.cs
@@ -131,8 +131,8 @@ namespace Umbraco.Web.Editors
{
Editor = dataTypeDiff.EditorAlias,
Validation = new PropertyTypeValidation(),
- View = editor.ValueEditor.View,
- Config = editor.ConfigurationEditor.ToConfigurationEditor(configuration)
+ View = editor.GetValueEditor().View,
+ Config = editor.GetConfigurationEditor().ToConfigurationEditor(configuration)
};
}
diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
index 227db6db31..030d59de8f 100644
--- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
+++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
@@ -152,8 +152,8 @@ namespace Umbraco.Web.Editors
ModelState.AddModelError("Alias", "A content type, media type or member type with this alias already exists");
}
- //now let the external validators execute
- ValidationHelper.ValidateEditorModelWithResolver(ModelState, contentTypeSave);
+ // execute the externam validators
+ EditorValidator.Validate(ModelState, contentTypeSave);
if (ModelState.IsValid == false)
{
diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs
index ad33113720..1007107b57 100644
--- a/src/Umbraco.Web/Editors/DataTypeController.cs
+++ b/src/Umbraco.Web/Editors/DataTypeController.cs
@@ -211,7 +211,7 @@ namespace Umbraco.Web.Editors
// and map to an actual configuration object
var currentConfiguration = dataType.PersistedDataType.Configuration;
var configurationDictionary = dataType.ConfigurationFields.ToDictionary(x => x.Key, x => x.Value);
- var configuration = dataType.PropertyEditor.ConfigurationEditor.FromConfigurationEditor(configurationDictionary, currentConfiguration);
+ var configuration = dataType.PropertyEditor.GetConfigurationEditor().FromConfigurationEditor(configurationDictionary, currentConfiguration);
dataType.PersistedDataType.Configuration = configuration;
@@ -320,7 +320,7 @@ namespace Umbraco.Web.Editors
{
var propertyEditor = propertyEditors.SingleOrDefault(x => x.Alias == dataType.Alias);
if (propertyEditor != null)
- dataType.HasPrevalues = propertyEditor.ConfigurationEditor.Fields.Any(); ;
+ dataType.HasPrevalues = propertyEditor.GetConfigurationEditor().Fields.Any(); ;
}
var grouped = dataTypes
@@ -347,7 +347,7 @@ namespace Umbraco.Web.Editors
var propertyEditors = Current.PropertyEditors;
foreach (var propertyEditor in propertyEditors)
{
- var hasPrevalues = propertyEditor.ConfigurationEditor.Fields.Any();
+ var hasPrevalues = propertyEditor.GetConfigurationEditor().Fields.Any();
var basic = Mapper.Map(propertyEditor);
basic.HasPrevalues = hasPrevalues;
datatypes.Add(basic);
diff --git a/src/Umbraco.Web/Editors/DataTypeValidateAttribute.cs b/src/Umbraco.Web/Editors/DataTypeValidateAttribute.cs
index 98342b9a6d..f8f2b5ac23 100644
--- a/src/Umbraco.Web/Editors/DataTypeValidateAttribute.cs
+++ b/src/Umbraco.Web/Editors/DataTypeValidateAttribute.cs
@@ -5,8 +5,11 @@ using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using AutoMapper;
+using LightInject;
using Umbraco.Core;
using Umbraco.Core.Models;
+using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.WebApi;
@@ -18,20 +21,23 @@ namespace Umbraco.Web.Editors
///
internal sealed class DataTypeValidateAttribute : ActionFilterAttribute
{
+ // LightInject can inject dependencies into properties
+
+ [Inject]
+ public IDataTypeService DataTypeService { get; set; }
+
+ [Inject]
+ public PropertyEditorCollection PropertyEditors { get; set; }
+
public override void OnActionExecuting(HttpActionContext actionContext)
{
- // injecting in attributes is not easy.
- // eventually, actionContext should give access to the service factory
- // but for the time being, have to rely on the global locator
- var dataTypeService = Current.Services.DataTypeService;
-
var dataType = (DataTypeSave) actionContext.ActionArguments["dataType"];
dataType.Name = dataType.Name.CleanForXss('[', ']', '(', ')', ':');
dataType.Alias = dataType.Alias == null ? dataType.Name : dataType.Alias.CleanForXss('[', ']', '(', ')', ':');
// get the property editor, ensuring that it exits
- if (!Current.PropertyEditors.TryGet(dataType.EditorAlias, out var propertyEditor))
+ if (!PropertyEditors.TryGet(dataType.EditorAlias, out var propertyEditor))
{
var message = $"Property editor \"{dataType.EditorAlias}\" was not found.";
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
@@ -46,7 +52,7 @@ namespace Umbraco.Web.Editors
switch (dataType.Action)
{
case ContentSaveAction.Save:
- persisted = dataTypeService.GetDataType(Convert.ToInt32(dataType.Id));
+ persisted = DataTypeService.GetDataType(Convert.ToInt32(dataType.Id));
if (persisted == null)
{
var message = $"Data type with id {dataType.Id} was not found.";
@@ -73,14 +79,15 @@ namespace Umbraco.Web.Editors
// validate the configuration
// which is posted as a set of fields with key (string) and value (object)
+ var configurationEditor = propertyEditor.GetConfigurationEditor();
foreach (var field in dataType.ConfigurationFields)
{
- var value = field.Value;
- var editorField = propertyEditor.ConfigurationEditor.Fields.SingleOrDefault(x => x.Key == field.Key);
+ var editorField = configurationEditor.Fields.SingleOrDefault(x => x.Key == field.Key);
if (editorField == null) continue;
+ // run each IValueValidator (with null valueType and dataTypeConfiguration: not relevant here) - fixme - editing
foreach (var validator in editorField.Validators)
- foreach (var result in validator.Validate(value, null, null))
+ foreach (var result in validator.Validate(field.Value, null, null))
actionContext.ModelState.AddValidationError(result, "Properties", field.Key);
}
diff --git a/src/Umbraco.Web/Editors/EditorValidator.cs b/src/Umbraco.Web/Editors/EditorValidator.cs
index d2b86116b8..2010fae943 100644
--- a/src/Umbraco.Web/Editors/EditorValidator.cs
+++ b/src/Umbraco.Web/Editors/EditorValidator.cs
@@ -1,21 +1,29 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Web.Http.ModelBinding;
+using Umbraco.Web.Composing;
namespace Umbraco.Web.Editors
{
- internal abstract class EditorValidator : IEditorValidator
+ ///
+ /// Provides a method to validate an object using validation.
+ ///
+ internal static class EditorValidator
{
- public Type ModelType
+ ///
+ /// Validates an object.
+ ///
+ public static void Validate(ModelStateDictionary modelState, object model)
{
- get { return typeof (T); }
- }
+ var modelType = model.GetType();
- protected abstract IEnumerable PerformValidate(T model);
+ var validationResults = Current.EditorValidators // fixme inject
+ .Where(x => x.ModelType == modelType)
+ .SelectMany(x => x.Validate(model))
+ .Where(x => !string.IsNullOrWhiteSpace(x.ErrorMessage) && x.MemberNames.Any());
- public IEnumerable Validate(object model)
- {
- return PerformValidate((T) model);
+ foreach (var r in validationResults)
+ foreach (var m in r.MemberNames)
+ modelState.AddModelError(m, r.ErrorMessage);
}
}
}
diff --git a/src/Umbraco.Web/Editors/EditorValidatorCollection.cs b/src/Umbraco.Web/Editors/EditorValidatorCollection.cs
index 535d1133a6..6fc6bb5de2 100644
--- a/src/Umbraco.Web/Editors/EditorValidatorCollection.cs
+++ b/src/Umbraco.Web/Editors/EditorValidatorCollection.cs
@@ -11,14 +11,5 @@ namespace Umbraco.Web.Editors
public EditorValidatorCollection(IEnumerable items)
: base(items)
{ }
-
- public IEnumerable Validate(object model)
- {
- var modelType = model.GetType();
- return this
- .Where(x => x.ModelType == modelType)
- .WhereNotNull()
- .SelectMany(x => x.Validate(model));
- }
}
}
diff --git a/src/Umbraco.Web/Editors/EditorValidatorOfT.cs b/src/Umbraco.Web/Editors/EditorValidatorOfT.cs
new file mode 100644
index 0000000000..4ca008cf0d
--- /dev/null
+++ b/src/Umbraco.Web/Editors/EditorValidatorOfT.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Umbraco.Web.Editors
+{
+ ///
+ /// Provides a base class for implementations.
+ ///
+ /// The validated object type.
+ internal abstract class EditorValidator : IEditorValidator
+ {
+ public Type ModelType => typeof (T);
+
+ public IEnumerable Validate(object model) => Validate((T) model);
+
+ protected abstract IEnumerable Validate(T model);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Editors/IEditorValidator.cs b/src/Umbraco.Web/Editors/IEditorValidator.cs
index bf6aa3c643..bec978788c 100644
--- a/src/Umbraco.Web/Editors/IEditorValidator.cs
+++ b/src/Umbraco.Web/Editors/IEditorValidator.cs
@@ -5,9 +5,32 @@ using Umbraco.Core.Composing;
namespace Umbraco.Web.Editors
{
+ // note - about IEditorValidator
+ //
+ // interface: IEditorValidator
+ // base class: EditorValidator
+ // static validation: EditorValidator.Validate()
+ // composition: via EditorValidationCollection and builder
+ // initialized with all IEditorValidator instances
+ //
+ // validation is used exclusively in ContentTypeControllerBase
+ // the whole thing is internal at the moment, never released
+ // and, there are no IEditorValidator implementation in Core
+ // so... this all mechanism is basically useless
+
+ ///
+ /// Provides a general object validator.
+ ///
internal interface IEditorValidator : IDiscoverable
{
+ ///
+ /// Gets the object type validated by this validator.
+ ///
Type ModelType { get; }
+
+ ///
+ /// Validates an object.
+ ///
IEnumerable Validate(object model);
}
}
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index e77b5497b2..5287b06a00 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -36,6 +36,7 @@ using Notification = Umbraco.Web.Models.ContentEditing.Notification;
using Umbraco.Core.Persistence;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Models.Editors;
+using Umbraco.Core.Models.Validation;
namespace Umbraco.Web.Editors
{
@@ -481,7 +482,7 @@ namespace Umbraco.Web.Editors
// a message indicating this
if (ModelState.IsValid == false)
{
- if (ValidationHelper.ModelHasRequiredForPersistenceErrors(contentItem)
+ if (!RequiredForPersistenceAttribute.HasRequiredValuesForPersistence(contentItem)
&& (contentItem.Action == ContentSaveAction.SaveNew))
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index 0ab42b9d7f..3bb1e60be2 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -205,8 +205,9 @@ namespace Umbraco.Web.Editors
if (!Security.CurrentUser.IsSuper())
{
- // only super can see super
- filterQuery.Where(x => !x.IsSuper());
+ // only super can see super - but don't use IsSuper, cannot be mapped to SQL - fixme NOW
+ //filterQuery.Where(x => !x.IsSuper());
+ filterQuery.Where(x => x.Id != Constants.Security.SuperId);
}
if (filter.IsNullOrWhiteSpace() == false)
diff --git a/src/Umbraco.Web/Editors/ValidationHelper.cs b/src/Umbraco.Web/Editors/ValidationHelper.cs
deleted file mode 100644
index 09140d1ee1..0000000000
--- a/src/Umbraco.Web/Editors/ValidationHelper.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Linq;
-using System.Web.Http.ModelBinding;
-using Umbraco.Core;
-using Umbraco.Core.Models.Validation;
-using Umbraco.Web.Composing;
-
-namespace Umbraco.Web.Editors
-{
- internal class ValidationHelper
- {
- internal static void ValidateEditorModelWithResolver(ModelStateDictionary modelState, object model)
- {
- var validationResult = Current.EditorValidators.Validate(model);
- foreach (var vr in validationResult
- .WhereNotNull()
- .Where(x => x.ErrorMessage.IsNullOrWhiteSpace() == false)
- .Where(x => x.MemberNames.Any()))
- {
- foreach (var memberName in vr.MemberNames)
- {
- modelState.AddModelError(memberName, vr.ErrorMessage);
- }
- }
- }
-
- ///
- /// This will check if any properties of the model are attributed with the RequiredForPersistenceAttribute attribute and if they are it will
- /// check if that property validates, if it doesn't it means that the current model cannot be persisted because it doesn't have the necessary information
- /// to be saved.
- ///
- ///
- ///
- ///
- /// This is normally used for things like content creating when the name is empty since we cannot actually create a content item when the name is empty.
- /// This is similar but different from the standard Required validator since we still allow content to be saved when validation fails but there are some
- /// content fields that are absolutely mandatory for creating/saving.
- ///
- internal static bool ModelHasRequiredForPersistenceErrors(object model)
- {
- var requiredForPersistenceProperties = TypeDescriptor.GetProperties(model).Cast()
- .Where(x => x.Attributes.Cast().Any(a => a is RequiredForPersistenceAttribute));
-
- var validator = new RequiredForPersistenceAttribute();
- return requiredForPersistenceProperties.Any(p => !validator.IsValid(p.GetValue(model)));
- }
- }
-}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
index 73f474c46d..dff38938e0 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
@@ -126,7 +126,7 @@ namespace Umbraco.Web.Models.Mapping
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}doctype",
Label = localizedText.Localize("content/documentType"),
Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
- View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].ValueEditor.View
+ View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View
},
new ContentPropertyDisplay
{
@@ -134,7 +134,7 @@ namespace Umbraco.Web.Models.Mapping
Label = localizedText.Localize("content/releaseDate"),
Value = display.ReleaseDate?.ToIsoString(),
//Not editible for people without publish permission (U4-287)
- View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].ValueEditor.View,
+ View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View,
Config = new Dictionary
{
{"offsetTime", "1"}
@@ -147,7 +147,7 @@ namespace Umbraco.Web.Models.Mapping
Label = localizedText.Localize("content/unpublishDate"),
Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null,
//Not editible for people without publish permission (U4-287)
- View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].ValueEditor.View,
+ View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View,
Config = new Dictionary
{
{"offsetTime", "1"}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
index 6d703c1f6e..b4f0436660 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
@@ -15,11 +15,13 @@ namespace Umbraco.Web.Models.Mapping
internal class ContentPropertyBasicConverter : ITypeConverter
where TDestination : ContentPropertyBasic, new()
{
- protected Lazy DataTypeService { get; }
+ private readonly Lazy _dataTypeService;
+
+ protected IDataTypeService DataTypeService => _dataTypeService.Value;
public ContentPropertyBasicConverter(Lazy dataTypeService)
{
- DataTypeService = dataTypeService;
+ _dataTypeService = dataTypeService;
}
///
@@ -40,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
var result = new TDestination
{
Id = property.Id,
- Value = editor.ValueEditor.ConvertDbToEditor(property, property.PropertyType, DataTypeService.Value),
+ Value = editor.GetValueEditor().ToEditor(property, DataTypeService),
Alias = property.Alias,
PropertyEditor = editor,
Editor = editor.Alias
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
index 367fc89b1b..99540fc6ea 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
@@ -23,18 +23,16 @@ namespace Umbraco.Web.Models.Mapping
{
var display = base.Convert(originalProp, dest, context);
- var dataTypeService = DataTypeService.Value;
- var config = dataTypeService.GetDataType(originalProp.PropertyType.DataTypeId).Configuration;
+ var config = DataTypeService.GetDataType(originalProp.PropertyType.DataTypeId).Configuration;
- //configure the editor for display with the pre-values
- var valEditor = display.PropertyEditor.ValueEditor;
- // fixme - the value editor REQUIRES the configuration to operate
- // at the moment, only for richtext and nested, where it's used to set HideLabel
- // but, this is the ONLY place where it's assigned? it is also the only place where
- // .HideLabel is used - and basically all the rest kinda never depends on config,
- // but... it should?
- var ve = (DataValueEditor) valEditor;
- ve.Configuration = config;
+ // fixme - IDataValueEditor configuration - general issue
+ // GetValueEditor() returns a non-configured IDataValueEditor
+ // - for richtext and nested, configuration determines HideLabel, so we need to configure the value editor
+ // - could configuration also determines ValueType, everywhere?
+ // - does it make any sense to use a IDataValueEditor without configuring it?
+
+ // configure the editor for display with configuration
+ var valEditor = display.PropertyEditor.GetValueEditor(config);
//set the display properties after mapping
display.Alias = originalProp.Alias;
@@ -56,7 +54,7 @@ namespace Umbraco.Web.Models.Mapping
else
{
//let the property editor format the pre-values
- display.Config = display.PropertyEditor.ConfigurationEditor.ToValueEditor(config);
+ display.Config = display.PropertyEditor.GetConfigurationEditor().ToValueEditor(config);
display.View = valEditor.View;
}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
index 13b3be853b..c1cad75674 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
@@ -19,13 +19,11 @@ namespace Umbraco.Web.Models.Mapping
{
var propertyDto = base.Convert(originalProperty, dest, context);
- var dataTypeService = DataTypeService.Value;
-
propertyDto.IsRequired = originalProperty.PropertyType.Mandatory;
propertyDto.ValidationRegExp = originalProperty.PropertyType.ValidationRegExp;
propertyDto.Description = originalProperty.PropertyType.Description;
propertyDto.Label = originalProperty.PropertyType.Name;
- propertyDto.DataType = dataTypeService.GetDataType(originalProperty.PropertyType.DataTypeId);
+ propertyDto.DataType = DataTypeService.GetDataType(originalProperty.PropertyType.DataTypeId);
return propertyDto;
}
diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs b/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs
index 3e70f36839..9cdbd6101e 100644
--- a/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs
@@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
-using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
-using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
@@ -26,8 +24,8 @@ namespace Umbraco.Web.Models.Mapping
{
if (configuration.TryGetValue(field.Key, out var value))
field.Value = value;
- else // fixme should this be fatal?
- Current.Logger.Warn($"Could not find persisted pre-value for field \"{field.Key}\".");
+ else // weird - just leave the field without a value - but warn
+ Current.Logger.Warn($"Could not find a value for configuration field \"{field.Key}\".");
}
}
@@ -36,26 +34,17 @@ namespace Umbraco.Web.Models.Mapping
///
public IEnumerable Resolve(IDataType dataType)
{
- if (string.IsNullOrWhiteSpace(dataType.EditorAlias) || !Current.PropertyEditors.TryGet(dataType.EditorAlias, out var e) || !(e is DataEditor editor))
+ // in v7 it was apparently fine to have an empty .EditorAlias here, in which case we would map onto
+ // an empty fields list, which made no sense since there would be nothing to map to - and besides,
+ // a datatype without an editor alias is a serious issue - v8 wants an editor here
+
+ if (string.IsNullOrWhiteSpace(dataType.EditorAlias) || !Current.PropertyEditors.TryGet(dataType.EditorAlias, out var editor))
throw new InvalidOperationException($"Could not find a property editor with alias \"{dataType.EditorAlias}\".");
- var configuration = dataType.Configuration;
- Dictionary configurationDictionary = null;
- var fields = Array.Empty();
+ var configurationEditor = editor.GetConfigurationEditor();
+ var fields = configurationEditor.Fields.Select(Mapper.Map).ToArray();
+ var configurationDictionary = configurationEditor.ToConfigurationEditor(dataType.Configuration);
- // if we have a property editor,
- // map the configuration editor field to display,
- // and convert configuration to editor
- if (editor != null)
- {
- var configurationEditor = editor.ConfigurationEditor;
- fields = configurationEditor.Fields.Select(Mapper.Map).ToArray();
- configurationDictionary = configurationEditor.ToConfigurationEditor(configuration);
- }
-
- if (configurationDictionary == null)
- configurationDictionary = new Dictionary();
-
MapConfigurationFields(fields, configurationDictionary);
return fields;
diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs
index fa1146adae..92a0be1346 100644
--- a/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs
@@ -23,7 +23,7 @@ namespace Umbraco.Web.Models.Mapping
var configurationDisplayResolver = new DataTypeConfigurationFieldDisplayResolver();
var databaseTypeResolver = new DatabaseTypeResolver();
- CreateMap();
+ CreateMap();
// map the standard properties, not the values
CreateMap()
@@ -36,7 +36,7 @@ namespace Umbraco.Web.Models.Mapping
Constants.DataTypes.DefaultMembersListView
};
- CreateMap()
+ CreateMap()
.ForMember(dest => dest.Udi, opt => opt.Ignore())
.ForMember(dest => dest.HasPrevalues, opt => opt.Ignore())
.ForMember(dest => dest.IsSystemDataType, opt => opt.Ignore())
@@ -105,7 +105,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.Editor, opt => opt.MapFrom(src => propertyEditors[src.EditorAlias]));
//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>()
+ CreateMap>()
.ConvertUsing(src =>
{
// this is a new data type, initialize default configuration
@@ -113,7 +113,7 @@ namespace Umbraco.Web.Models.Mapping
// get the configuration fields and map to UI,
// get the configuration default values and map to UI
- var configurationEditor = src.ConfigurationEditor;
+ var configurationEditor = src.GetConfigurationEditor();
var fields = configurationEditor.Fields.Select(Mapper.Map).ToArray();
diff --git a/src/Umbraco.Web/Models/Mapping/DatabaseTypeResolver.cs b/src/Umbraco.Web/Models/Mapping/DatabaseTypeResolver.cs
index 540217d493..8cf32339f9 100644
--- a/src/Umbraco.Web/Models/Mapping/DatabaseTypeResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/DatabaseTypeResolver.cs
@@ -13,13 +13,11 @@ namespace Umbraco.Web.Models.Mapping
{
public ValueStorageType Resolve(DataTypeSave source)
{
- var propertyEditor = Current.PropertyEditors[source.EditorAlias];
- if (propertyEditor == null)
- {
- throw new InvalidOperationException("Could not find property editor with id " + source.EditorAlias);
- }
+ if (!Current.PropertyEditors.TryGet(source.EditorAlias, out var editor))
+ throw new InvalidOperationException($"Could not find property editor \"{source.EditorAlias}\".");
- var valueType = propertyEditor.ValueEditor.ValueType;
+ // fixme - what about source.PropertyEditor? can we get the configuration here? 'cos it may change the storage type?!
+ var valueType = editor.GetValueEditor().ValueType;
return ValueTypes.ToStorageType(valueType);
}
}
diff --git a/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs
index 8cc68ea77f..2e97697578 100644
--- a/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/MacroMapperProfile.cs
@@ -44,7 +44,7 @@ namespace Umbraco.Web.Models.Mapping
Current.Logger.Warn("Could not resolve a parameter editor with alias " + property.EditorAlias + ", a textbox will be rendered in it's place");
}
- parameter.View = paramEditor.ValueEditor.View;
+ parameter.View = paramEditor.GetValueEditor().View;
//set the config
parameter.Configuration = paramEditor.DefaultConfiguration;
});
diff --git a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs
index 70329a0d48..6d3ae36759 100644
--- a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs
@@ -96,7 +96,7 @@ namespace Umbraco.Web.Models.Mapping
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/mediatype"),
Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
- View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].ValueEditor.View
+ View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View
}
};
diff --git a/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs
index 8c79ccc97c..24f5b5ebfd 100644
--- a/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs
@@ -179,7 +179,7 @@ namespace Umbraco.Web.Models.Mapping
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/membertype"),
Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
- View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].ValueEditor.View
+ View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View
},
GetLoginProperty(memberService, member, display, localizedText),
new ContentPropertyDisplay
diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs
index 772aa23744..9a1aeda845 100644
--- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs
@@ -212,8 +212,8 @@ namespace Umbraco.Web.Models.Mapping
Editor = p.PropertyEditorAlias,
Validation = new PropertyTypeValidation {Mandatory = p.Mandatory, Pattern = p.ValidationRegExp},
Label = p.Name,
- View = propertyEditor.ValueEditor.View,
- Config = propertyEditor.ConfigurationEditor.ToConfigurationEditor(configuration),
+ View = propertyEditor.GetValueEditor().View,
+ Config = propertyEditor.GetConfigurationEditor().ToConfigurationEditor(configuration),
//Value = "",
GroupId = groupId,
Inherited = inherited,
diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs
index f3c9df26a8..696837c669 100644
--- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs
@@ -57,7 +57,7 @@ namespace Umbraco.Web.Models.Mapping
//store the current props to append to the newly inserted ones
var currProps = genericProps.Properties.ToArray();
- var labelEditor = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].ValueEditor.View;
+ var labelEditor = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View;
var contentProps = new List
{
@@ -162,7 +162,7 @@ namespace Umbraco.Web.Models.Mapping
IsActive = true
};
- var listViewConfig = editor.ConfigurationEditor.ToConfigurationEditor(dt.Configuration);
+ var listViewConfig = editor.GetConfigurationEditor().ToConfigurationEditor(dt.Configuration);
//add the entity type to the config
listViewConfig["entityType"] = entityType;
@@ -180,7 +180,7 @@ namespace Umbraco.Web.Models.Mapping
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}containerView",
Label = "",
Value = null,
- View = editor.ValueEditor.View,
+ View = editor.GetValueEditor().View,
HideLabel = true,
Config = listViewConfig
});
diff --git a/src/Umbraco.Web/Models/PublishedProperty.cs b/src/Umbraco.Web/Models/PublishedProperty.cs
index 535b704e7b..b3bad63609 100644
--- a/src/Umbraco.Web/Models/PublishedProperty.cs
+++ b/src/Umbraco.Web/Models/PublishedProperty.cs
@@ -48,7 +48,7 @@ namespace Umbraco.Web.Models
// nothing ensures that the two methods are consistent.
if (e != null)
- v = e.ValueEditor.ConvertDbToString(p.PropertyType, v, dataTypeService);
+ v = e.GetValueEditor().ConvertDbToString(p.PropertyType, v, dataTypeService);
}
return map(x, v);
diff --git a/src/Umbraco.Web/PropertyEditors/DateValueEditor.cs b/src/Umbraco.Web/PropertyEditors/DateValueEditor.cs
index b47cd6a0e5..728b4474a8 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 ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
var date = property.GetValue().TryConvertTo();
if (date.Success == false || date.Result == null)
diff --git a/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs
index a4a682d95f..011e46475c 100644
--- a/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs
@@ -40,7 +40,7 @@ namespace Umbraco.Web.PropertyEditors
/// Other places (FileUploadPropertyEditor...) do NOT deal with multiple files, and our logic for reusing
/// folders would NOT work, etc.
///
- public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
currentValue = currentValue ?? string.Empty;
diff --git a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs
index ca7705aaa0..eb1af95def 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 ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
ImageCropperValue value;
try
@@ -45,7 +45,7 @@ namespace Umbraco.Web.PropertyEditors
value = new ImageCropperValue { Src = property.GetValue().ToString() };
}
- var dataType = dataTypeService.GetDataType(propertyType.DataTypeId);
+ var dataType = dataTypeService.GetDataType(property.PropertyType.DataTypeId);
if (dataType?.Configuration != null)
value.ApplyConfiguration(dataType.ConfigurationAs());
@@ -62,7 +62,7 @@ namespace Umbraco.Web.PropertyEditors
/// editorValue.Value is used to figure out editorFile and, if it has been cleared, remove the old file - but
/// it is editorValue.AdditionalData["files"] that is used to determine the actual file that has been uploaded.
///
- public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
// get the current path
var currentPath = string.Empty;
diff --git a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs
index 66fdfec7ac..a30a48a241 100644
--- a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs
@@ -4,7 +4,7 @@ using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
- // fixme - if deprecated, what's the alternative?
+ // fixme - MacroContainerPropertyEditor is deprecated, but what's the alternative?
[DataEditor(Constants.PropertyEditors.Aliases.MacroContainer, "(Obsolete) Macro Picker", "macrocontainer", ValueType = ValueTypes.Text, Group="rich content", Icon="icon-settings-alt", IsDeprecated = true)]
public class MacroContainerPropertyEditor : DataEditor
{
diff --git a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs
index df2174ed09..76c334f254 100644
--- a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs
@@ -47,7 +47,7 @@ namespace Umbraco.Web.PropertyEditors
///
/// We will also check the pre-values here, if there are more items than what is allowed we'll just trim the end
///
- public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
var asArray = editorValue.Value as JArray;
if (asArray == null)
@@ -84,7 +84,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 ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
return property.GetValue() == null
? new JObject[] {}
diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs
index 3fbbab1510..95121e8b02 100644
--- a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs
@@ -74,9 +74,10 @@ namespace Umbraco.Web.PropertyEditors
if (value == null)
throw new ArgumentNullException(nameof(value));
if (!(value is NestedContentConfiguration configuration))
- throw new ArgumentException($"Expected a {typeof(RichTextConfiguration).Name} instance, but got {value.GetType().Name}.", nameof(value));
- HideLabel = configuration.HideLabel.TryConvertTo().Result;
+ throw new ArgumentException($"Expected a {typeof(NestedContentConfiguration).Name} instance, but got {value.GetType().Name}.", nameof(value));
base.Configuration = value;
+
+ HideLabel = configuration.HideLabel.TryConvertTo().Result;
}
}
@@ -115,7 +116,9 @@ namespace Umbraco.Web.PropertyEditors
{
// convert the value, and store the converted value
var propEditor = _propertyEditors[propType.PropertyEditorAlias];
- var convValue = propEditor.ValueEditor.ConvertDbToString(propType, propValues[propAlias]?.ToString(), dataTypeService);
+ var tempConfig = dataTypeService.GetDataType(propType.DataTypeId).Configuration;
+ var valEditor = propEditor.GetValueEditor(tempConfig);
+ var convValue = valEditor.ConvertDbToString(propType, propValues[propAlias]?.ToString(), dataTypeService);
propValues[propAlias] = convValue;
}
catch (InvalidOperationException)
@@ -136,7 +139,7 @@ namespace Umbraco.Web.PropertyEditors
// note: there is NO variant support here
- public override object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
if (property.GetValue() == null || string.IsNullOrWhiteSpace(property.GetValue().ToString()))
return string.Empty;
@@ -173,7 +176,9 @@ namespace Umbraco.Web.PropertyEditors
// convert that temp property, and store the converted value
var propEditor = _propertyEditors[propType.PropertyEditorAlias];
- var convValue = propEditor.ValueEditor.ConvertDbToEditor(tempProp, propType, dataTypeService);
+ var tempConfig = dataTypeService.GetDataType(propType.DataTypeId).Configuration;
+ var valEditor = propEditor.GetValueEditor(tempConfig);
+ var convValue = valEditor.ToEditor(tempProp, dataTypeService);
propValues[propAlias] = convValue == null ? null : JToken.FromObject(convValue);
}
catch (InvalidOperationException)
@@ -190,7 +195,7 @@ namespace Umbraco.Web.PropertyEditors
return value;
}
- public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
if (editorValue.Value == null || string.IsNullOrWhiteSpace(editorValue.Value.ToString()))
return null;
@@ -240,7 +245,7 @@ namespace Umbraco.Web.PropertyEditors
var contentPropData = new ContentPropertyData(propValues[propKey], propConfiguration);
// Get the property editor to do it's conversion
- var newValue = propEditor.ValueEditor.ConvertEditorToDb(contentPropData, propValues[propKey]);
+ var newValue = propEditor.GetValueEditor().FromEditor(contentPropData, propValues[propKey]);
// Store the value back
propValues[propKey] = (newValue == null) ? null : JToken.FromObject(newValue);
@@ -289,9 +294,9 @@ namespace Umbraco.Web.PropertyEditors
var config = dataTypeService.GetDataType(propType.DataTypeId).Configuration;
var propertyEditor = _propertyEditors[propType.PropertyEditorAlias];
- foreach (var validator in propertyEditor.ValueEditor.Validators)
+ foreach (var validator in propertyEditor.GetValueEditor().Validators)
{
- foreach (var result in validator.Validate(propValues[propKey], propertyEditor.ValueEditor.ValueType, config))
+ foreach (var result in validator.Validate(propValues[propKey], propertyEditor.GetValueEditor().ValueType, config))
{
result.ErrorMessage = "Item " + (i + 1) + " '" + propType.Name + "' " + result.ErrorMessage;
yield return result;
diff --git a/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs b/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs
index a05f04224a..803c8b5994 100644
--- a/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/PublishValuesMultipleValueEditor.cs
@@ -72,9 +72,9 @@ namespace Umbraco.Web.PropertyEditors
///
///
///
- public override object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
- var delimited = base.ConvertDbToEditor(property, propertyType, dataTypeService).ToString();
+ var delimited = base.ToEditor(property, dataTypeService).ToString();
return delimited.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
@@ -85,7 +85,7 @@ namespace Umbraco.Web.PropertyEditors
///
///
///
- public override object ConvertEditorToDb(Core.Models.Editors.ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(Core.Models.Editors.ContentPropertyData editorValue, object currentValue)
{
var json = editorValue.Value as JArray;
if (json == null)
diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
index ec499d9f01..56fd24bb8a 100644
--- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
@@ -50,10 +50,10 @@ namespace Umbraco.Web.PropertyEditors
throw new ArgumentNullException(nameof(value));
if (!(value is RichTextConfiguration configuration))
throw new ArgumentException($"Expected a {typeof(RichTextConfiguration).Name} instance, but got {value.GetType().Name}.", nameof(value));
- HideLabel = configuration.HideLabel;
base.Configuration = value;
- }
+ HideLabel = configuration.HideLabel;
+ }
}
///
@@ -63,7 +63,7 @@ namespace Umbraco.Web.PropertyEditors
///
///
///
- public override object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
if (property.GetValue() == null)
return null;
@@ -78,7 +78,7 @@ namespace Umbraco.Web.PropertyEditors
///
///
///
- public override object ConvertEditorToDb(Core.Models.Editors.ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(Core.Models.Editors.ContentPropertyData editorValue, object currentValue)
{
if (editorValue.Value == null)
return null;
diff --git a/src/Umbraco.Web/PropertyEditors/TagConfigurationEditor.cs b/src/Umbraco.Web/PropertyEditors/TagConfigurationEditor.cs
index aa823ea5a9..3a68c878b6 100644
--- a/src/Umbraco.Web/PropertyEditors/TagConfigurationEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/TagConfigurationEditor.cs
@@ -4,6 +4,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.PropertyEditors.Validators;
namespace Umbraco.Web.PropertyEditors
{
@@ -12,9 +13,9 @@ namespace Umbraco.Web.PropertyEditors
///
public class TagConfigurationEditor : ConfigurationEditor
{
- public TagConfigurationEditor(ManifestValidatorCollection validators)
+ public TagConfigurationEditor(ManifestValueValidatorCollection validators)
{
- Fields.Add(new ConfigurationField(new ManifestValueValidator(validators) { ValidationName = "Required" })
+ Fields.Add(new ConfigurationField(new RequiredValidator())
{
Description = "Define a tag group",
Key = "group",
@@ -23,7 +24,7 @@ namespace Umbraco.Web.PropertyEditors
View = "requiredfield"
});
- Fields.Add(new ConfigurationField(new ManifestValueValidator(validators) {ValidationName = "Required"})
+ Fields.Add(new ConfigurationField(new RequiredValidator())
{
Description = "Select whether to store the tags in cache as CSV (default) or as JSON. The only benefits of storage as JSON is that you are able to have commas in a tag value but this will require parsing the json in your views or using a property value converter",
Key = "storageType",
diff --git a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs
index e863c662a7..88a8c92ba3 100644
--- a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs
@@ -17,9 +17,9 @@ namespace Umbraco.Web.PropertyEditors
[DataEditor(Constants.PropertyEditors.Aliases.Tags, "Tags", "tags", Icon="icon-tags")]
public class TagsPropertyEditor : DataEditor
{
- private readonly ManifestValidatorCollection _validators;
+ private readonly ManifestValueValidatorCollection _validators;
- public TagsPropertyEditor(ManifestValidatorCollection validators, ILogger logger)
+ public TagsPropertyEditor(ManifestValueValidatorCollection validators, ILogger logger)
: base(logger)
{
_validators = validators;
@@ -36,7 +36,7 @@ namespace Umbraco.Web.PropertyEditors
{ }
///
- public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
+ public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
return editorValue.Value is JArray json
? json.Select(x => x.Value())
@@ -44,41 +44,29 @@ namespace Umbraco.Web.PropertyEditors
}
///
- public override ManifestValidator RequiredValidator => new RequiredTagsValueValidator();
+ public override IValueRequiredValidator RequiredValidator => new RequiredJsonValueValidator();
///
- /// Custom validator to validate a required value against an empty json value
+ /// Custom validator to validate a required value against an empty json value.
///
///
- /// This is required because the Tags property editor is not of type 'JSON', it's just string so the underlying
- /// validator does not validate against an empty json string
+ /// This validator is required because the default RequiredValidator uses ValueType to
+ /// determine whether a property value is JSON, and for tags the ValueType is string although
+ /// the underlying data is JSON. Yes, this makes little sense.
///
- private class RequiredTagsValueValidator : ManifestValidator
+ private class RequiredJsonValueValidator : IValueRequiredValidator
{
///
- public override string ValidationName => "Required";
-
- ///
- public override IEnumerable Validate(object value, string valueType, object dataTypeConfiguration, object validatorConfiguration)
+ public IEnumerable ValidateRequired(object value, string valueType)
{
if (value == null)
{
- yield return new ValidationResult("Value cannot be null", new[] { "value" });
+ yield return new ValidationResult("Value cannot be null", new[] {"value"});
+ yield break;
}
- else
- {
- var asString = value.ToString();
- if (asString.DetectIsEmptyJson())
- {
- yield return new ValidationResult("Value cannot be empty", new[] { "value" });
- }
-
- if (asString.IsNullOrWhiteSpace())
- {
- yield return new ValidationResult("Value cannot be empty", new[] { "value" });
- }
- }
+ if (value.ToString().DetectIsEmptyJson())
+ yield return new ValidationResult("Value cannot be empty", new[] { "value" });
}
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs b/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs
index 6f6598576a..8c056f5ff7 100644
--- a/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/TextOnlyValueEditor.cs
@@ -25,7 +25,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 ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
+ public override object ToEditor(Property property, IDataTypeService dataTypeService)
{
if (property.GetValue() == null) return string.Empty;
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
index 224a35f3c3..bf1fd2473b 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
@@ -757,7 +757,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
using (_contentStore.GetWriter(_scopeProvider))
using (_mediaStore.GetWriter(_scopeProvider))
{
- // fixme - datatype lock
+ // fixme - need to add a datatype lock
// this is triggering datatypes reload in the factory, and right after we create some
// content types by loading them ... there's a race condition here, which would require
// some locking on datatypes
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 6e12f51097..86545139a6 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -133,6 +133,7 @@
+
@@ -812,7 +813,6 @@
-
diff --git a/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs b/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs
index aab19481b9..02396fc92f 100644
--- a/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs
+++ b/src/Umbraco.Web/WebApi/Filters/ContentItemValidationHelper.cs
@@ -1,11 +1,8 @@
using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
-using System.Web.Http.ModelBinding;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -117,64 +114,23 @@ namespace Umbraco.Web.WebApi.Filters
foreach (var p in postedItem.ContentDto.Properties)
{
var editor = p.PropertyEditor;
+
if (editor == null)
{
- var message = string.Format("The property editor with alias: {0} was not found for property with id {1}", p.DataType.EditorAlias, p.Id);
+ var message = $"Could not find property editor \"{p.DataType.EditorAlias}\" for property with id {p.Id}.";
Current.Logger.Warn>(message);
//actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
//return false;
continue;
}
- //get the posted value for this property
+ // get the posted value
var postedValue = postedItem.Properties.Single(x => x.Alias == p.Alias).Value;
- //get the pre-values for this property
- var preValues = p.DataType.Configuration;
-
- // fixme what does this mean?
- //TODO: when we figure out how to 'override' certain pre-value properties we'll either need to:
- // * Combine the preValues with the overridden values stored with the document type property (but how to combine?)
- // * Or, pass in the overridden values stored with the doc type property separately
-
- foreach (var result in editor.ValueEditor.Validators.SelectMany(v => v.Validate(postedValue, editor.ValueEditor.ValueType, preValues)))
- {
- actionContext.ModelState.AddPropertyError(result, p.Alias);
- }
-
- //Now we need to validate the property based on the PropertyType validation (i.e. regex and required)
- // NOTE: These will become legacy once we have pre-value overrides.
- if (p.IsRequired)
- {
- foreach (var result in p.PropertyEditor.ValueEditor.RequiredValidator.Validate(postedValue, editor.ValueEditor.ValueType, preValues, null))
- {
- actionContext.ModelState.AddPropertyError(result, p.Alias);
- }
- }
-
- if (p.ValidationRegExp.IsNullOrWhiteSpace() == false)
- {
-
- //We only want to execute the regex statement if:
- // * the value is null or empty AND it is required OR
- // * the value is not null or empty
- //See: http://issues.umbraco.org/issue/U4-4669
-
- var asString = postedValue as string;
-
- if (
- //Value is not null or empty
- (postedValue != null && asString.IsNullOrWhiteSpace() == false)
- //It's required
- || (p.IsRequired))
- {
- foreach (var result in p.PropertyEditor.ValueEditor.RegexValidator.Validate(postedValue, null, preValues, p.ValidationRegExp))
- {
- actionContext.ModelState.AddPropertyError(result, p.Alias);
- }
- }
-
- }
+ // validate
+ var valueEditor = editor.GetValueEditor(p.DataType.Configuration);
+ foreach (var r in valueEditor.Validate(postedValue, p.IsRequired, p.ValidationRegExp))
+ actionContext.ModelState.AddPropertyError(r, p.Alias);
}
return actionContext.ModelState.IsValid;