diff --git a/src/Umbraco.Core/IO/MediaFileSystem.cs b/src/Umbraco.Core/IO/MediaFileSystem.cs index b5955f825d..6e1d554c1f 100644 --- a/src/Umbraco.Core/IO/MediaFileSystem.cs +++ b/src/Umbraco.Core/IO/MediaFileSystem.cs @@ -341,36 +341,35 @@ namespace Umbraco.Core.IO // fixme - what's below belongs to the upload property editor, not the media filesystem! - public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filename, Stream filestream) + public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filename, Stream filestream, int? languageId = null, string segment = null) { var property = GetProperty(content, propertyTypeAlias); - var svalue = property.GetValue() as string; - var oldpath = svalue == null ? null : GetRelativePath(svalue); + var oldpath = property.GetValue(languageId, segment) is string svalue ? GetRelativePath(svalue) : null; var filepath = StoreFile(content, property.PropertyType, filename, filestream, oldpath); - property.SetValue(GetUrl(filepath)); - SetUploadFile(content, property, filepath, filestream); + property.SetValue(GetUrl(filepath), languageId, segment); + SetUploadFile(content, property, filepath, filestream, languageId, segment); } - public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filepath) + public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filepath, int? languageId = null, string segment = null) { var property = GetProperty(content, propertyTypeAlias); - var svalue = property.GetValue() as string; - var oldpath = svalue == null ? null : GetRelativePath(svalue); // FIXME DELETE? + // fixme delete? + var oldpath = property.GetValue(languageId, segment) is string svalue ? GetRelativePath(svalue) : null; if (string.IsNullOrWhiteSpace(oldpath) == false && oldpath != filepath) DeleteFile(oldpath); - property.SetValue(GetUrl(filepath)); + property.SetValue(GetUrl(filepath), languageId, segment); using (var filestream = OpenFile(filepath)) { - SetUploadFile(content, property, filepath, filestream); + SetUploadFile(content, property, filepath, filestream, languageId, segment); } } // sets a file for the FileUpload property editor // ie generates thumbnails and populates autofill properties - private void SetUploadFile(IContentBase content, Property property, string filepath, Stream filestream) + private void SetUploadFile(IContentBase content, Property property, string filepath, Stream filestream, int? languageId = null, string segment = null) { // will use filepath for extension, and filestream for length - UploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream); + UploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream, languageId, segment); } #endregion diff --git a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs index 2639024cb0..3fdaf7b3d3 100644 --- a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs @@ -41,7 +41,9 @@ namespace Umbraco.Core.Media /// /// The content item. /// The property type alias. - public void Reset(IContentBase content, string propertyTypeAlias) + /// Variation language. + /// Variation segment. + public void Reset(IContentBase content, string propertyTypeAlias, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (propertyTypeAlias == null) throw new ArgumentNullException(nameof(propertyTypeAlias)); @@ -51,7 +53,7 @@ namespace Umbraco.Core.Media if (autoFillConfig == null) return; // nothing // reset - Reset(content, autoFillConfig); + Reset(content, autoFillConfig, languageId, segment); } /// @@ -59,12 +61,14 @@ namespace Umbraco.Core.Media /// /// The content item. /// The auto-fill configuration. - public void Reset(IContentBase content, IImagingAutoFillUploadField autoFillConfig) + /// Variation language. + /// Variation segment. + public void Reset(IContentBase content, IImagingAutoFillUploadField autoFillConfig, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); - ResetProperties(content, autoFillConfig); + ResetProperties(content, autoFillConfig, languageId, segment); } /// @@ -73,7 +77,9 @@ namespace Umbraco.Core.Media /// The content item. /// The property type alias. /// The filesystem-relative filepath, or null to clear properties. - public void Populate(IContentBase content, string propertyTypeAlias, string filepath) + /// Variation language. + /// Variation segment. + public void Populate(IContentBase content, string propertyTypeAlias, string filepath, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (propertyTypeAlias == null) throw new ArgumentNullException(nameof(propertyTypeAlias)); @@ -86,7 +92,7 @@ namespace Umbraco.Core.Media if (autoFillConfig == null) return; // nothing // populate - Populate(content, autoFillConfig, filepath); + Populate(content, autoFillConfig, filepath, languageId, segment); } /// @@ -96,7 +102,9 @@ namespace Umbraco.Core.Media /// The property type alias. /// The filesystem-relative filepath, or null to clear properties. /// The stream containing the file data. - public void Populate(IContentBase content, string propertyTypeAlias, string filepath, Stream filestream) + /// Variation language. + /// Variation segment. + public void Populate(IContentBase content, string propertyTypeAlias, string filepath, Stream filestream, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (propertyTypeAlias == null) throw new ArgumentNullException(nameof(propertyTypeAlias)); @@ -109,7 +117,7 @@ namespace Umbraco.Core.Media if (autoFillConfig == null) return; // nothing // populate - Populate(content, autoFillConfig, filepath, filestream); + Populate(content, autoFillConfig, filepath, filestream, languageId, segment); } /// @@ -119,7 +127,9 @@ namespace Umbraco.Core.Media /// The auto-fill configuration. /// The filesystem path to the uploaded file. /// The parameter is the path relative to the filesystem. - public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath) + /// Variation language. + /// Variation segment. + public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -127,7 +137,7 @@ namespace Umbraco.Core.Media // no file = reset, file = auto-fill if (filepath.IsNullOrWhiteSpace()) { - ResetProperties(content, autoFillConfig); + ResetProperties(content, autoFillConfig, languageId, segment); } else { @@ -138,13 +148,13 @@ namespace Umbraco.Core.Media { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); var size = _mediaFileSystem.IsImageFile(extension) ? (Size?) _mediaFileSystem.GetDimensions(filestream) : null; - SetProperties(content, autoFillConfig, size, filestream.Length, extension); + SetProperties(content, autoFillConfig, size, filestream.Length, extension, languageId, segment); } } catch (Exception ex) { _logger.Error(typeof(UploadAutoFillProperties), $"Could not populate upload auto-fill properties for file \"{filepath}\".", ex); - ResetProperties(content, autoFillConfig); + ResetProperties(content, autoFillConfig, languageId, segment); } } } @@ -156,7 +166,9 @@ namespace Umbraco.Core.Media /// /// The filesystem-relative filepath, or null to clear properties. /// The stream containing the file data. - public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream) + /// Variation language. + /// Variation segment. + public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -164,50 +176,50 @@ namespace Umbraco.Core.Media // no file = reset, file = auto-fill if (filepath.IsNullOrWhiteSpace() || filestream == null) { - ResetProperties(content, autoFillConfig); + ResetProperties(content, autoFillConfig, languageId, segment); } else { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); var size = _mediaFileSystem.IsImageFile(extension) ? (Size?)_mediaFileSystem.GetDimensions(filestream) : null; - SetProperties(content, autoFillConfig, size, filestream.Length, extension); + SetProperties(content, autoFillConfig, size, filestream.Length, extension, languageId, segment); } } - private static void SetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension) + private static void SetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); if (content.Properties.Contains(autoFillConfig.WidthFieldAlias)) - content.Properties[autoFillConfig.WidthFieldAlias].SetValue(size.HasValue ? size.Value.Width.ToInvariantString() : string.Empty); + content.Properties[autoFillConfig.WidthFieldAlias].SetValue(size.HasValue ? size.Value.Width.ToInvariantString() : string.Empty, languageId, segment); if (content.Properties.Contains(autoFillConfig.HeightFieldAlias)) - content.Properties[autoFillConfig.HeightFieldAlias].SetValue(size.HasValue ? size.Value.Height.ToInvariantString() : string.Empty); + content.Properties[autoFillConfig.HeightFieldAlias].SetValue(size.HasValue ? size.Value.Height.ToInvariantString() : string.Empty, languageId, segment); if (content.Properties.Contains(autoFillConfig.LengthFieldAlias)) - content.Properties[autoFillConfig.LengthFieldAlias].SetValue(length); + content.Properties[autoFillConfig.LengthFieldAlias].SetValue(length, languageId, segment); if (content.Properties.Contains(autoFillConfig.ExtensionFieldAlias)) - content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(extension); + content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(extension, languageId, segment); } - private static void ResetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig) + private static void ResetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, int? languageId, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); if (content.Properties.Contains(autoFillConfig.WidthFieldAlias)) - content.Properties[autoFillConfig.WidthFieldAlias].SetValue(string.Empty); + content.Properties[autoFillConfig.WidthFieldAlias].SetValue(string.Empty, languageId, segment); if (content.Properties.Contains(autoFillConfig.HeightFieldAlias)) - content.Properties[autoFillConfig.HeightFieldAlias].SetValue(string.Empty); + content.Properties[autoFillConfig.HeightFieldAlias].SetValue(string.Empty, languageId, segment); if (content.Properties.Contains(autoFillConfig.LengthFieldAlias)) - content.Properties[autoFillConfig.LengthFieldAlias].SetValue(string.Empty); + content.Properties[autoFillConfig.LengthFieldAlias].SetValue(string.Empty, languageId, segment); if (content.Properties.Contains(autoFillConfig.ExtensionFieldAlias)) - content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(string.Empty); + content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(string.Empty, languageId, segment); } } } diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index 1d728ede8b..6adec3db5f 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -293,28 +293,24 @@ namespace Umbraco.Core.Models Properties.Add(property); } - // fixme - these three use an extension method that needs to be adapted too - // HttpPostedFileBase is the base class that can be mocked // HttpPostedFile is what we get in ASP.NET // HttpPostedFileWrapper wraps sealed HttpPostedFile as HttpPostedFileBase /// - /// Sets the posted file value of a Property + /// Sets the posted file value of a property. /// - public virtual void SetValue(string propertyTypeAlias, HttpPostedFile value) + public virtual void SetValue(string propertyTypeAlias, HttpPostedFile value, int? languageId = null, string segment = null) { - ContentExtensions.SetValue(this, propertyTypeAlias, new HttpPostedFileWrapper(value)); + ContentExtensions.SetValue(this, propertyTypeAlias, new HttpPostedFileWrapper(value), languageId, segment); } /// - /// Sets the posted file base value of a Property + /// Sets the posted file value of a property. /// - /// Alias of the PropertyType - /// Value to set for the Property - public virtual void SetValue(string propertyTypeAlias, HttpPostedFileBase value) + public virtual void SetValue(string propertyTypeAlias, HttpPostedFileBase value, int? languageId = null, string segment = null) { - ContentExtensions.SetValue(this, propertyTypeAlias, value); + ContentExtensions.SetValue(this, propertyTypeAlias, value, languageId, segment); } #endregion diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index 21d6b9b80f..e34d7026da 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -267,12 +267,9 @@ namespace Umbraco.Core.Models #region SetValue for setting file contents /// - /// Stores and sets an uploaded HttpPostedFileBase as a property value. + /// Sets the posted file value of a property. /// - /// A content item. - /// The property alias. - /// The uploaded . - public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value) + public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value, int? languageId = null, string segment = null) { // ensure we get the filename without the path in IE in intranet mode // http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie @@ -291,20 +288,16 @@ namespace Umbraco.Core.Models if (string.IsNullOrWhiteSpace(filename)) return; filename = filename.ToLower(); // fixme - er... why? - MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, value.InputStream); + MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, value.InputStream, languageId, segment); } /// - /// Stores and sets a file as a property value. + /// Sets the posted file value of a property. /// - /// A content item. - /// The property alias. - /// The name of the file. - /// A stream containing the file data. /// This really is for FileUpload fields only, and should be obsoleted. For anything else, /// you need to store the file by yourself using Store and then figure out /// how to deal with auto-fill properties (if any) and thumbnails (if any) by yourself. - public static void SetValue(this IContentBase content, string propertyTypeAlias, string filename, Stream filestream) + public static void SetValue(this IContentBase content, string propertyTypeAlias, string filename, Stream filestream, int? languageId = null, string segment = null) { if (filename == null || filestream == null) return; @@ -313,7 +306,7 @@ namespace Umbraco.Core.Models if (string.IsNullOrWhiteSpace(filename)) return; filename = filename.ToLower(); // fixme - er... why? - MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, filestream); + MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, filestream, languageId, segment); } /// diff --git a/src/Umbraco.Web/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/FileUploadPropertyEditor.cs index 8a36ee34b5..79824c96d7 100644 --- a/src/Umbraco.Web/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/FileUploadPropertyEditor.cs @@ -148,7 +148,6 @@ namespace Umbraco.Web.PropertyEditors /// /// Auto-fill properties (or clear). /// - /// The content. private void AutoFillProperties(IContentBase model) { var properties = model.Properties.Where(x => IsUploadField(x, false)); @@ -158,11 +157,14 @@ namespace Umbraco.Web.PropertyEditors var autoFillConfig = _mediaFileSystem.UploadAutoFillProperties.GetConfig(property.Alias); if (autoFillConfig == null) continue; - var svalue = property.GetValue() as string; - if (string.IsNullOrWhiteSpace(svalue)) - _mediaFileSystem.UploadAutoFillProperties.Reset(model, autoFillConfig); - else - _mediaFileSystem.UploadAutoFillProperties.Populate(model, autoFillConfig, _mediaFileSystem.GetRelativePath(svalue)); + foreach (var pvalue in property.Values) + { + var svalue = property.GetValue(pvalue.LanguageId, pvalue.Segment) as string; + if (string.IsNullOrWhiteSpace(svalue)) + _mediaFileSystem.UploadAutoFillProperties.Reset(model, autoFillConfig, pvalue.LanguageId, pvalue.Segment); + else + _mediaFileSystem.UploadAutoFillProperties.Populate(model, autoFillConfig, _mediaFileSystem.GetRelativePath(svalue), pvalue.LanguageId, pvalue.Segment); + } } } @@ -232,22 +234,20 @@ namespace Umbraco.Web.PropertyEditors { public IEnumerable Validate(object value, PreValueCollection preValues, PropertyEditor editor) { - var json = value as JArray; - if (json == null) yield break; + if (!(value is JArray json)) yield break; //validate each item which is a json object for (var index = 0; index < json.Count; index++) { var i = json[index]; var jItem = i as JObject; - if (jItem == null || jItem["value"] == null) continue; + if (jItem?["value"] == null) continue; //NOTE: we will be removing empty values when persisting so no need to validate var asString = jItem["value"].ToString(); if (asString.IsNullOrWhiteSpace()) continue; - int parsed; - if (int.TryParse(asString, out parsed) == false) + if (int.TryParse(asString, out _) == false) { yield return new ValidationResult("The value " + asString + " is not a valid number", new[] { diff --git a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs index ab1db28fe8..167e3d2a0b 100644 --- a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs @@ -18,7 +18,6 @@ namespace Umbraco.Web.PropertyEditors public class ImageCropperPropertyEditor : PropertyEditor { private readonly MediaFileSystem _mediaFileSystem; - private readonly IContentSection _contentSettings; private readonly IDataTypeService _dataTypeService; private readonly UploadAutoFillProperties _autoFillProperties; private IDictionary _internalPreValues; // preValues @@ -29,13 +28,9 @@ namespace Umbraco.Web.PropertyEditors public ImageCropperPropertyEditor(ILogger logger, MediaFileSystem mediaFileSystem, IContentSection contentSettings, IDataTypeService dataTypeService) : base(logger) { - if (mediaFileSystem == null) throw new ArgumentNullException(nameof(mediaFileSystem)); - if (contentSettings == null) throw new ArgumentNullException(nameof(contentSettings)); - if (dataTypeService == null) throw new ArgumentNullException(nameof(dataTypeService)); - - _mediaFileSystem = mediaFileSystem; - _contentSettings = contentSettings; - _dataTypeService = dataTypeService; + _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + var contentSettings1 = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); _internalPreValues = new Dictionary { @@ -43,13 +38,13 @@ namespace Umbraco.Web.PropertyEditors {"src", ""} }; - _autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, Logger, _contentSettings); + _autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, Logger, contentSettings1); } public override IDictionary DefaultPreValues { - get { return _internalPreValues; } - set { _internalPreValues = value; } + get => _internalPreValues; + set => _internalPreValues = value; } /// @@ -157,9 +152,8 @@ namespace Umbraco.Web.PropertyEditors foreach (var property in properties) { var jo = GetJObject((string) property.GetValue(), true); - if (jo == null || jo["src"] == null) continue; - var src = jo["src"].Value(); + var src = jo?["src"]?.Value(); if (string.IsNullOrWhiteSpace(src)) continue; var sourcePath = _mediaFileSystem.GetRelativePath(src); @@ -208,7 +202,6 @@ namespace Umbraco.Web.PropertyEditors /// /// Auto-fill properties (or clear). /// - /// The content. private void AutoFillProperties(IContentBase model) { var properties = model.Properties.Where(x => IsCropperField(x, false)); @@ -218,37 +211,40 @@ namespace Umbraco.Web.PropertyEditors var autoFillConfig = _autoFillProperties.GetConfig(property.Alias); if (autoFillConfig == null) continue; - var svalue = property.GetValue() as string; - if (string.IsNullOrWhiteSpace(svalue)) + foreach (var pvalue in property.Values) { - _autoFillProperties.Reset(model, autoFillConfig); - continue; - } + var svalue = property.GetValue(pvalue.LanguageId, pvalue.Segment) as string; + if (string.IsNullOrWhiteSpace(svalue)) + { + _autoFillProperties.Reset(model, autoFillConfig, pvalue.LanguageId, pvalue.Segment); + continue; + } - var jo = GetJObject(svalue, false); - string src; - if (jo == null) - { - // so we have a non-empty string value that cannot be parsed into a json object - // see http://issues.umbraco.org/issue/U4-4756 - // it can happen when an image is uploaded via the folder browser, in which case - // the property value will be the file source eg '/media/23454/hello.jpg' and we - // are fixing that anomaly here - does not make any sense at all but... bah... - var config = _dataTypeService - .GetPreValuesByDataTypeId(property.PropertyType.DataTypeDefinitionId).FirstOrDefault(); - var crops = string.IsNullOrWhiteSpace(config) ? "[]" : config; - src = svalue; - property.SetValue("{\"src\": \"" + svalue + "\", \"crops\": " + crops + "}"); - } - else - { - src = jo["src"]?.Value(); - } + var jo = GetJObject(svalue, false); + string src; + if (jo == null) + { + // so we have a non-empty string value that cannot be parsed into a json object + // see http://issues.umbraco.org/issue/U4-4756 + // it can happen when an image is uploaded via the folder browser, in which case + // the property value will be the file source eg '/media/23454/hello.jpg' and we + // are fixing that anomaly here - does not make any sense at all but... bah... + var config = _dataTypeService + .GetPreValuesByDataTypeId(property.PropertyType.DataTypeDefinitionId).FirstOrDefault(); + var crops = string.IsNullOrWhiteSpace(config) ? "[]" : config; + src = svalue; + property.SetValue("{\"src\": \"" + svalue + "\", \"crops\": " + crops + "}"); + } + else + { + src = jo["src"]?.Value(); + } - if (src == null) - _autoFillProperties.Reset(model, autoFillConfig); - else - _autoFillProperties.Populate(model, autoFillConfig, _mediaFileSystem.GetRelativePath(src)); + if (src == null) + _autoFillProperties.Reset(model, autoFillConfig, pvalue.LanguageId, pvalue.Segment); + else + _autoFillProperties.Populate(model, autoFillConfig, _mediaFileSystem.GetRelativePath(src), pvalue.LanguageId, pvalue.Segment); + } } }