From eb62789b68d14c8efae1ce98e74e4456ed51b6ec Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Fri, 18 Sep 2020 12:02:12 +0200 Subject: [PATCH] Added configuration validation for content imaging settings. --- .../ContentSettingsExtensions.cs | 2 +- .../Configuration/Models/ContentErrorPage.cs | 10 ++++---- .../Models/ContentImagingSettings.cs | 22 +++--------------- .../Models/ImagingAutoFillUploadField.cs | 23 +++++++++++++++++++ .../Validation/ConfigurationValidationBase.cs | 12 ++++++++++ .../Validation/ContentSettingsValidation.cs | 20 +++++++++------- .../Models/Validation/ValidatableEntryBase.cs | 15 ++++++++++++ .../Media/UploadAutoFillProperties.cs | 11 ++++----- 8 files changed, 77 insertions(+), 38 deletions(-) create mode 100644 src/Umbraco.Core/Configuration/Models/ImagingAutoFillUploadField.cs create mode 100644 src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs diff --git a/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs b/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs index 21ebe55f2f..7bf8f0fa15 100644 --- a/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs +++ b/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs @@ -39,7 +39,7 @@ namespace Umbraco.Core.Configuration /// /// The property type alias. /// The auto-fill configuration for the specified property alias, or null. - public static IImagingAutoFillUploadField GetConfig(this ContentSettings contentSettings, string propertyTypeAlias) + public static ImagingAutoFillUploadField GetConfig(this ContentSettings contentSettings, string propertyTypeAlias) { var autoFillConfigs = contentSettings.Imaging.AutoFillImageProperties; return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias); diff --git a/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs index ec4869d3b4..6a362c93a3 100644 --- a/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs +++ b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs @@ -1,8 +1,10 @@ using System; +using System.ComponentModel.DataAnnotations; +using Umbraco.Core.Configuration.Models.Validation; namespace Umbraco.Core.Configuration.Models { - public class ContentErrorPage + public class ContentErrorPage : ValidatableEntryBase { public int ContentId { get; set; } @@ -16,12 +18,12 @@ namespace Umbraco.Core.Configuration.Models public bool HasContentXPath => !string.IsNullOrEmpty(ContentXPath); + [Required] public string Culture { get; set; } - public bool IsValid() + internal override bool IsValid() { - // Entry is valid if Culture and one and only one of ContentId, ContentKey or ContentXPath is provided. - return !string.IsNullOrWhiteSpace(Culture) && + return base.IsValid() && ((HasContentId ? 1 : 0) + (HasContentKey ? 1 : 0) + (HasContentXPath ? 1 : 0) == 1); } } diff --git a/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs index 681dcbbe88..7c1e570426 100644 --- a/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Core.Configuration.Models +namespace Umbraco.Core.Configuration.Models { public class ContentImagingSettings { @@ -17,21 +14,8 @@ namespace Umbraco.Core.Configuration.Models } }; - public IEnumerable ImageFileTypes { get; set; } = new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }; + public string[] ImageFileTypes { get; set; } = new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }; - public IEnumerable AutoFillImageProperties { get; set; } = DefaultImagingAutoFillUploadField; - - private class ImagingAutoFillUploadField : IImagingAutoFillUploadField - { - public string Alias { get; set; } - - public string WidthFieldAlias { get; set; } - - public string HeightFieldAlias { get; set; } - - public string LengthFieldAlias { get; set; } - - public string ExtensionFieldAlias { get; set; } - } + public ImagingAutoFillUploadField[] AutoFillImageProperties { get; set; } = DefaultImagingAutoFillUploadField; } } diff --git a/src/Umbraco.Core/Configuration/Models/ImagingAutoFillUploadField.cs b/src/Umbraco.Core/Configuration/Models/ImagingAutoFillUploadField.cs new file mode 100644 index 0000000000..f58e2bb4f8 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ImagingAutoFillUploadField.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Core.Configuration.Models +{ + public class ImagingAutoFillUploadField : ValidatableEntryBase + { + [Required] + public string Alias { get; set; } + + [Required] + public string WidthFieldAlias { get; set; } + + [Required] + public string HeightFieldAlias { get; set; } + + [Required] + public string LengthFieldAlias { get; set; } + + [Required] + public string ExtensionFieldAlias { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/Validation/ConfigurationValidationBase.cs b/src/Umbraco.Core/Configuration/Models/Validation/ConfigurationValidationBase.cs index d311b5157c..1af1945665 100644 --- a/src/Umbraco.Core/Configuration/Models/Validation/ConfigurationValidationBase.cs +++ b/src/Umbraco.Core/Configuration/Models/Validation/ConfigurationValidationBase.cs @@ -23,5 +23,17 @@ namespace Umbraco.Core.Configuration.Models.Validation var validValues = Enum.GetValues(enumType).OfType().Select(x => x.ToString().ToFirstLowerInvariant()); return ValidateStringIsOneOfValidValues(configPath, value, validValues, out message); } + + public bool ValidateCollection(string configPath, IEnumerable values, string validationDescription, out string message) + { + if (values.Any(x => !x.IsValid())) + { + message = $"Configuration entry {configPath} contains one or more invalid values. {validationDescription}."; + return false; + } + + message = string.Empty; + return true; + } } } diff --git a/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidation.cs b/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidation.cs index 8693cfd218..527dcc4737 100644 --- a/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidation.cs +++ b/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidation.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Options; using Umbraco.Core.Macros; @@ -20,6 +21,11 @@ namespace Umbraco.Core.Configuration.Models.Validation return ValidateOptionsResult.Fail(message); } + if (!ValidateAutoFillImageProperties(options.Imaging.AutoFillImageProperties, out message)) + { + return ValidateOptionsResult.Fail(message); + } + return ValidateOptionsResult.Success; } @@ -30,14 +36,12 @@ namespace Umbraco.Core.Configuration.Models.Validation private bool ValidateError404Collection(IEnumerable values, out string message) { - if (values.Any(x => !x.IsValid())) - { - message = $"Configuration entry Content:Error404Collection contains one or more invalid values. Culture and one and only one of ContentId, ContentKey and ContentXPath must be specified for each entry."; - return false; - } + return ValidateCollection("Content:Error404Collection", values, "Culture and one and only one of ContentId, ContentKey and ContentXPath must be specified for each entry", out message); + } - message = string.Empty; - return true; + private bool ValidateAutoFillImageProperties(IEnumerable values, out string message) + { + return ValidateCollection("Content:Imaging:AutoFillImageProperties", values, "Alias, WidthFieldAlias, HeightFieldAlias, LengthFieldAlias and ExtensionFieldAlias must be specified for each entry", out message); } } } diff --git a/src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs b/src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs new file mode 100644 index 0000000000..32e3c3270b --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Umbraco.Core.Configuration.Models.Validation +{ + public abstract class ValidatableEntryBase + { + internal virtual bool IsValid() + { + var ctx = new ValidationContext(this); + var results = new List(); + return Validator.TryValidateObject(this, ctx, results, true); + } + } +} diff --git a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs index 762e418441..be46c6ef20 100644 --- a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -38,7 +37,7 @@ namespace Umbraco.Web.Media /// The auto-fill configuration. /// Variation language. /// Variation segment. - public void Reset(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string culture, string segment) + public void Reset(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -55,7 +54,7 @@ namespace Umbraco.Web.Media /// The parameter is the path relative to the filesystem. /// Variation language. /// Variation segment. - public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, string culture, string segment) + public void Populate(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -94,7 +93,7 @@ namespace Umbraco.Web.Media /// The stream containing the file data. /// Variation language. /// Variation segment. - public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, string culture, string segment) + public void Populate(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -112,7 +111,7 @@ namespace Umbraco.Web.Media } } - private static void SetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment) + private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -130,7 +129,7 @@ namespace Umbraco.Web.Media content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(extension, culture, segment); } - private static void ResetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string culture, string segment) + private static void ResetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));