using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Editors;
using Umbraco.Cms.Core.PropertyEditors.Validators;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors
{
///
/// Represents a value editor.
///
[DataContract]
public class DataValueEditor : IDataValueEditor
{
private readonly ILocalizedTextService _localizedTextService;
private readonly IShortStringHelper _shortStringHelper;
private readonly IJsonSerializer _jsonSerializer;
///
/// Initializes a new instance of the class.
///
public DataValueEditor(
ILocalizedTextService localizedTextService,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer) // for tests, and manifest
{
_localizedTextService = localizedTextService;
_shortStringHelper = shortStringHelper;
_jsonSerializer = jsonSerializer;
ValueType = ValueTypes.String;
Validators = new List();
}
///
/// Initializes a new instance of the class.
///
public DataValueEditor(
ILocalizedTextService localizedTextService,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
DataEditorAttribute attribute)
{
if (attribute == null) throw new ArgumentNullException(nameof(attribute));
_localizedTextService = localizedTextService;
_shortStringHelper = shortStringHelper;
_jsonSerializer = jsonSerializer;
var view = attribute.View;
if (string.IsNullOrWhiteSpace(view))
throw new ArgumentException("The attribute does not specify a view.", nameof(attribute));
if (view.StartsWith("~/"))
{
view = ioHelper.ResolveRelativeOrVirtualUrl(view);
}
View = view;
ValueType = attribute.ValueType;
HideLabel = attribute.HideLabel;
}
///
/// Gets or sets the value editor configuration.
///
public virtual object Configuration { get; set; }
///
/// Gets or sets the editor view.
///
///
/// The view can be three things: (1) the full virtual path, or (2) the relative path to the current Umbraco
/// folder, or (3) a view name which maps to views/propertyeditors/{view}/{view}.html.
///
[Required]
[DataMember(Name = "view")]
public string View { get; set; }
///
/// The value type which reflects how it is validated and stored in the database
///
[DataMember(Name = "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 explicitly 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
///
[DataMember(Name = "validation")]
public List Validators { get; private set; } = new List();
///
/// Gets the validator used to validate the special property type -level "required".
///
public virtual IValueRequiredValidator RequiredValidator => new RequiredValidator(_localizedTextService);
///
/// Gets the validator used to validate the special property type -level "format".
///
public virtual IValueFormatValidator FormatValidator => new RegexValidator(_localizedTextService);
///
/// If this is true than the editor will be displayed full width without a label
///
[DataMember(Name = "hideLabel")]
public bool HideLabel { get; set; }
///
/// Set this to true if the property editor is for display purposes only
///
public virtual bool IsReadOnly => false;
///
/// Used to try to convert the string value to the correct CLR type based on the specified for this value editor.
///
/// The value.
///
/// The result of the conversion attempt.
///
/// ValueType was out of range.
internal Attempt