From e325c275ec50c93dbfae88309f71e34da18ecde2 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Fri, 4 Apr 2025 16:23:50 +0200 Subject: [PATCH] Amend accessibility modifiers on file upload property editor components to support extension. --- .../FileUploadPropertyEditor.cs | 4 +- .../FileUploadPropertyValueEditor.cs | 53 +++++++++++++------ .../TemporaryFileUploadValidator.cs | 23 +++++--- 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index 1d1b5a633f1f..a529abe7ed51 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -124,8 +124,8 @@ protected override IDataValueEditor CreateValueEditor() /// /// true if the specified property is an upload field; otherwise, false. /// - private static bool IsUploadField(IProperty property) => property.PropertyType.PropertyEditorAlias == - Constants.PropertyEditors.Aliases.UploadField; + protected virtual bool IsUploadField(IProperty property) => + property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.UploadField; /// /// The paths to all file upload property files contained within a collection of content entities diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index 1150fa09a23a..b3ef2c0095c7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -20,15 +20,15 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// The value editor for the file upload property editor. /// -internal class FileUploadPropertyValueEditor : DataValueEditor +public class FileUploadPropertyValueEditor : DataValueEditor { - private readonly MediaFileManager _mediaFileManager; private readonly IJsonSerializer _jsonSerializer; private readonly ITemporaryFileService _temporaryFileService; private readonly IScopeProvider _scopeProvider; - private readonly IFileStreamSecurityValidator _fileStreamSecurityValidator; - private ContentSettings _contentSettings; + /// + /// Initializes a new instance of the class. + /// public FileUploadPropertyValueEditor( DataEditorAttribute attribute, MediaFileManager mediaFileManager, @@ -41,21 +41,39 @@ public FileUploadPropertyValueEditor( IFileStreamSecurityValidator fileStreamSecurityValidator) : base(shortStringHelper, jsonSerializer, ioHelper, attribute) { - _mediaFileManager = mediaFileManager ?? throw new ArgumentNullException(nameof(mediaFileManager)); _jsonSerializer = jsonSerializer; _temporaryFileService = temporaryFileService; _scopeProvider = scopeProvider; - _fileStreamSecurityValidator = fileStreamSecurityValidator; - _contentSettings = contentSettings.CurrentValue ?? throw new ArgumentNullException(nameof(contentSettings)); - contentSettings.OnChange(x => _contentSettings = x); + + MediaFileManager = mediaFileManager; + FileStreamSecurityValidator = fileStreamSecurityValidator; + + ContentSettings = contentSettings.CurrentValue; + contentSettings.OnChange(x => ContentSettings = x); Validators.Add(new TemporaryFileUploadValidator( - () => _contentSettings, + () => ContentSettings, TryParseTemporaryFileKey, TryGetTemporaryFile, IsAllowedInDataTypeConfiguration)); } + /// + /// Gets the . + /// + protected MediaFileManager MediaFileManager { get; } + + /// + /// Gets the . + /// + protected IFileStreamSecurityValidator FileStreamSecurityValidator { get; } + + /// + /// Gets the . + /// + protected ContentSettings ContentSettings { get; private set; } + + /// public override object? ToEditor(IProperty property, string? culture = null, string? segment = null) { // the stored property value (if any) is the path to the file; convert it to the client model (FileUploadValue) @@ -68,6 +86,7 @@ public FileUploadPropertyValueEditor( : null; } + /// /// /// Converts the client model (FileUploadValue) into the value can be stored in the database (the file path). /// @@ -94,14 +113,14 @@ public FileUploadPropertyValueEditor( // the current editor value (if any) is the path to the file var currentPath = currentValue is string currentStringValue && currentStringValue.IsNullOrWhiteSpace() is false - ? _mediaFileManager.FileSystem.GetRelativePath(currentStringValue) + ? MediaFileManager.FileSystem.GetRelativePath(currentStringValue) : null; // resetting the current value? if (string.IsNullOrEmpty(editorModelValue?.Src) && currentPath.IsNullOrWhiteSpace() is false) { // delete the current file and clear the value of this property - _mediaFileManager.FileSystem.DeleteFile(currentPath); + MediaFileManager.FileSystem.DeleteFile(currentPath); return null; } @@ -138,12 +157,12 @@ public FileUploadPropertyValueEditor( // remove current file if replaced if (currentPath != filepath && currentPath.IsNullOrWhiteSpace() is false) { - _mediaFileManager.FileSystem.DeleteFile(currentPath); + MediaFileManager.FileSystem.DeleteFile(currentPath); } scope.Complete(); - return filepath is null ? null : _mediaFileManager.FileSystem.GetUrl(filepath); + return filepath is null ? null : MediaFileManager.FileSystem.GetUrl(filepath); } private FileUploadValue? ParseFileUploadValue(object? editorValue) @@ -192,7 +211,7 @@ private bool IsAllowedInDataTypeConfiguration(string extension, object? dataType // this check is somewhat redundant as the file validity has already been checked by TemporaryFileUploadValidator, // but we'll retain it here as a last measure in case someone accidentally breaks the validator var extension = Path.GetExtension(file.FileName).TrimStart('.'); - if (_contentSettings.IsFileAllowedForUpload(extension) is false || + if (ContentSettings.IsFileAllowedForUpload(extension) is false || IsAllowedInDataTypeConfiguration(extension, dataTypeConfiguration) is false) { return null; @@ -200,18 +219,18 @@ private bool IsAllowedInDataTypeConfiguration(string extension, object? dataType // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) - var filepath = _mediaFileManager.GetMediaPath(file.FileName, contentKey, propertyTypeKey); // fs-relative path + var filepath = MediaFileManager.GetMediaPath(file.FileName, contentKey, propertyTypeKey); // fs-relative path using (Stream filestream = file.OpenReadStream()) { - if (_fileStreamSecurityValidator.IsConsideredSafe(filestream) == false) + if (FileStreamSecurityValidator.IsConsideredSafe(filestream) == false) { return null; } // TODO: Here it would make sense to do the auto-fill properties stuff but the API doesn't allow us to do that right // since we'd need to be able to return values for other properties from these methods - _mediaFileManager.FileSystem.AddFile(filepath, filestream, true); // must overwrite! + MediaFileManager.FileSystem.AddFile(filepath, filestream, true); // must overwrite! } return filepath; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TemporaryFileUploadValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/TemporaryFileUploadValidator.cs index 71aba644cd95..6601a41d245a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TemporaryFileUploadValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TemporaryFileUploadValidator.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models.TemporaryFile; using Umbraco.Cms.Core.Models.Validation; @@ -6,21 +6,27 @@ namespace Umbraco.Cms.Core.PropertyEditors; -internal class TemporaryFileUploadValidator : IValueValidator +/// +/// Validates a temporary file upload. +/// +public class TemporaryFileUploadValidator : IValueValidator { private readonly GetContentSettings _getContentSettings; private readonly ParseTemporaryFileKey _parseTemporaryFileKey; private readonly GetTemporaryFileModel _getTemporaryFileModel; private readonly ValidateFileType? _validateFileType; - internal delegate ContentSettings GetContentSettings(); + public delegate ContentSettings GetContentSettings(); - internal delegate Guid? ParseTemporaryFileKey(object? editorValue); + public delegate Guid? ParseTemporaryFileKey(object? editorValue); - internal delegate TemporaryFileModel? GetTemporaryFileModel(Guid temporaryFileKey); + public delegate TemporaryFileModel? GetTemporaryFileModel(Guid temporaryFileKey); - internal delegate bool ValidateFileType(string extension, object? dataTypeConfiguration); + public delegate bool ValidateFileType(string extension, object? dataTypeConfiguration); + /// + /// Initializes a new instance of the class. + /// public TemporaryFileUploadValidator( GetContentSettings getContentSettings, ParseTemporaryFileKey parseTemporaryFileKey, @@ -33,6 +39,7 @@ public TemporaryFileUploadValidator( _validateFileType = validateFileType; } + /// public IEnumerable Validate(object? value, string? valueType, object? dataTypeConfiguration, PropertyValidationContext validationContext) { Guid? temporaryFileKey = _parseTemporaryFileKey(value); @@ -46,7 +53,7 @@ public IEnumerable Validate(object? value, string? valueType, { yield return new ValidationResult( $"No temporary file was found for the key: {temporaryFileKey.Value}", - new[] { "value" }); + ["value"]); } else { @@ -61,7 +68,7 @@ public IEnumerable Validate(object? value, string? valueType, { yield return new ValidationResult( $"The file type for file name \"{temporaryFile.FileName}\" is not valid for upload", - new[] { "value" }); + ["value"]); } } }