diff --git a/src/Umbraco.Core/Extensions/ContentExtensions.cs b/src/Umbraco.Core/Extensions/ContentExtensions.cs index 8ea51fafca..8385de5e70 100644 --- a/src/Umbraco.Core/Extensions/ContentExtensions.cs +++ b/src/Umbraco.Core/Extensions/ContentExtensions.cs @@ -9,6 +9,8 @@ using System.Xml.Linq; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; @@ -17,6 +19,41 @@ namespace Umbraco.Extensions { public static class ContentExtensions { + /// + /// Returns the path to a media item stored in a property if the property editor is + /// + /// + /// + /// + /// + /// + /// + /// True if the file path can be resolved and the property is + public static bool TryGetMediaPath( + this IContentBase content, + string propertyTypeAlias, + MediaUrlGeneratorCollection mediaUrlGenerators, + out string mediaFilePath, + string culture = null, + string segment = null) + { + if (!content.Properties.TryGetValue(propertyTypeAlias, out IProperty property)) + { + mediaFilePath = null; + return false; + } + + if (!mediaUrlGenerators.TryGetMediaPath( + property.PropertyType.PropertyEditorAlias, + property.GetValue(culture, segment), + out mediaFilePath)) + { + return false; + } + + return true; + } + public static bool IsAnyUserPropertyDirty(this IContentBase entity) { return entity.Properties.Any(x => x.IsDirty()); @@ -204,42 +241,56 @@ namespace Umbraco.Extensions /// /// Sets the posted file value of a property. /// - public static void SetValue(this IContentBase content, MediaFileManager mediaFileManager, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer serializer, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) + public static void SetValue( + this IContentBase content, + MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, + IShortStringHelper shortStringHelper, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + string propertyTypeAlias, + string filename, + Stream filestream, + string culture = null, + string segment = null) { - if (filename == null || filestream == null) return; + if (filename == null || filestream == null) + return; filename = shortStringHelper.CleanStringForSafeFileName(filename); - if (string.IsNullOrWhiteSpace(filename)) return; + if (string.IsNullOrWhiteSpace(filename)) + return; filename = filename.ToLower(); - SetUploadFile(content, mediaFileManager, contentTypeBaseServiceProvider, serializer, propertyTypeAlias, filename, filestream, culture, segment); + SetUploadFile(content, mediaFileManager, mediaUrlGenerators, contentTypeBaseServiceProvider, propertyTypeAlias, filename, filestream, culture, segment); } - private static void SetUploadFile(this IContentBase content, MediaFileManager mediaFileManager, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer serializer, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) + private static void SetUploadFile( + this IContentBase content, + MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + string propertyTypeAlias, + string filename, + Stream filestream, + string culture = null, + string segment = null) { var property = GetProperty(content, contentTypeBaseServiceProvider, propertyTypeAlias); // Fixes https://github.com/umbraco/Umbraco-CMS/issues/3937 - Assigning a new file to an // existing IMedia with extension SetValue causes exception 'Illegal characters in path' string oldpath = null; - if (property.GetValue(culture, segment) is string svalue) - { - // TODO: This is still horrible! We are not delagating to the actual property editors on how to handle this - // which we know how to do. - if (svalue.DetectIsJson()) - { - // the property value is a JSON serialized image crop data set - grab the "src" property as the file source - svalue = serializer.DeserializeSubset(svalue, "src"); - } - oldpath = mediaFileManager.FileSystem.GetRelativePath(svalue); + if (content.TryGetMediaPath(property.Alias, mediaUrlGenerators, out string mediaFilePath, culture, segment)) + { + oldpath = mediaFileManager.FileSystem.GetRelativePath(mediaFilePath); } var filepath = mediaFileManager.StoreFile(content, property.PropertyType, filename, filestream, oldpath); - // TODO: And here we are just setting the value to a string which means that any file based editor - // will need to handle the raw string value and progressively save it to it's correct (i.e. JSON) - // format. + // NOTE: Here we are just setting the value to a string which means that any file based editor + // will need to handle the raw string value and save it to it's correct (i.e. JSON) + // format. I'm unsure how this works today with image cropper but it does (maybe events?) property.SetValue(mediaFileManager.FileSystem.GetUrl(filepath), culture, segment); } @@ -247,7 +298,8 @@ namespace Umbraco.Extensions private static IProperty GetProperty(IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias) { var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); - if (property != null) return property; + if (property != null) + return property; var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); var propertyType = contentType.CompositionPropertyTypes @@ -281,7 +333,8 @@ namespace Umbraco.Extensions var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); var propertyType = contentType .CompositionPropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); - if (propertyType == null) throw new ArgumentException("Invalid property type alias " + propertyTypeAlias + "."); + if (propertyType == null) + throw new ArgumentException("Invalid property type alias " + propertyTypeAlias + "."); return mediaFileManager.StoreFile(content, propertyType, filename, filestream, filepath); } diff --git a/src/Umbraco.Core/IO/IMediaPathScheme.cs b/src/Umbraco.Core/IO/IMediaPathScheme.cs index 2b2696ec5d..5daf5490a8 100644 --- a/src/Umbraco.Core/IO/IMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/IMediaPathScheme.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Umbraco.Cms.Core.IO { @@ -14,9 +14,9 @@ namespace Umbraco.Cms.Core.IO /// The (content, media) item unique identifier. /// The property type unique identifier. /// The file name. - /// A previous filename. + /// /// The filesystem-relative complete file path. - string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null); + string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename); /// /// Gets the directory that can be deleted when the file is deleted. diff --git a/src/Umbraco.Core/IO/MediaFileManager.cs b/src/Umbraco.Core/IO/MediaFileManager.cs index 679eed9239..96680d3f84 100644 --- a/src/Umbraco.Core/IO/MediaFileManager.cs +++ b/src/Umbraco.Core/IO/MediaFileManager.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Strings; using Umbraco.Extensions; @@ -107,52 +108,40 @@ namespace Umbraco.Cms.Core.IO return _mediaPathScheme.GetFilePath(this, cuid, puid, filename); } - /// - /// Gets the file path of a media file. - /// - /// The file name. - /// A previous file path. - /// The unique identifier of the content/media owning the file. - /// The unique identifier of the property type owning the file. - /// The filesystem-relative path to the media file. - /// In the old, legacy, number-based scheme, we try to re-use the media folder - /// specified by . Else, we CREATE a new one. Each time we are invoked. - public string GetMediaPath(string filename, string prevpath, Guid cuid, Guid puid) - { - filename = Path.GetFileName(filename); - if (filename == null) - { - throw new ArgumentException("Cannot become a safe filename.", nameof(filename)); - } - - filename = _shortStringHelper.CleanStringForSafeFileName(filename.ToLowerInvariant()); - - return _mediaPathScheme.GetFilePath(this, cuid, puid, filename, prevpath); - } - #endregion #region Associated Media Files - public Stream GetFile(IMedia media, out string mediaFilePath) + /// + /// Returns a stream (file) for a content item or null if there is no file. + /// + /// + /// The file path if a file was found + /// + /// + /// + public Stream GetFile( + IContentBase content, + out string mediaFilePath, + string propertyTypeAlias = Constants.Conventions.Media.File, + string culture = null, + string segment = null) { // TODO: If collections were lazy we could just inject them if (_mediaUrlGenerators == null) { _mediaUrlGenerators = _serviceProvider.GetRequiredService(); - } + } - // This is how we get all URLs based on the defined aliases, - // then we just try each to get a file until one works. - var urls = media.GetUrls(_contentSettings, _mediaUrlGenerators); - foreach(var url in urls) + if (!content.TryGetMediaPath(propertyTypeAlias, _mediaUrlGenerators, out mediaFilePath, culture, segment)) { - Stream stream = FileSystem.OpenFile(url); - if (stream != null) - { - mediaFilePath = url; - return stream; - } + return null; + } + + Stream stream = FileSystem.OpenFile(mediaFilePath); + if (stream != null) + { + return stream; } mediaFilePath = null; @@ -207,8 +196,7 @@ namespace Umbraco.Cms.Core.IO } // get the filepath, store the data - // use oldpath as "prevpath" to try and reuse the folder, in original number-based scheme - var filepath = GetMediaPath(filename, oldpath, content.Key, propertyType.Key); + var filepath = GetMediaPath(filename, content.Key, propertyType.Key); FileSystem.AddFile(filepath, filestream); return filepath; } diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs index f3c15a13d6..b4127e080d 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace Umbraco.Cms.Core.IO.MediaPathSchemes @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes public class CombinedGuidsMediaPathScheme : IMediaPathScheme { /// - public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename) { // assumes that cuid and puid keys can be trusted - and that a single property type // for a single content cannot store two different files with the same name diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs deleted file mode 100644 index d1cea0c46b..0000000000 --- a/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Threading; - -namespace Umbraco.Cms.Core.IO.MediaPathSchemes -{ - /// - /// Implements the original media path scheme. - /// - /// - /// Path is "{number}/{filename}" or "{number}-{filename}" where number is an incremented counter. - /// Use '/' or '-' depending on UploadAllowDirectories setting. - /// - // scheme: path is "/" where number is an incremented counter - public class OriginalMediaPathScheme : IMediaPathScheme - { - private readonly object _folderCounterLock = new object(); - private long _folderCounter; - private bool _folderCounterInitialized; - - /// - public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) - { - string directory; - if (previous != null) - { - // old scheme, with a previous path - // prevpath should be "/" OR "-" - // and we want to reuse the "" part, so try to find it - - const string sep = "/"; - var pos = previous.IndexOf(sep, StringComparison.Ordinal); - var s = pos > 0 ? previous.Substring(0, pos) : null; - - directory = pos > 0 && int.TryParse(s, out _) ? s : GetNextDirectory(fileManager.FileSystem); - } - else - { - directory = GetNextDirectory(fileManager.FileSystem); - } - - if (directory == null) - throw new InvalidOperationException("Cannot use a null directory."); - - return Path.Combine(directory, filename).Replace('\\', '/'); - } - - /// - public string GetDeleteDirectory(MediaFileManager fileSystem, string filepath) - { - return Path.GetDirectoryName(filepath); - } - - private string GetNextDirectory(IFileSystem fileSystem) - { - EnsureFolderCounterIsInitialized(fileSystem); - return Interlocked.Increment(ref _folderCounter).ToString(CultureInfo.InvariantCulture); - } - - private void EnsureFolderCounterIsInitialized(IFileSystem fileSystem) - { - lock (_folderCounterLock) - { - if (_folderCounterInitialized) return; - - _folderCounter = 1000; // seed - var directories = fileSystem.GetDirectories(""); - foreach (var directory in directories) - { - if (long.TryParse(directory, out var folderNumber) && folderNumber > _folderCounter) - _folderCounter = folderNumber; - } - - // note: not multi-domains ie LB safe as another domain could create directories - // while we read and parse them - don't fix, move to new scheme eventually - - _folderCounterInitialized = true; - } - } - } -} diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs index 203c8aaed8..ebce899697 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace Umbraco.Cms.Core.IO.MediaPathSchemes @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes public class TwoGuidsMediaPathScheme : IMediaPathScheme { /// - public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename) { return Path.Combine(itemGuid.ToString("N"), propertyGuid.ToString("N"), filename).Replace('\\', '/'); } diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs index 55a9cd4574..c247c37032 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; namespace Umbraco.Cms.Core.IO.MediaPathSchemes @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes private const int DirectoryLength = 8; /// - public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename) { var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid); var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength); diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs index e517f0be63..8c35e80988 100644 --- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs +++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -146,17 +146,21 @@ namespace Umbraco.Cms.Core.IO var fullPath = GetFullPath(path); var exists = File.Exists(fullPath); if (exists && overrideExisting == false) + { throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path)); + } var directory = Path.GetDirectoryName(fullPath); if (directory == null) throw new InvalidOperationException("Could not get directory."); Directory.CreateDirectory(directory); // ensure it exists - if (stream.CanSeek) // TODO: what if we cannot? + if (stream.CanSeek) + { stream.Seek(0, 0); + } - using (var destination = (Stream) File.Create(fullPath)) - stream.CopyTo(destination); + using var destination = (Stream)File.Create(fullPath); + stream.CopyTo(destination); } /// diff --git a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs index 32c8ddd98d..10a372ce9f 100644 --- a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Configuration.Models; @@ -66,20 +66,24 @@ namespace Umbraco.Cms.Core.Media } else { - // if anything goes wrong, just reset the properties - try + // it might not exist if the media item has been created programatically but doesn't have a file persisted yet. + if (_mediaFileManager.FileSystem.FileExists(filepath)) { - using (var filestream = _mediaFileManager.FileSystem.OpenFile(filepath)) + // if anything goes wrong, just reset the properties + try { - var extension = (Path.GetExtension(filepath) ?? "").TrimStart(Constants.CharArrays.Period); - var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null; - SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); + using (var filestream = _mediaFileManager.FileSystem.OpenFile(filepath)) + { + var extension = (Path.GetExtension(filepath) ?? "").TrimStart(Constants.CharArrays.Period); + var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null; + SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Could not populate upload auto-fill properties for file '{File}'.", filepath); + ResetProperties(content, autoFillConfig, culture, segment); } - } - catch (Exception ex) - { - _logger.LogError(ex, "Could not populate upload auto-fill properties for file '{File}'.", filepath); - ResetProperties(content, autoFillConfig, culture, segment); } } } diff --git a/src/Umbraco.Core/Models/ContentBaseExtensions.cs b/src/Umbraco.Core/Models/ContentBaseExtensions.cs index 45fe9e41d9..9aae08c74b 100644 --- a/src/Umbraco.Core/Models/ContentBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentBaseExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Umbraco.Cms.Core.Models; @@ -25,8 +25,19 @@ namespace Umbraco.Extensions if (urlSegmentProviders == null) throw new ArgumentNullException(nameof(urlSegmentProviders)); var url = urlSegmentProviders.Select(p => p.GetUrlSegment(content, culture)).FirstOrDefault(u => u != null); - url ??= new DefaultUrlSegmentProvider(shortStringHelper).GetUrlSegment(content, culture); // be safe + if (url == null) + { + if (s_defaultUrlSegmentProvider == null) + { + s_defaultUrlSegmentProvider = new DefaultUrlSegmentProvider(shortStringHelper); + } + + url = s_defaultUrlSegmentProvider.GetUrlSegment(content, culture); // be safe + } + return url; } + + private static DefaultUrlSegmentProvider s_defaultUrlSegmentProvider; } } diff --git a/src/Umbraco.Core/Models/MediaExtensions.cs b/src/Umbraco.Core/Models/MediaExtensions.cs index 137997c271..616dbd1d12 100644 --- a/src/Umbraco.Core/Models/MediaExtensions.cs +++ b/src/Umbraco.Core/Models/MediaExtensions.cs @@ -12,16 +12,11 @@ namespace Umbraco.Extensions /// public static string GetUrl(this IMedia media, string propertyAlias, MediaUrlGeneratorCollection mediaUrlGenerators) { - if (!media.Properties.TryGetValue(propertyAlias, out var property)) - return string.Empty; - - // TODO: would need to be adjusted to variations, when media become variants - if (mediaUrlGenerators.TryGetMediaPath(property.PropertyType.PropertyEditorAlias, property.GetValue(), out var mediaUrl)) + if (media.TryGetMediaPath(propertyAlias, mediaUrlGenerators, out var mediaPath)) { - return mediaUrl; + return mediaPath; } - // Without knowing what it is, just adding a string here might not be very nice return string.Empty; } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index ab86e338f0..ae19da3036 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -218,8 +218,8 @@ namespace Umbraco.Cms.Core.Packaging foreach (KeyValuePair mediaFile in mediaFiles) { - // must ensure the path is relative, doesn't start with / - ZipArchiveEntry mediaEntry = archive.CreateEntry(mediaFile.Key.TrimStart('/')); + var entryPath = $"media{mediaFile.Key.EnsureStartsWith('/')}"; + ZipArchiveEntry mediaEntry = archive.CreateEntry(entryPath); using (Stream entryStream = mediaEntry.Open()) using (mediaFile.Value) { diff --git a/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs index 58c1f73bf2..446290f83f 100644 --- a/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Examine; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PropertyEditors.ValueConverters; @@ -17,67 +20,40 @@ namespace Umbraco.Cms.Infrastructure.Examine public class MediaValueSetBuilder : BaseValueSetBuilder { private readonly UrlSegmentProviderCollection _urlSegmentProviders; + private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IUserService _userService; - private readonly ILogger _logger; private readonly IShortStringHelper _shortStringHelper; - private readonly IJsonSerializer _serializer; + private readonly ContentSettings _contentSettings; - public MediaValueSetBuilder(PropertyEditorCollection propertyEditors, + public MediaValueSetBuilder( + PropertyEditorCollection propertyEditors, UrlSegmentProviderCollection urlSegmentProviders, - IUserService userService, ILogger logger, IShortStringHelper shortStringHelper, IJsonSerializer serializer) + MediaUrlGeneratorCollection mediaUrlGenerators, + IUserService userService, + IShortStringHelper shortStringHelper, + IOptions contentSettings) : base(propertyEditors, false) { _urlSegmentProviders = urlSegmentProviders; + _mediaUrlGenerators = mediaUrlGenerators; _userService = userService; - _logger = logger; _shortStringHelper = shortStringHelper; - _serializer = serializer; + _contentSettings = contentSettings.Value; } /// public override IEnumerable GetValueSets(params IMedia[] media) { - foreach (var m in media) + foreach (IMedia m in media) { - var urlValue = m.GetUrlSegment(_shortStringHelper, _urlSegmentProviders); - var umbracoFilePath = string.Empty; var umbracoFile = string.Empty; - // TODO: To get the file path we should/could use the MediaUrlGeneratorCollection instead of this - // just like we are doing in the MediaFileManager? + var urlValue = m.GetUrlSegment(_shortStringHelper, _urlSegmentProviders); - var umbracoFileSource = m.GetValue(Constants.Conventions.Media.File); - - if (umbracoFileSource.DetectIsJson()) - { - ImageCropperValue cropper = null; - try - { - cropper = _serializer.Deserialize( - m.GetValue(Constants.Conventions.Media.File)); - } - catch (Exception ex) - { - _logger.LogError(ex, $"Could not Deserialize ImageCropperValue for item with key {m.Key} "); - } - - if (cropper != null) - { - umbracoFilePath = cropper.Src; - } - } - else - { - umbracoFilePath = umbracoFileSource; - } - - if (!string.IsNullOrEmpty(umbracoFilePath)) - { - // intentional dummy Uri - var uri = new Uri("https://localhost/" + umbracoFilePath); - umbracoFile = uri.Segments.Last(); - } + IEnumerable mediaFiles = m.GetUrls(_contentSettings, _mediaUrlGenerators) + .Select(x => Path.GetFileName(x)) + .Distinct(); var values = new Dictionary> { @@ -95,7 +71,7 @@ namespace Umbraco.Cms.Infrastructure.Examine {"path", m.Path?.Yield() ?? Enumerable.Empty()}, {"nodeType", m.ContentType.Id.ToString().Yield() }, {"creatorName", (m.GetCreatorProfile(_userService)?.Name ?? "??").Yield()}, - {UmbracoExamineFieldNames.UmbracoFileFieldName, umbracoFile.Yield()} + {UmbracoExamineFieldNames.UmbracoFileFieldName, mediaFiles} }; foreach (var property in m.Properties) diff --git a/src/Umbraco.Infrastructure/Packaging/AutomaticPackageMigrationPlan.cs b/src/Umbraco.Infrastructure/Packaging/AutomaticPackageMigrationPlan.cs index 8188545f6b..92e1086fbd 100644 --- a/src/Umbraco.Infrastructure/Packaging/AutomaticPackageMigrationPlan.cs +++ b/src/Umbraco.Infrastructure/Packaging/AutomaticPackageMigrationPlan.cs @@ -1,9 +1,7 @@ using System; -using System.IO.Compression; -using System.Xml.Linq; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Packaging; -using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Migrations; @@ -36,8 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging private class MigrateToPackageData : PackageMigrationBase { - public MigrateToPackageData(IPackagingService packagingService, MediaFileManager mediaFileManager, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer jsonSerializer, IMigrationContext context) - : base(packagingService, mediaFileManager, shortStringHelper, contentTypeBaseServiceProvider, jsonSerializer, context) + public MigrateToPackageData(IPackagingService packagingService, IMediaService mediaService, MediaFileManager mediaFileManager, MediaUrlGeneratorCollection mediaUrlGenerators, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMigrationContext context) : base(packagingService, mediaService, mediaFileManager, mediaUrlGenerators, shortStringHelper, contentTypeBaseServiceProvider, context) { } diff --git a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs index 0416cea8ae..c14d3e5119 100644 --- a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs +++ b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs @@ -1,6 +1,7 @@ using System; using System.Xml.Linq; using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; @@ -14,17 +15,19 @@ namespace Umbraco.Cms.Infrastructure.Packaging { public ImportPackageBuilder( IPackagingService packagingService, + IMediaService mediaService, MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, - IJsonSerializer jsonSerializer, IMigrationContext context) : base(new ImportPackageBuilderExpression( packagingService, + mediaService, mediaFileManager, + mediaUrlGenerators, shortStringHelper, contentTypeBaseServiceProvider, - jsonSerializer, context)) { } diff --git a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs index 4c57ff856a..b16326ea56 100644 --- a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs +++ b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs @@ -9,7 +9,7 @@ using Umbraco.Cms.Core; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Packaging; -using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Migrations; @@ -20,25 +20,28 @@ namespace Umbraco.Cms.Infrastructure.Packaging internal class ImportPackageBuilderExpression : MigrationExpressionBase { private readonly IPackagingService _packagingService; + private readonly IMediaService _mediaService; private readonly MediaFileManager _mediaFileManager; + private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IShortStringHelper _shortStringHelper; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; - private readonly IJsonSerializer _jsonSerializer; private bool _executed; public ImportPackageBuilderExpression( IPackagingService packagingService, + IMediaService mediaService, MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, - IJsonSerializer jsonSerializer, IMigrationContext context) : base(context) { _packagingService = packagingService; + _mediaService = mediaService; _mediaFileManager = mediaFileManager; + _mediaUrlGenerators = mediaUrlGenerators; _shortStringHelper = shortStringHelper; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; - _jsonSerializer = jsonSerializer; } /// @@ -78,21 +81,23 @@ namespace Umbraco.Cms.Infrastructure.Packaging var mediaWithFiles = xml.XPathSelectElements( "./umbPackage/MediaItems/MediaSet//*[@id][@mediaFilePath]") .ToDictionary( - x => x.AttributeValue("id"), + x => x.AttributeValue("key"), x => x.AttributeValue("mediaFilePath")); - // TODO: Almost works! Just wonder if the media installed list is empty because nothing changed? - - foreach(IMedia media in installationSummary.MediaInstalled) + // Any existing media by GUID will not be installed by the package service, it will just be skipped + // so you cannot 'update' media (or content) using a package since those are not schema type items. + // This means you cannot 'update' the media file either. The installationSummary.MediaInstalled + // will be empty for any existing media which means that the files will also not be updated. + foreach (IMedia media in installationSummary.MediaInstalled) { - if (mediaWithFiles.TryGetValue(media.Id, out var mediaFilePath)) + if (mediaWithFiles.TryGetValue(media.Key, out var mediaFilePath)) { - // this is a media item that has a file, so find that file in the zip - string entryName = mediaFilePath.TrimStart('/'); - ZipArchiveEntry mediaEntry = zipPackage.GetEntry(entryName); + // this is a media item that has a file, so find that file in the zip + var entryPath = $"media{mediaFilePath.EnsureStartsWith('/')}"; + ZipArchiveEntry mediaEntry = zipPackage.GetEntry(entryPath); if (mediaEntry == null) { - throw new InvalidOperationException("No media file found in package zip for path " + entryName); + throw new InvalidOperationException("No media file found in package zip for path " + entryPath); } // read the media file and save it to the media item @@ -101,13 +106,15 @@ namespace Umbraco.Cms.Infrastructure.Packaging { media.SetValue( _mediaFileManager, + _mediaUrlGenerators, _shortStringHelper, _contentTypeBaseServiceProvider, - _jsonSerializer, Constants.Conventions.Media.File, Path.GetFileName(mediaFilePath), mediaStream); } + + _mediaService.Save(media); } } } diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index e680471486..79cbf00de0 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -168,7 +168,9 @@ namespace Umbraco.Cms.Infrastructure.Packaging var contents = ParseContentBaseRootXml(roots, parentId, importedDocumentTypes, typeService, service).ToList(); if (contents.Any()) + { service.Save(contents, userId); + } return contents; @@ -189,29 +191,35 @@ namespace Umbraco.Cms.Infrastructure.Packaging // "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); } - private IEnumerable ParseContentBaseRootXml( + private IEnumerable ParseContentBaseRootXml( IEnumerable roots, int parentId, - IDictionary importedContentTypes, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition + IDictionary importedContentTypes, + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { - var contents = new List(); - foreach (var root in roots) + var contents = new List(); + foreach (XElement root in roots) { var contentTypeAlias = root.Name.LocalName; if (!importedContentTypes.ContainsKey(contentTypeAlias)) { - var contentType = FindContentTypeByAlias(contentTypeAlias, typeService); + TContentTypeComposition contentType = FindContentTypeByAlias(contentTypeAlias, typeService); + if (contentType == null) + { + throw new InvalidOperationException("Could not find content type with alias " + contentTypeAlias); + } importedContentTypes.Add(contentTypeAlias, contentType); } - var content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], default, parentId, service); + TContentBase content = CreateContentFromXml(root, importedContentTypes[contentTypeAlias], default, parentId, service); if (content == null) + { continue; + } contents.Add(content); @@ -280,7 +288,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging return null; } - var id = element.Attribute("id").Value; var level = element.Attribute("level").Value; var sortOrder = element.Attribute("sortOrder").Value; var nodeName = element.Attribute("nodeName").Value; diff --git a/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs b/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs index a2fa7040ea..3166cdbd4f 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageMigrationBase.cs @@ -1,10 +1,8 @@ using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Packaging; -using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Migrations; -using Umbraco.Cms.Infrastructure.Migrations.Expressions.Execute; namespace Umbraco.Cms.Infrastructure.Packaging { @@ -12,34 +10,38 @@ namespace Umbraco.Cms.Infrastructure.Packaging public abstract class PackageMigrationBase : MigrationBase { private readonly IPackagingService _packagingService; + private readonly IMediaService _mediaService; private readonly MediaFileManager _mediaFileManager; + private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IShortStringHelper _shortStringHelper; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; - private readonly IJsonSerializer _jsonSerializer; public PackageMigrationBase( IPackagingService packagingService, + IMediaService mediaService, MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, - IJsonSerializer jsonSerializer, IMigrationContext context) : base(context) { _packagingService = packagingService; + _mediaService = mediaService; _mediaFileManager = mediaFileManager; + _mediaUrlGenerators = mediaUrlGenerators; _shortStringHelper = shortStringHelper; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; - _jsonSerializer = jsonSerializer; } public IImportPackageBuilder ImportPackage => BeginBuild( new ImportPackageBuilder( _packagingService, + _mediaService, _mediaFileManager, + _mediaUrlGenerators, _shortStringHelper, _contentTypeBaseServiceProvider, - _jsonSerializer, Context)); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index 3511a4ce0e..6cfc248827 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -69,9 +69,9 @@ namespace Umbraco.Cms.Core.PropertyEditors return editor; } - public bool TryGetMediaPath(string alias, object value, out string mediaPath) + public bool TryGetMediaPath(string propertyEditorAlias, object value, out string mediaPath) { - if (alias == Alias) + if (propertyEditorAlias == Alias) { mediaPath = value?.ToString(); return true; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index 3892071e57..805d92a267 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -92,11 +92,13 @@ namespace Umbraco.Cms.Core.PropertyEditors } // process the file - var filepath = editorFile == null ? null : ProcessFile(editorValue, file, currentPath, cuid, puid); + var filepath = editorFile == null ? null : ProcessFile(file, cuid, puid); // remove all temp files - foreach (var f in uploads) + foreach (ContentPropertyFile f in uploads) + { File.Delete(f.TempFilePath); + } // remove current file if replaced if (currentPath != filepath && string.IsNullOrWhiteSpace(currentPath) == false) @@ -109,16 +111,18 @@ namespace Umbraco.Cms.Core.PropertyEditors } - private string ProcessFile(ContentPropertyData editorValue, ContentPropertyFile file, string currentPath, Guid cuid, Guid puid) + private string ProcessFile(ContentPropertyFile file, Guid cuid, Guid puid) { // process the file // no file, invalid file, reject change if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _contentSettings) == false) + { return null; + } // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) - var filepath = _mediaFileManager.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path + var filepath = _mediaFileManager.GetMediaPath(file.FileName, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index f9425cbade..f21a18401c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -68,9 +68,9 @@ namespace Umbraco.Cms.Core.PropertyEditors _logger = loggerFactory.CreateLogger(); } - public bool TryGetMediaPath(string alias, object value, out string mediaPath) + public bool TryGetMediaPath(string propertyEditorAlias, object value, out string mediaPath) { - if (alias == Alias) + if (propertyEditorAlias == Alias) { mediaPath = GetFileSrcFromPropertyValue(value, out _, false); return true; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index c375b6f576..10a99ccd99 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -142,15 +142,19 @@ namespace Umbraco.Cms.Core.PropertyEditors } // process the file - var filepath = editorJson == null ? null : ProcessFile(editorValue, file, currentPath, cuid, puid); + var filepath = editorJson == null ? null : ProcessFile(file, cuid, puid); // remove all temp files - foreach (var f in uploads) + foreach (ContentPropertyFile f in uploads) + { File.Delete(f.TempFilePath); + } // remove current file if replaced if (currentPath != filepath && string.IsNullOrWhiteSpace(currentPath) == false) + { _mediaFileManager.FileSystem.DeleteFile(currentPath); + } // update json and return if (editorJson == null) return null; @@ -158,16 +162,18 @@ namespace Umbraco.Cms.Core.PropertyEditors return editorJson.ToString(); } - private string ProcessFile(ContentPropertyData editorValue, ContentPropertyFile file, string currentPath, Guid cuid, Guid puid) + private string ProcessFile(ContentPropertyFile file, Guid cuid, Guid puid) { // process the file // no file, invalid file, reject change if (UploadFileTypeValidator.IsValidFileExtension(file.FileName, _contentSettings) == false) + { return null; + } // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) - var filepath = _mediaFileManager.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path + var filepath = _mediaFileManager.GetMediaPath(file.FileName, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index f92b2911dd..80769663c6 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -28,11 +28,10 @@ namespace Umbraco.Cms.Core.PropertyEditors private readonly IMediaService _mediaService; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly MediaFileManager _mediaFileManager; + private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IShortStringHelper _shortStringHelper; private readonly IPublishedUrlProvider _publishedUrlProvider; - private readonly IJsonSerializer _serializer; - - const string TemporaryImageDataAttribute = "data-tmpimg"; + private const string TemporaryImageDataAttribute = "data-tmpimg"; public RichTextEditorPastedImages( IUmbracoContextAccessor umbracoContextAccessor, @@ -41,9 +40,9 @@ namespace Umbraco.Cms.Core.PropertyEditors IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, IShortStringHelper shortStringHelper, - IPublishedUrlProvider publishedUrlProvider, - IJsonSerializer serializer) + IPublishedUrlProvider publishedUrlProvider) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -51,9 +50,9 @@ namespace Umbraco.Cms.Core.PropertyEditors _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider ?? throw new ArgumentNullException(nameof(contentTypeBaseServiceProvider)); _mediaFileManager = mediaFileManager; + _mediaUrlGenerators = mediaUrlGenerators; _shortStringHelper = shortStringHelper; _publishedUrlProvider = publishedUrlProvider; - _serializer = serializer; } /// @@ -107,7 +106,7 @@ namespace Umbraco.Cms.Core.PropertyEditors if (fileStream == null) throw new InvalidOperationException("Could not acquire file stream"); using (fileStream) { - mediaFile.SetValue(_mediaFileManager, _shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File, safeFileName, fileStream); + mediaFile.SetValue(_mediaFileManager, _mediaUrlGenerators, _shortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File, safeFileName, fileStream); } _mediaService.Save(mediaFile, userId); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs index d4db4a76c7..52fade8dc2 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/RuntimeStateTests.cs @@ -8,6 +8,7 @@ using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Packaging; +using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; @@ -92,7 +93,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core private class TestMigration : PackageMigrationBase { - public TestMigration(IPackagingService packagingService, MediaFileManager mediaFileManager, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer jsonSerializer, IMigrationContext context) : base(packagingService, mediaFileManager, shortStringHelper, contentTypeBaseServiceProvider, jsonSerializer, context) + public TestMigration(IPackagingService packagingService, IMediaService mediaService, MediaFileManager mediaFileManager, MediaUrlGeneratorCollection mediaUrlGenerators, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMigrationContext context) : base(packagingService, mediaService, mediaFileManager, mediaUrlGenerators, shortStringHelper, contentTypeBaseServiceProvider, context) { } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs index b7aa9fafe1..c0a1b1700c 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs @@ -10,6 +10,7 @@ using Lucene.Net.Store; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Models; @@ -17,7 +18,6 @@ using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Persistence.Querying; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Examine; @@ -33,23 +33,26 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine public class IndexInitializer { private readonly IShortStringHelper _shortStringHelper; - private readonly IJsonSerializer _jsonSerializer; private readonly PropertyEditorCollection _propertyEditors; + private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IScopeProvider _scopeProvider; private readonly ILoggerFactory _loggerFactory; + private readonly IOptions _contentSettings; public IndexInitializer( IShortStringHelper shortStringHelper, - IJsonSerializer jsonSerializer, PropertyEditorCollection propertyEditors, + MediaUrlGeneratorCollection mediaUrlGenerators, IScopeProvider scopeProvider, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + IOptions contentSettings) { _shortStringHelper = shortStringHelper; - _jsonSerializer = jsonSerializer; _propertyEditors = propertyEditors; + _mediaUrlGenerators = mediaUrlGenerators; _scopeProvider = scopeProvider; _loggerFactory = loggerFactory; + _contentSettings = contentSettings; } public ContentValueSetBuilder GetContentValueSetBuilder(bool publishedValuesOnly) @@ -80,7 +83,13 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine public MediaIndexPopulator GetMediaIndexRebuilder(IMediaService mediaService) { - var mediaValueSetBuilder = new MediaValueSetBuilder(_propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(_shortStringHelper) }), GetMockUserService(), Mock.Of>(), _shortStringHelper, _jsonSerializer); + var mediaValueSetBuilder = new MediaValueSetBuilder( + _propertyEditors, + new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(_shortStringHelper) }), + _mediaUrlGenerators, + GetMockUserService(), + _shortStringHelper, + _contentSettings); var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder); return mediaIndexDataSource; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index c8c33c510e..e8947dbf17 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -67,7 +67,6 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly IRelationService _relationService; private readonly IImageUrlGenerator _imageUrlGenerator; - private readonly IJsonSerializer _serializer; private readonly IAuthorizationService _authorizationService; private readonly AppCaches _appCaches; private readonly ILogger _logger; @@ -90,6 +89,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers IRelationService relationService, PropertyEditorCollection propertyEditors, MediaFileManager mediaFileManager, + MediaUrlGeneratorCollection mediaUrlGenerators, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, IJsonSerializer serializer, @@ -111,10 +111,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers _relationService = relationService; _propertyEditors = propertyEditors; _mediaFileManager = mediaFileManager; + _mediaUrlGenerators = mediaUrlGenerators; _hostingEnvironment = hostingEnvironment; _logger = loggerFactory.CreateLogger(); _imageUrlGenerator = imageUrlGenerator; - _serializer = serializer; _authorizationService = authorizationService; _appCaches = appCaches; } @@ -289,6 +289,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers private int[] _userStartNodes; private readonly PropertyEditorCollection _propertyEditors; private readonly MediaFileManager _mediaFileManager; + private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IHostingEnvironment _hostingEnvironment; @@ -827,7 +828,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers await using (var stream = formFile.OpenReadStream()) { - f.SetValue(_mediaFileManager, _shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File, fileName, stream); + f.SetValue(_mediaFileManager, _mediaUrlGenerators, _shortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File, fileName, stream); }