diff --git a/src/Umbraco.Core/Events/QueuingEventDispatcher.cs b/src/Umbraco.Core/Events/QueuingEventDispatcher.cs index de82fc1f24..e79cd67cd8 100644 --- a/src/Umbraco.Core/Events/QueuingEventDispatcher.cs +++ b/src/Umbraco.Core/Events/QueuingEventDispatcher.cs @@ -11,11 +11,11 @@ namespace Umbraco.Cms.Core.Events /// public class QueuingEventDispatcher : QueuingEventDispatcherBase { - private readonly IMediaFileSystem _mediaFileSystem; - public QueuingEventDispatcher(IMediaFileSystem mediaFileSystem) + private readonly MediaFileManager _mediaFileManager; + public QueuingEventDispatcher(MediaFileManager mediaFileManager) : base(true) { - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; } protected override void ScopeExitCompleted() @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Core.Events // but then where should it be (without making things too complicated)? var delete = e.Args as IDeletingMediaFilesEventArgs; if (delete != null && delete.MediaFilesToDelete.Count > 0) - _mediaFileSystem.DeleteMediaFiles(delete.MediaFilesToDelete); + _mediaFileManager.DeleteMediaFiles(delete.MediaFilesToDelete); } } diff --git a/src/Umbraco.Core/Extensions/ContentExtensions.cs b/src/Umbraco.Core/Extensions/ContentExtensions.cs index 7794d60b15..5aaad5e303 100644 --- a/src/Umbraco.Core/Extensions/ContentExtensions.cs +++ b/src/Umbraco.Core/Extensions/ContentExtensions.cs @@ -204,7 +204,7 @@ namespace Umbraco.Extensions /// /// Sets the posted file value of a property. /// - public static void SetValue(this IContentBase content, IMediaFileSystem mediaFileSystem, 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, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer serializer, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) { if (filename == null || filestream == null) return; @@ -212,10 +212,10 @@ namespace Umbraco.Extensions if (string.IsNullOrWhiteSpace(filename)) return; filename = filename.ToLower(); - SetUploadFile(content, mediaFileSystem, contentTypeBaseServiceProvider, serializer, propertyTypeAlias, filename, filestream, culture, segment); + SetUploadFile(content, mediaFileManager, contentTypeBaseServiceProvider, serializer, propertyTypeAlias, filename, filestream, culture, segment); } - private static void SetUploadFile(this IContentBase content, IMediaFileSystem mediaFileSystem, 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, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer serializer, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) { var property = GetProperty(content, contentTypeBaseServiceProvider, propertyTypeAlias); @@ -229,11 +229,11 @@ namespace Umbraco.Extensions // 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 = mediaFileSystem.GetRelativePath(svalue); + oldpath = mediaFileManager.FileSystem.GetRelativePath(svalue); } - var filepath = mediaFileSystem.StoreFile(content, property.PropertyType, filename, filestream, oldpath); - property.SetValue(mediaFileSystem.GetUrl(filepath), culture, segment); + var filepath = mediaFileManager.StoreFile(content, property.PropertyType, filename, filestream, oldpath); + property.SetValue(mediaFileManager.FileSystem.GetUrl(filepath), culture, segment); } // gets or creates a property for a content item. @@ -269,13 +269,13 @@ namespace Umbraco.Extensions /// the "folder number" that was assigned to the previous file referenced by the property, /// if any. /// - public static string StoreFile(this IContentBase content, IMediaFileSystem mediaFileSystem, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string filepath) + public static string StoreFile(this IContentBase content, MediaFileManager mediaFileManager, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string filepath) { 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 + "."); - return mediaFileSystem.StoreFile(content, propertyType, filename, filestream, filepath); + return mediaFileManager.StoreFile(content, propertyType, filename, filestream, filepath); } #endregion diff --git a/src/Umbraco.Core/IO/FileSystemExtensions.cs b/src/Umbraco.Core/IO/FileSystemExtensions.cs index e688ca22da..6f1f47007f 100644 --- a/src/Umbraco.Core/IO/FileSystemExtensions.cs +++ b/src/Umbraco.Core/IO/FileSystemExtensions.cs @@ -66,33 +66,5 @@ namespace Umbraco.Extensions } fs.DeleteFile(tempFile); } - - /// - /// Unwraps a filesystem. - /// - /// - /// A filesystem can be wrapped in a (public) or a (internal), - /// and this method deals with the various wrappers and - /// - public static IFileSystem Unwrap(this IFileSystem filesystem) - { - var unwrapping = true; - while (unwrapping) - { - switch (filesystem) - { - case FileSystemWrapper wrapper: - filesystem = wrapper.InnerFileSystem; - break; - case ShadowWrapper shadow: - filesystem = shadow.InnerFileSystem; - break; - default: - unwrapping = false; - break; - } - } - return filesystem; - } } } diff --git a/src/Umbraco.Core/IO/FileSystemWrapper.cs b/src/Umbraco.Core/IO/FileSystemWrapper.cs deleted file mode 100644 index 34276131c7..0000000000 --- a/src/Umbraco.Core/IO/FileSystemWrapper.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Umbraco.Cms.Core.IO -{ - /// - /// All custom file systems that are based upon another IFileSystem should inherit from FileSystemWrapper - /// - /// - /// An IFileSystem is generally used as a base file system, for example like a PhysicalFileSystem or an S3FileSystem. - /// Then, other custom file systems are wrapped upon these files systems like MediaFileSystem, etc... All of the custom - /// file systems must inherit from FileSystemWrapper. - /// - /// This abstract class just wraps the 'real' IFileSystem object passed in to its constructor. - /// - public abstract class FileSystemWrapper : IFileSystem - { - protected FileSystemWrapper(IFileSystem innerFileSystem) - { - InnerFileSystem = innerFileSystem; - } - - internal IFileSystem InnerFileSystem { get; set; } - - public virtual IEnumerable GetDirectories(string path) - { - return InnerFileSystem.GetDirectories(path); - } - - public virtual void DeleteDirectory(string path) - { - InnerFileSystem.DeleteDirectory(path); - } - - public virtual void DeleteDirectory(string path, bool recursive) - { - InnerFileSystem.DeleteDirectory(path, recursive); - } - - public virtual bool DirectoryExists(string path) - { - return InnerFileSystem.DirectoryExists(path); - } - - public virtual void AddFile(string path, Stream stream) - { - InnerFileSystem.AddFile(path, stream); - } - - public virtual void AddFile(string path, Stream stream, bool overrideExisting) - { - InnerFileSystem.AddFile(path, stream, overrideExisting); - } - - public virtual IEnumerable GetFiles(string path) - { - return InnerFileSystem.GetFiles(path); - } - - public virtual IEnumerable GetFiles(string path, string filter) - { - return InnerFileSystem.GetFiles(path, filter); - } - - public virtual Stream OpenFile(string path) - { - return InnerFileSystem.OpenFile(path); - } - - public virtual void DeleteFile(string path) - { - InnerFileSystem.DeleteFile(path); - } - - public virtual bool FileExists(string path) - { - return InnerFileSystem.FileExists(path); - } - - public virtual string GetRelativePath(string fullPathOrUrl) - { - return InnerFileSystem.GetRelativePath(fullPathOrUrl); - } - - public virtual string GetFullPath(string path) - { - return InnerFileSystem.GetFullPath(path); - } - - public virtual string GetUrl(string path) - { - return InnerFileSystem.GetUrl(path); - } - - public virtual DateTimeOffset GetLastModified(string path) - { - return InnerFileSystem.GetLastModified(path); - } - - public virtual DateTimeOffset GetCreated(string path) - { - return InnerFileSystem.GetCreated(path); - } - - public virtual long GetSize(string path) - { - return InnerFileSystem.GetSize(path); - } - - public virtual bool CanAddPhysical => InnerFileSystem.CanAddPhysical; - - public virtual void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false) - { - InnerFileSystem.AddFile(path, physicalPath, overrideIfExists, copy); - } - } -} diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index 52ee2fe0d3..1b4db6acec 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -1,23 +1,25 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; -using Umbraco.Extensions; namespace Umbraco.Cms.Core.IO { - public class FileSystems : IFileSystems + /// + /// Provides the system filesystems. + /// + public sealed class FileSystems { - private readonly IServiceProvider _container; private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; private readonly IIOHelper _ioHelper; + private GlobalSettings _globalSettings; + private readonly IHostingEnvironment _hostingEnvironment; - private readonly ConcurrentDictionary> _filesystems = new ConcurrentDictionary>(); // wrappers for shadow support private ShadowWrapper _macroPartialFileSystem; @@ -38,93 +40,175 @@ namespace Umbraco.Cms.Core.IO #region Constructor // DI wants a public ctor - public FileSystems(IServiceProvider container, ILogger logger, ILoggerFactory loggerFactory, IIOHelper ioHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) + public FileSystems( + ILoggerFactory loggerFactory, + IIOHelper ioHelper, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment) { - _container = container; - _logger = logger; + _logger = loggerFactory.CreateLogger(); _loggerFactory = loggerFactory; _ioHelper = ioHelper; _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } - // for tests only, totally unsafe - internal void Reset() + // Ctor for tests, allows you to set the various filesystems + internal FileSystems( + ILoggerFactory loggerFactory, + IIOHelper ioHelper, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IFileSystem macroPartialFileSystem, + IFileSystem partialViewsFileSystem, + IFileSystem stylesheetFileSystem, + IFileSystem scriptsFileSystem, + IFileSystem mvcViewFileSystem) : this(loggerFactory, ioHelper, globalSettings, hostingEnvironment) { - _shadowWrappers.Clear(); - _filesystems.Clear(); - Volatile.Write(ref _wkfsInitialized, false); - _shadowCurrentId = null; + _macroPartialFileSystem = CreateShadowWrapperInternal(macroPartialFileSystem, "macro-partials"); + _partialViewsFileSystem = CreateShadowWrapperInternal(partialViewsFileSystem, "partials"); + _stylesheetsFileSystem = CreateShadowWrapperInternal(stylesheetFileSystem, "css"); + _scriptsFileSystem = CreateShadowWrapperInternal(scriptsFileSystem, "scripts"); + _mvcViewsFileSystem = CreateShadowWrapperInternal(mvcViewFileSystem, "view"); + // Set initialized to true so the filesystems doesn't get overwritten. + _wkfsInitialized = true; + } - // for tests only, totally unsafe - internal static void ResetShadowId() - { - _shadowCurrentId = null; - } - - // set by the scope provider when taking control of filesystems + /// + /// Used be Scope provider to take control over the filesystems, should never be used for anything else. + /// + [EditorBrowsable(EditorBrowsableState.Never)] public Func IsScoped { get; set; } = () => false; #endregion #region Well-Known FileSystems - /// + /// + /// Gets the macro partials filesystem. + /// public IFileSystem MacroPartialsFileSystem { get { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); + if (Volatile.Read(ref _wkfsInitialized) == false) + { + EnsureWellKnownFileSystems(); + } + return _macroPartialFileSystem; } } - /// + /// + /// Gets the partial views filesystem. + /// public IFileSystem PartialViewsFileSystem { get { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); + if (Volatile.Read(ref _wkfsInitialized) == false) + { + EnsureWellKnownFileSystems(); + } + return _partialViewsFileSystem; } } - /// + /// + /// Gets the stylesheets filesystem. + /// public IFileSystem StylesheetsFileSystem { get { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); + if (Volatile.Read(ref _wkfsInitialized) == false) + { + EnsureWellKnownFileSystems(); + } + return _stylesheetsFileSystem; } } - /// + /// + /// Gets the scripts filesystem. + /// public IFileSystem ScriptsFileSystem { get { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); + if (Volatile.Read(ref _wkfsInitialized) == false) + { + EnsureWellKnownFileSystems(); + } + return _scriptsFileSystem; } } - /// + /// + /// Gets the MVC views filesystem. + /// public IFileSystem MvcViewsFileSystem { get { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); + if (Volatile.Read(ref _wkfsInitialized) == false) + { + EnsureWellKnownFileSystems(); + } + return _mvcViewsFileSystem; } } - private void EnsureWellKnownFileSystems() + /// + /// Sets the stylesheet filesystem. + /// + /// + /// Be careful when using this, the root path and root url must be correct for this to work. + /// + /// The . + /// If the is null + /// Throws exception if the StylesheetFileSystem has already been initialized. + /// Throws exception if full path can't be resolved successfully. + public void SetStylesheetFilesystem(IFileSystem fileSystem) { - LazyInitializer.EnsureInitialized(ref _wkfsObject, ref _wkfsInitialized, ref _wkfsLock, CreateWellKnownFileSystems); + if (fileSystem == null) + { + throw new ArgumentNullException(nameof(fileSystem)); + } + + if (_stylesheetsFileSystem != null) + { + throw new InvalidOperationException( + "The StylesheetFileSystem cannot be changed when it's already been initialized."); + } + + // Verify that _rootUrl/_rootPath is correct + // We have to do this because there's a tight coupling + // to the VirtualPath we get with CodeFileDisplay from the frontend. + try + { + var rootPath = fileSystem.GetFullPath("/css/"); + } + catch (UnauthorizedAccessException exception) + { + throw new UnauthorizedAccessException( + "Can't register the stylesheet filesystem, " + + "this is most likely caused by using a PhysicalFileSystem with an incorrect " + + "rootPath/rootUrl. RootPath must be \\wwwroot\\css" + + " and rootUrl must be /css", exception); + } + + _stylesheetsFileSystem = CreateShadowWrapperInternal(fileSystem, "css"); } + private void EnsureWellKnownFileSystems() => LazyInitializer.EnsureInitialized(ref _wkfsObject, ref _wkfsInitialized, ref _wkfsLock, CreateWellKnownFileSystems); + // need to return something to LazyInitializer.EnsureInitialized // but it does not really matter what we return - here, null private object CreateWellKnownFileSystems() @@ -134,20 +218,28 @@ namespace Umbraco.Cms.Core.IO //TODO this is fucked, why do PhysicalFileSystem has a root url? Mvc views cannot be accessed by url! var macroPartialFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MacroPartials), _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.MacroPartials)); var partialViewsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.PartialViews), _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.PartialViews)); - var stylesheetsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _hostingEnvironment.MapPathWebRoot(_globalSettings.UmbracoCssPath), _hostingEnvironment.ToAbsolute(_globalSettings.UmbracoCssPath)); var scriptsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _hostingEnvironment.MapPathWebRoot(_globalSettings.UmbracoScriptsPath), _hostingEnvironment.ToAbsolute(_globalSettings.UmbracoScriptsPath)); var mvcViewsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MvcViews), _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.MvcViews)); _macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "macro-partials", IsScoped); _partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "partials", IsScoped); - _stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "css", IsScoped); _scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "scripts", IsScoped); _mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "views", IsScoped); + if (_stylesheetsFileSystem == null) + { + var stylesheetsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, + _hostingEnvironment.MapPathWebRoot(_globalSettings.UmbracoCssPath), + _hostingEnvironment.ToAbsolute(_globalSettings.UmbracoCssPath)); + + _stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "css", IsScoped); + + _shadowWrappers.Add(_stylesheetsFileSystem); + } + // TODO: do we need a lock here? _shadowWrappers.Add(_macroPartialFileSystem); _shadowWrappers.Add(_partialViewsFileSystem); - _shadowWrappers.Add(_stylesheetsFileSystem); _shadowWrappers.Add(_scriptsFileSystem); _shadowWrappers.Add(_mvcViewsFileSystem); @@ -156,64 +248,6 @@ namespace Umbraco.Cms.Core.IO #endregion - #region Providers - - private readonly Dictionary _paths = new Dictionary(); - - // internal for tests - internal IReadOnlyDictionary Paths => _paths; - private GlobalSettings _globalSettings; - private readonly IHostingEnvironment _hostingEnvironment; - - /// - /// Gets a strongly-typed filesystem. - /// - /// The type of the filesystem. - /// A strongly-typed filesystem of the specified type. - /// - /// Note that any filesystem created by this method *after* shadowing begins, will *not* be - /// shadowing (and an exception will be thrown by the ShadowWrapper). - /// - public TFileSystem GetFileSystem(IFileSystem supporting) - where TFileSystem : FileSystemWrapper - { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); - - return (TFileSystem) _filesystems.GetOrAdd(typeof(TFileSystem), _ => new Lazy(() => - { - var typeofTFileSystem = typeof(TFileSystem); - - // path must be unique and not collide with paths used in CreateWellKnownFileSystems - // for our well-known 'media' filesystem we can use the short 'media' path - // for others, put them under 'x/' and use ... something - string path; - if (typeofTFileSystem == typeof(MediaFileSystem)) - { - path = "media"; - } - else - { - lock (_paths) - { - if (!_paths.TryGetValue(typeofTFileSystem, out path)) - { - path = Guid.NewGuid().ToString("N").Substring(0, 6); - while (_paths.ContainsValue(path)) // this can't loop forever, right? - path = Guid.NewGuid().ToString("N").Substring(0, 6); - _paths[typeofTFileSystem] = path; - } - } - - path = "x/" + path; - } - - var shadowWrapper = CreateShadowWrapper(supporting, path); - return _container.CreateInstance(shadowWrapper); - })).Value; - } - - #endregion - #region Shadow // note @@ -221,9 +255,17 @@ namespace Umbraco.Cms.Core.IO // global shadow for the entire application, so great care should be taken to ensure that the // application is *not* doing anything else when using a shadow. + /// + /// Shadows the filesystem, should never be used outside the Scope class. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] public ICompletable Shadow() { - if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems(); + if (Volatile.Read(ref _wkfsInitialized) == false) + { + EnsureWellKnownFileSystems(); + } var id = ShadowWrapper.CreateShadowId(_hostingEnvironment); return new ShadowFileSystems(this, id); // will invoke BeginShadow and EndShadow @@ -235,14 +277,18 @@ namespace Umbraco.Cms.Core.IO { // if we throw here, it means that something very wrong happened. if (_shadowCurrentId != null) + { throw new InvalidOperationException("Already shadowing."); + } _shadowCurrentId = id; _logger.LogDebug("Shadow '{ShadowId}'", _shadowCurrentId); - foreach (var wrapper in _shadowWrappers) + foreach (ShadowWrapper wrapper in _shadowWrappers) + { wrapper.Shadow(_shadowCurrentId); + } } } @@ -252,14 +298,19 @@ namespace Umbraco.Cms.Core.IO { // if we throw here, it means that something very wrong happened. if (_shadowCurrentId == null) + { throw new InvalidOperationException("Not shadowing."); + } + if (id != _shadowCurrentId) + { throw new InvalidOperationException("Not the current shadow."); + } _logger.LogDebug("UnShadow '{ShadowId}' {Status}", id, completed ? "complete" : "abort"); var exceptions = new List(); - foreach (var wrapper in _shadowWrappers) + foreach (ShadowWrapper wrapper in _shadowWrappers) { try { @@ -275,17 +326,31 @@ namespace Umbraco.Cms.Core.IO _shadowCurrentId = null; if (exceptions.Count > 0) + { throw new AggregateException(completed ? "Failed to apply all changes (see exceptions)." : "Failed to abort (see exceptions).", exceptions); + } } } - private ShadowWrapper CreateShadowWrapper(IFileSystem filesystem, string shadowPath) + /// + /// Creates a shadow wrapper for a filesystem, should never be used outside UmbracoBuilder or testing + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IFileSystem CreateShadowWrapper(IFileSystem filesystem, string shadowPath) => CreateShadowWrapperInternal(filesystem, shadowPath); + + private ShadowWrapper CreateShadowWrapperInternal(IFileSystem filesystem, string shadowPath) { lock (_shadowLocker) { var wrapper = new ShadowWrapper(filesystem, _ioHelper, _hostingEnvironment, _loggerFactory, shadowPath,() => IsScoped()); if (_shadowCurrentId != null) + { wrapper.Shadow(_shadowCurrentId); + } + _shadowWrappers.Add(wrapper); return wrapper; } diff --git a/src/Umbraco.Core/IO/IFileSystems.cs b/src/Umbraco.Core/IO/IFileSystems.cs deleted file mode 100644 index 3a169e33a3..0000000000 --- a/src/Umbraco.Core/IO/IFileSystems.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Umbraco.Cms.Core.IO -{ - /// - /// Provides the system filesystems. - /// - public interface IFileSystems - { - /// - /// Gets the macro partials filesystem. - /// - IFileSystem MacroPartialsFileSystem { get; } - - /// - /// Gets the partial views filesystem. - /// - IFileSystem PartialViewsFileSystem { get; } - - /// - /// Gets the stylesheets filesystem. - /// - IFileSystem StylesheetsFileSystem { get; } - - /// - /// Gets the scripts filesystem. - /// - IFileSystem ScriptsFileSystem { get; } - - /// - /// Gets the MVC views filesystem. - /// - IFileSystem MvcViewsFileSystem { get; } - } -} diff --git a/src/Umbraco.Core/IO/IMediaFileSystem.cs b/src/Umbraco.Core/IO/IMediaFileSystem.cs deleted file mode 100644 index eced74482e..0000000000 --- a/src/Umbraco.Core/IO/IMediaFileSystem.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Umbraco.Cms.Core.Models; - -namespace Umbraco.Cms.Core.IO -{ - /// - /// Provides methods allowing the manipulation of media files. - /// - public interface IMediaFileSystem : IFileSystem - { - /// - /// Delete media files. - /// - /// Files to delete (filesystem-relative paths). - void DeleteMediaFiles(IEnumerable files); - - /// - /// Gets the file path of a media file. - /// - /// The file name. - /// 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. - /// With the old media path scheme, this CREATES a new media path each time it is invoked. - string GetMediaPath(string filename, Guid cuid, Guid puid); - - /// - /// 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. - string GetMediaPath(string filename, string prevpath, Guid cuid, Guid puid); - - /// - /// Stores a media file associated to a property of a content item. - /// - /// The content item owning the media file. - /// The property type owning the media file. - /// The media file name. - /// A stream containing the media bytes. - /// An optional filesystem-relative filepath to the previous media file. - /// The filesystem-relative filepath to the media file. - /// - /// The file is considered "owned" by the content/propertyType. - /// If an is provided then that file (and associated thumbnails if any) is deleted - /// before the new file is saved, and depending on the media path scheme, the folder may be reused for the new file. - /// - string StoreFile(IContentBase content, IPropertyType propertyType, string filename, Stream filestream, string oldpath); - - /// - /// Copies a media file as a new media file, associated to a property of a content item. - /// - /// The content item owning the copy of the media file. - /// The property type owning the copy of the media file. - /// The filesystem-relative path to the source media file. - /// The filesystem-relative path to the copy of the media file. - string CopyFile(IContentBase content, IPropertyType propertyType, string sourcepath); - } -} diff --git a/src/Umbraco.Core/IO/IMediaPathScheme.cs b/src/Umbraco.Core/IO/IMediaPathScheme.cs index bd48b21a16..2b2696ec5d 100644 --- a/src/Umbraco.Core/IO/IMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/IMediaPathScheme.cs @@ -10,13 +10,13 @@ namespace Umbraco.Cms.Core.IO /// /// Gets a media file path. /// - /// The media filesystem. + /// The media filesystem. /// 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(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null); + string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null); /// /// Gets the directory that can be deleted when the file is deleted. @@ -28,6 +28,6 @@ namespace Umbraco.Cms.Core.IO /// The directory, and anything below it, will be deleted. /// Can return null (or empty) when no directory should be deleted. /// - string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath); + string GetDeleteDirectory(MediaFileManager fileSystem, string filepath); } } diff --git a/src/Umbraco.Core/IO/MediaFileManager.cs b/src/Umbraco.Core/IO/MediaFileManager.cs new file mode 100644 index 0000000000..de89d7ca87 --- /dev/null +++ b/src/Umbraco.Core/IO/MediaFileManager.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Core.IO +{ + public sealed class MediaFileManager + { + private readonly IMediaPathScheme _mediaPathScheme; + private readonly ILogger _logger; + private readonly IShortStringHelper _shortStringHelper; + + /// + /// Gets the media filesystem. + /// + public IFileSystem FileSystem { get; } + + public MediaFileManager( + IFileSystem fileSystem, + IMediaPathScheme mediaPathScheme, + ILogger logger, + IShortStringHelper shortStringHelper) + { + _mediaPathScheme = mediaPathScheme; + _logger = logger; + _shortStringHelper = shortStringHelper; + FileSystem = fileSystem; + } + + /// + /// Delete media files. + /// + /// Files to delete (filesystem-relative paths). + public void DeleteMediaFiles(IEnumerable files) + { + files = files.Distinct(); + + // kinda try to keep things under control + var options = new ParallelOptions { MaxDegreeOfParallelism = 20 }; + + Parallel.ForEach(files, options, file => + { + try + { + if (file.IsNullOrWhiteSpace()) + { + return; + } + + if (FileSystem.FileExists(file) == false) + { + return; + } + + FileSystem.DeleteFile(file); + + var directory = _mediaPathScheme.GetDeleteDirectory(this, file); + if (!directory.IsNullOrWhiteSpace()) + { + FileSystem.DeleteDirectory(directory, true); + } + } + catch (Exception e) + { + _logger.LogError(e, "Failed to delete media file '{File}'.", file); + } + }); + } + + #region Media Path + + /// + /// Gets the file path of a media file. + /// + /// The file name. + /// 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. + /// With the old media path scheme, this CREATES a new media path each time it is invoked. + public string GetMediaPath(string filename, 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); + } + + /// + /// 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 + + /// + /// Stores a media file associated to a property of a content item. + /// + /// The content item owning the media file. + /// The property type owning the media file. + /// The media file name. + /// A stream containing the media bytes. + /// An optional filesystem-relative filepath to the previous media file. + /// The filesystem-relative filepath to the media file. + /// + /// The file is considered "owned" by the content/propertyType. + /// If an is provided then that file (and associated thumbnails if any) is deleted + /// before the new file is saved, and depending on the media path scheme, the folder may be reused for the new file. + /// + public string StoreFile(IContentBase content, IPropertyType propertyType, string filename, Stream filestream, string oldpath) + { + if (content == null) + { + throw new ArgumentNullException(nameof(content)); + } + + if (propertyType == null) + { + throw new ArgumentNullException(nameof(propertyType)); + } + + if (filename == null) + { + throw new ArgumentNullException(nameof(filename)); + } + + if (string.IsNullOrWhiteSpace(filename)) + { + throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(filename)); + } + + if (filestream == null) + { + throw new ArgumentNullException(nameof(filestream)); + } + + // clear the old file, if any + if (string.IsNullOrWhiteSpace(oldpath) == false) + { + FileSystem.DeleteFile(oldpath); + } + + // 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); + FileSystem.AddFile(filepath, filestream); + return filepath; + } + + /// + /// Copies a media file as a new media file, associated to a property of a content item. + /// + /// The content item owning the copy of the media file. + /// The property type owning the copy of the media file. + /// The filesystem-relative path to the source media file. + /// The filesystem-relative path to the copy of the media file. + public string CopyFile(IContentBase content, IPropertyType propertyType, string sourcepath) + { + if (content == null) + { + throw new ArgumentNullException(nameof(content)); + } + + if (propertyType == null) + { + throw new ArgumentNullException(nameof(propertyType)); + } + + if (sourcepath == null) + { + throw new ArgumentNullException(nameof(sourcepath)); + } + + if (string.IsNullOrWhiteSpace(sourcepath)) + { + throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(sourcepath)); + } + + // ensure we have a file to copy + if (FileSystem.FileExists(sourcepath) == false) + { + return null; + } + + // get the filepath + var filename = Path.GetFileName(sourcepath); + var filepath = GetMediaPath(filename, content.Key, propertyType.Key); + FileSystem.CopyFile(sourcepath, filepath); + return filepath; + } + + #endregion + } +} diff --git a/src/Umbraco.Core/IO/MediaFileSystem.cs b/src/Umbraco.Core/IO/MediaFileSystem.cs deleted file mode 100644 index 6d598941c5..0000000000 --- a/src/Umbraco.Core/IO/MediaFileSystem.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Strings; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Core.IO -{ - /// - /// A custom file system provider for media - /// - public class MediaFileSystem : FileSystemWrapper, IMediaFileSystem - { - private readonly IMediaPathScheme _mediaPathScheme; - private readonly ILogger _logger; - private readonly IShortStringHelper _shortStringHelper; - - /// - /// Initializes a new instance of the class. - /// - public MediaFileSystem(IFileSystem innerFileSystem, IMediaPathScheme mediaPathScheme, ILogger logger, IShortStringHelper shortStringHelper) - : base(innerFileSystem) - { - _mediaPathScheme = mediaPathScheme; - _logger = logger; - _shortStringHelper = shortStringHelper; - } - - /// - public void DeleteMediaFiles(IEnumerable files) - { - files = files.Distinct(); - - // kinda try to keep things under control - var options = new ParallelOptions { MaxDegreeOfParallelism = 20 }; - - Parallel.ForEach(files, options, file => - { - try - { - if (file.IsNullOrWhiteSpace()) return; - if (FileExists(file) == false) return; - DeleteFile(file); - - var directory = _mediaPathScheme.GetDeleteDirectory(this, file); - if (!directory.IsNullOrWhiteSpace()) - DeleteDirectory(directory, true); - } - catch (Exception e) - { - _logger.LogError(e, "Failed to delete media file '{File}'.", file); - } - }); - } - - #region Media Path - - /// - public string GetMediaPath(string filename, 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); - } - - /// - 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 string StoreFile(IContentBase content, IPropertyType propertyType, string filename, Stream filestream, string oldpath) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - if (propertyType == null) throw new ArgumentNullException(nameof(propertyType)); - if (filename == null) throw new ArgumentNullException(nameof(filename)); - if (string.IsNullOrWhiteSpace(filename)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(filename)); - if (filestream == null) throw new ArgumentNullException(nameof(filestream)); - - // clear the old file, if any - if (string.IsNullOrWhiteSpace(oldpath) == false) - DeleteFile(oldpath); - - // 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); - AddFile(filepath, filestream); - return filepath; - } - - /// - public string CopyFile(IContentBase content, IPropertyType propertyType, string sourcepath) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - if (propertyType == null) throw new ArgumentNullException(nameof(propertyType)); - if (sourcepath == null) throw new ArgumentNullException(nameof(sourcepath)); - if (string.IsNullOrWhiteSpace(sourcepath)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(sourcepath)); - - // ensure we have a file to copy - if (FileExists(sourcepath) == false) return null; - - // get the filepath - var filename = Path.GetFileName(sourcepath); - var filepath = GetMediaPath(filename, content.Key, propertyType.Key); - this.CopyFile(sourcepath, filepath); - return filepath; - } - - #endregion - } -} diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs index a23468d5ac..f3c15a13d6 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/CombinedGuidsMediaPathScheme.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes public class CombinedGuidsMediaPathScheme : IMediaPathScheme { /// - public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) { // 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 @@ -23,6 +23,6 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes } /// - public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => Path.GetDirectoryName(filepath); + public string GetDeleteDirectory(MediaFileManager fileSystem, string filepath) => Path.GetDirectoryName(filepath); } } diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs index ea23bf0145..d1cea0c46b 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/OriginalMediaPathScheme.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes private bool _folderCounterInitialized; /// - public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) { string directory; if (previous != null) @@ -33,11 +33,11 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes 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(fileSystem); + directory = pos > 0 && int.TryParse(s, out _) ? s : GetNextDirectory(fileManager.FileSystem); } else { - directory = GetNextDirectory(fileSystem); + directory = GetNextDirectory(fileManager.FileSystem); } if (directory == null) @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes } /// - public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) + public string GetDeleteDirectory(MediaFileManager fileSystem, string filepath) { return Path.GetDirectoryName(filepath); } diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs index 2fffd4e7d6..203c8aaed8 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/TwoGuidsMediaPathScheme.cs @@ -12,13 +12,13 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes public class TwoGuidsMediaPathScheme : IMediaPathScheme { /// - public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) { return Path.Combine(itemGuid.ToString("N"), propertyGuid.ToString("N"), filename).Replace('\\', '/'); } /// - public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) + public string GetDeleteDirectory(MediaFileManager fileManager, string filepath) { return Path.GetDirectoryName(filepath); } diff --git a/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs b/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs index faf94fb6e6..55a9cd4574 100644 --- a/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs +++ b/src/Umbraco.Core/IO/MediaPathSchemes/UniqueMediaPathScheme.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes private const int DirectoryLength = 8; /// - public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) + public string GetFilePath(MediaFileManager fileManager, Guid itemGuid, Guid propertyGuid, string filename, string previous = null) { var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid); var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength); @@ -32,6 +32,6 @@ namespace Umbraco.Cms.Core.IO.MediaPathSchemes /// race conditions. We'd need to implement locks in for /// this. /// - public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => null; + public string GetDeleteDirectory(MediaFileManager fileManager, string filepath) => null; } } diff --git a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs index dc5529d25f..32c8ddd98d 100644 --- a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs @@ -13,18 +13,18 @@ namespace Umbraco.Cms.Core.Media /// public class UploadAutoFillProperties { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ILogger _logger; private readonly IImageUrlGenerator _imageUrlGenerator; private readonly IImageDimensionExtractor _imageDimensionExtractor; public UploadAutoFillProperties( - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, ILogger logger, IImageUrlGenerator imageUrlGenerator, IImageDimensionExtractor imageDimensionExtractor) { - _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + _mediaFileManager = mediaFileManager ?? throw new ArgumentNullException(nameof(mediaFileManager)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator)); _imageDimensionExtractor = imageDimensionExtractor ?? throw new ArgumentNullException(nameof(imageDimensionExtractor)); @@ -69,7 +69,7 @@ namespace Umbraco.Cms.Core.Media // if anything goes wrong, just reset the properties try { - using (var filestream = _mediaFileSystem.OpenFile(filepath)) + 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; diff --git a/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs index 85da93fb31..4a19fbe530 100644 --- a/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs @@ -28,12 +28,12 @@ namespace Umbraco.Cms.Core.Models.Mapping private readonly ActionCollection _actions; private readonly AppCaches _appCaches; private readonly GlobalSettings _globalSettings; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly IShortStringHelper _shortStringHelper; private readonly IImageUrlGenerator _imageUrlGenerator; public UserMapDefinition(ILocalizedTextService textService, IUserService userService, IEntityService entityService, ISectionService sectionService, - AppCaches appCaches, ActionCollection actions, IOptions globalSettings, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, + AppCaches appCaches, ActionCollection actions, IOptions globalSettings, MediaFileManager mediaFileManager, IShortStringHelper shortStringHelper, IImageUrlGenerator imageUrlGenerator) { _sectionService = sectionService; @@ -43,7 +43,7 @@ namespace Umbraco.Cms.Core.Models.Mapping _actions = actions; _appCaches = appCaches; _globalSettings = globalSettings.Value; - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _shortStringHelper = shortStringHelper; _imageUrlGenerator = imageUrlGenerator; } @@ -283,7 +283,7 @@ namespace Umbraco.Cms.Core.Models.Mapping private void Map(IUser source, UserDisplay target, MapperContext context) { target.AvailableCultures = _textService.GetSupportedCultures().ToDictionary(x => x.Name, x => x.DisplayName); - target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator); target.CalculatedStartContentIds = GetStartNodes(source.CalculateContentStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Document, "content/contentRoot", context); target.CalculatedStartMediaIds = GetStartNodes(source.CalculateMediaStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Media, "media/mediaRoot", context); target.CreateDate = source.CreateDate; @@ -314,7 +314,7 @@ namespace Umbraco.Cms.Core.Models.Mapping //Loading in the user avatar's requires an external request if they don't have a local file avatar, this means that initial load of paging may incur a cost //Alternatively, if this is annoying the back office UI would need to be updated to request the avatars for the list of users separately so it doesn't look //like the load time is waiting. - target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator); target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString(); target.Email = source.Email; target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash(); @@ -333,7 +333,7 @@ namespace Umbraco.Cms.Core.Models.Mapping private void Map(IUser source, UserDetail target, MapperContext context) { target.AllowedSections = source.AllowedSections; - target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator); target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString(); target.Email = source.Email; target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash(); diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index 6fb74c3b86..dd96faf298 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -21,11 +21,11 @@ namespace Umbraco.Cms.Core.Models /// /// /// - /// + /// /// /// A list of 5 different sized avatar URLs /// - public static string[] GetUserAvatarUrls(this IUser user, IAppCache cache, IMediaFileSystem mediaFileSystem, IImageUrlGenerator imageUrlGenerator) + public static string[] GetUserAvatarUrls(this IUser user, IAppCache cache, MediaFileManager mediaFileManager, IImageUrlGenerator imageUrlGenerator) { // If FIPS is required, never check the Gravatar service as it only supports MD5 hashing. // Unfortunately, if the FIPS setting is enabled on Windows, using MD5 will throw an exception @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Core.Models } //use the custom avatar - var avatarUrl = mediaFileSystem.GetUrl(user.Avatar); + var avatarUrl = mediaFileManager.FileSystem.GetUrl(user.Avatar); return new[] { imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = ImageCropMode.Crop, Width = 30, Height = 30 }), diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs index b00b9a4985..edb8033f3d 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs @@ -19,10 +19,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection * Create an implementation of IFileSystem and register it as the underlying filesystem for * MediaFileSystem with the following extension on composition. * - * composition.SetMediaFileSystem(factory => FactoryMethodToReturnYourImplementation()) - * - * Alternatively you can just register an Implementation of IMediaFileSystem, however the - * extension above ensures that your IFileSystem implementation is wrapped by the "ShadowWrapper". + * builder.SetMediaFileSystem(factory => FactoryMethodToReturnYourImplementation()) * * WHAT IS SHADOWING * ----------------- @@ -37,23 +34,17 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection internal static IUmbracoBuilder AddFileSystems(this IUmbracoBuilder builder) { // register FileSystems, which manages all filesystems - // it needs to be registered (not only the interface) because it provides additional - // functionality eg for scoping, and is injected in the scope provider - whereas the - // interface is really for end-users to get access to filesystems. - builder.Services.AddUnique(factory => factory.CreateInstance(factory)); - - // register IFileSystems, which gives access too all filesystems - builder.Services.AddUnique(factory => factory.GetRequiredService()); + builder.Services.AddUnique(); // register the scheme for media paths builder.Services.AddUnique(); builder.SetMediaFileSystem(factory => { - var ioHelper = factory.GetRequiredService(); - var hostingEnvironment = factory.GetRequiredService(); - var logger = factory.GetRequiredService>(); - var globalSettings = factory.GetRequiredService>().Value; + IIOHelper ioHelper = factory.GetRequiredService(); + IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); + ILogger logger = factory.GetRequiredService>(); + GlobalSettings globalSettings = factory.GetRequiredService>().Value; var rootPath = hostingEnvironment.MapPathWebRoot(globalSettings.UmbracoMediaPath); var rootUrl = hostingEnvironment.ToAbsolute(globalSettings.UmbracoMediaPath); diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs index 5a6c8fe8f2..cbbaa6a3e0 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Dictionary; using Umbraco.Cms.Core.IO; @@ -109,20 +110,48 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection } /// - /// Sets the underlying media filesystem. + /// Sets the filesystem used by the MediaFileManager /// /// A builder. - /// A filesystem factory. - /// - /// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper - /// - public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func filesystemFactory) - => builder.Services.AddUnique(factory => + /// Factory method to create an IFileSystem implementation used in the MediaFileManager + public static void SetMediaFileSystem(this IUmbracoBuilder builder, + Func filesystemFactory) => builder.Services.AddUnique( + provider => { - var fileSystems = factory.GetRequiredService(); - return fileSystems.GetFileSystem(filesystemFactory(factory)); + IFileSystem filesystem = filesystemFactory(provider); + // We need to use the Filesystems to create a shadow wrapper, + // because shadow wrapper requires the IsScoped delegate from the FileSystems. + // This is used by the scope provider when taking control of the filesystems. + FileSystems fileSystems = provider.GetRequiredService(); + IFileSystem shadow = fileSystems.CreateShadowWrapper(filesystem, "media"); + + return provider.CreateInstance(shadow); }); + /// + /// Register FileSystems with a method to configure the . + /// + /// A builder. + /// Method that configures the . + /// Throws exception if is null. + /// Throws exception if full path can't be resolved successfully. + public static void ConfigureFileSystems(this IUmbracoBuilder builder, + Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + builder.Services.AddUnique( + provider => + { + FileSystems fileSystems = provider.CreateInstance(); + configure(provider, fileSystems); + return fileSystems; + }); + } + /// /// Sets the log viewer. /// diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewMacroRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewMacroRepository.cs index d13e4c6945..47123b790e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewMacroRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewMacroRepository.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { internal class PartialViewMacroRepository : PartialViewRepository, IPartialViewMacroRepository { - public PartialViewMacroRepository(IFileSystems fileSystems, IIOHelper ioHelper) + public PartialViewMacroRepository(FileSystems fileSystems, IIOHelper ioHelper) : base(fileSystems.MacroPartialsFileSystem, ioHelper) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs index eee199e252..a1d2b218c4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { private readonly IIOHelper _ioHelper; - public PartialViewRepository(IFileSystems fileSystems, IIOHelper ioHelper) + public PartialViewRepository(FileSystems fileSystems, IIOHelper ioHelper) : base(fileSystems.PartialViewsFileSystem) { _ioHelper = ioHelper; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs index 161b7a90a8..77b8ac9e20 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs @@ -19,7 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private readonly IIOHelper _ioHelper; private readonly GlobalSettings _globalSettings; - public ScriptRepository(IFileSystems fileSystems, IIOHelper ioHelper, IOptions globalSettings) + public ScriptRepository(FileSystems fileSystems, IIOHelper ioHelper, IOptions globalSettings) : base(fileSystems.ScriptsFileSystem) { _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs index 03c729b51c..ac255890bd 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private readonly IIOHelper _ioHelper; private readonly GlobalSettings _globalSettings; - public StylesheetRepository(ILogger logger, IFileSystems fileSystems, IIOHelper ioHelper, IOptions globalSettings) + public StylesheetRepository(ILogger logger, FileSystems fileSystems, IIOHelper ioHelper, IOptions globalSettings) : base(fileSystems.StylesheetsFileSystem) { _logger = logger; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs index ec54a6bef8..3aad92a012 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs @@ -30,7 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement private readonly IFileSystem _viewsFileSystem; private readonly ViewHelper _viewHelper; - public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IFileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper) + public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, FileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger) { _ioHelper = ioHelper; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index a0bbf2a7fe..db895444c4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -30,7 +30,7 @@ namespace Umbraco.Cms.Core.PropertyEditors INotificationHandler, INotificationHandler, INotificationHandler { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ContentSettings _contentSettings; private readonly UploadAutoFillProperties _uploadAutoFillProperties; private readonly IDataTypeService _dataTypeService; @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.PropertyEditors public FileUploadPropertyEditor( ILoggerFactory loggerFactory, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IOptions contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Core.PropertyEditors IContentService contentService) : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { - _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + _mediaFileManager = mediaFileManager ?? throw new ArgumentNullException(nameof(mediaFileManager)); _contentSettings = contentSettings.Value; _dataTypeService = dataTypeService; _localizationService = localizationService; @@ -66,7 +66,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// The corresponding property value editor. protected override IDataValueEditor CreateValueEditor() { - var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Options.Create(_contentSettings), JsonSerializer); + var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileManager, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Options.Create(_contentSettings), JsonSerializer); editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, Options.Create(_contentSettings))); return editor; } @@ -115,12 +115,12 @@ namespace Umbraco.Cms.Core.PropertyEditors //check if the published value contains data and return it var propVal = propertyValue.PublishedValue; if (propVal != null && propVal is string str1 && !str1.IsNullOrWhiteSpace()) - yield return _mediaFileSystem.GetRelativePath(str1); + yield return _mediaFileManager.FileSystem.GetRelativePath(str1); //check if the edited value contains data and return it propVal = propertyValue.EditedValue; if (propVal != null && propVal is string str2 && !str2.IsNullOrWhiteSpace()) - yield return _mediaFileSystem.GetRelativePath(str2); + yield return _mediaFileManager.FileSystem.GetRelativePath(str2); } } @@ -142,9 +142,9 @@ namespace Umbraco.Cms.Core.PropertyEditors continue; } - var sourcePath = _mediaFileSystem.GetRelativePath(str); - var copyPath = _mediaFileSystem.CopyFile(notification.Copy, property.PropertyType, sourcePath); - notification.Copy.SetValue(property.Alias, _mediaFileSystem.GetUrl(copyPath), propertyValue.Culture, propertyValue.Segment); + var sourcePath = _mediaFileManager.FileSystem.GetRelativePath(str); + var copyPath = _mediaFileManager.CopyFile(notification.Copy, property.PropertyType, sourcePath); + notification.Copy.SetValue(property.Alias, _mediaFileManager.FileSystem.GetUrl(copyPath), propertyValue.Culture, propertyValue.Segment); isUpdated = true; } } @@ -165,7 +165,7 @@ namespace Umbraco.Cms.Core.PropertyEditors private void DeleteContainedFiles(IEnumerable deletedEntities) { var filePathsToDelete = ContainedFilePaths(deletedEntities); - _mediaFileSystem.DeleteMediaFiles(filePathsToDelete); + _mediaFileManager.DeleteMediaFiles(filePathsToDelete); } public void Handle(MediaSavingNotification notification) @@ -194,7 +194,7 @@ namespace Umbraco.Cms.Core.PropertyEditors if (string.IsNullOrWhiteSpace(svalue)) _uploadAutoFillProperties.Reset(model, autoFillConfig, pvalue.Culture, pvalue.Segment); else - _uploadAutoFillProperties.Populate(model, autoFillConfig, _mediaFileSystem.GetRelativePath(svalue), pvalue.Culture, pvalue.Segment); + _uploadAutoFillProperties.Populate(model, autoFillConfig, _mediaFileManager.FileSystem.GetRelativePath(svalue), pvalue.Culture, pvalue.Segment); } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index 3f892dd000..b30a0b971d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -19,12 +19,12 @@ namespace Umbraco.Cms.Core.PropertyEditors /// internal class FileUploadPropertyValueEditor : DataValueEditor { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ContentSettings _contentSettings; public FileUploadPropertyValueEditor( DataEditorAttribute attribute, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Core.PropertyEditors IJsonSerializer jsonSerializer) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { - _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + _mediaFileManager = mediaFileManager ?? throw new ArgumentNullException(nameof(mediaFileManager)); _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); } @@ -59,7 +59,7 @@ namespace Umbraco.Cms.Core.PropertyEditors { var currentPath = currentValue as string; if (!currentPath.IsNullOrWhiteSpace()) - currentPath = _mediaFileSystem.GetRelativePath(currentPath); + currentPath = _mediaFileManager.FileSystem.GetRelativePath(currentPath); string editorFile = null; if (editorValue.Value != null) @@ -84,7 +84,7 @@ namespace Umbraco.Cms.Core.PropertyEditors // value is unchanged. if (string.IsNullOrWhiteSpace(editorFile) && string.IsNullOrWhiteSpace(currentPath) == false) { - _mediaFileSystem.DeleteFile(currentPath); + _mediaFileManager.FileSystem.DeleteFile(currentPath); return null; // clear } @@ -100,11 +100,11 @@ namespace Umbraco.Cms.Core.PropertyEditors // remove current file if replaced if (currentPath != filepath && string.IsNullOrWhiteSpace(currentPath) == false) - _mediaFileSystem.DeleteFile(currentPath); + _mediaFileManager.FileSystem.DeleteFile(currentPath); // update json and return if (editorFile == null) return null; - return filepath == null ? string.Empty : _mediaFileSystem.GetUrl(filepath); + return filepath == null ? string.Empty : _mediaFileManager.FileSystem.GetUrl(filepath); } @@ -118,14 +118,14 @@ namespace Umbraco.Cms.Core.PropertyEditors // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) - var filepath = _mediaFileSystem.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path + var filepath = _mediaFileManager.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { // 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 - _mediaFileSystem.AddFile(filepath, filestream, true); // must overwrite! + _mediaFileManager.FileSystem.AddFile(filepath, filestream, true); // must overwrite! } return filepath; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index e138e98618..fe66a31e13 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Core.PropertyEditors INotificationHandler, INotificationHandler, INotificationHandler { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ContentSettings _contentSettings; private readonly IDataTypeService _dataTypeService; private readonly IIOHelper _ioHelper; @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// public ImageCropperPropertyEditor( ILoggerFactory loggerFactory, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IOptions contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, @@ -62,7 +62,7 @@ namespace Umbraco.Cms.Core.PropertyEditors IContentService contentService) : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer) { - _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + _mediaFileManager = mediaFileManager ?? throw new ArgumentNullException(nameof(mediaFileManager)); _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); @@ -86,7 +86,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// Creates the corresponding property value editor. /// /// The corresponding property value editor. - protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, LoggerFactory.CreateLogger(), _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings, JsonSerializer); + protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, LoggerFactory.CreateLogger(), _mediaFileManager, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings, JsonSerializer); /// /// Creates the corresponding preValue editor. @@ -151,11 +151,11 @@ namespace Umbraco.Cms.Core.PropertyEditors { //check if the published value contains data and return it var src = GetFileSrcFromPropertyValue(propertyValue.PublishedValue, out var _); - if (src != null) yield return _mediaFileSystem.GetRelativePath(src); + if (src != null) yield return _mediaFileManager.FileSystem.GetRelativePath(src); //check if the edited value contains data and return it src = GetFileSrcFromPropertyValue(propertyValue.EditedValue, out var _); - if (src != null) yield return _mediaFileSystem.GetRelativePath(src); + if (src != null) yield return _mediaFileManager.FileSystem.GetRelativePath(src); } } @@ -174,7 +174,7 @@ namespace Umbraco.Cms.Core.PropertyEditors deserializedValue = GetJObject(str, true); if (deserializedValue?["src"] == null) return null; var src = deserializedValue["src"].Value(); - return relative ? _mediaFileSystem.GetRelativePath(src) : src; + return relative ? _mediaFileManager.FileSystem.GetRelativePath(src) : src; } /// @@ -198,9 +198,9 @@ namespace Umbraco.Cms.Core.PropertyEditors { continue; } - var sourcePath = _mediaFileSystem.GetRelativePath(src); - var copyPath = _mediaFileSystem.CopyFile(notification.Copy, property.PropertyType, sourcePath); - jo["src"] = _mediaFileSystem.GetUrl(copyPath); + var sourcePath = _mediaFileManager.FileSystem.GetRelativePath(src); + var copyPath = _mediaFileManager.CopyFile(notification.Copy, property.PropertyType, sourcePath); + jo["src"] = _mediaFileManager.FileSystem.GetUrl(copyPath); notification.Copy.SetValue(property.Alias, jo.ToString(), propertyValue.Culture, propertyValue.Segment); isUpdated = true; } @@ -221,7 +221,7 @@ namespace Umbraco.Cms.Core.PropertyEditors private void DeleteContainedFiles(IEnumerable deletedEntities) { var filePathsToDelete = ContainedFilePaths(deletedEntities); - _mediaFileSystem.DeleteMediaFiles(filePathsToDelete); + _mediaFileManager.DeleteMediaFiles(filePathsToDelete); } public void Handle(MediaSavingNotification notification) @@ -282,7 +282,7 @@ namespace Umbraco.Cms.Core.PropertyEditors if (src == null) _autoFillProperties.Reset(model, autoFillConfig, pvalue.Culture, pvalue.Segment); else - _autoFillProperties.Populate(model, autoFillConfig, _mediaFileSystem.GetRelativePath(src), pvalue.Culture, pvalue.Segment); + _autoFillProperties.Populate(model, autoFillConfig, _mediaFileManager.FileSystem.GetRelativePath(src), pvalue.Culture, pvalue.Segment); } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 5cbbdf8e31..19fceb21e5 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -24,13 +24,13 @@ namespace Umbraco.Cms.Core.PropertyEditors internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core vs web? { private readonly ILogger _logger; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ContentSettings _contentSettings; public ImageCropperPropertyValueEditor( DataEditorAttribute attribute, ILogger logger, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.PropertyEditors : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, jsonSerializer, attribute) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + _mediaFileManager = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); } @@ -97,7 +97,7 @@ namespace Umbraco.Cms.Core.PropertyEditors _logger.LogWarning(ex, "Could not parse current db value to a JObject."); } if (string.IsNullOrWhiteSpace(currentPath) == false) - currentPath = _mediaFileSystem.GetRelativePath(currentPath); + currentPath = _mediaFileManager.FileSystem.GetRelativePath(currentPath); // get the new json and path JObject editorJson = null; @@ -130,7 +130,7 @@ namespace Umbraco.Cms.Core.PropertyEditors // value is unchanged. if (string.IsNullOrWhiteSpace(editorFile) && string.IsNullOrWhiteSpace(currentPath) == false) { - _mediaFileSystem.DeleteFile(currentPath); + _mediaFileManager.FileSystem.DeleteFile(currentPath); return null; // clear } @@ -146,11 +146,11 @@ namespace Umbraco.Cms.Core.PropertyEditors // remove current file if replaced if (currentPath != filepath && string.IsNullOrWhiteSpace(currentPath) == false) - _mediaFileSystem.DeleteFile(currentPath); + _mediaFileManager.FileSystem.DeleteFile(currentPath); // update json and return if (editorJson == null) return null; - editorJson["src"] = filepath == null ? string.Empty : _mediaFileSystem.GetUrl(filepath); + editorJson["src"] = filepath == null ? string.Empty : _mediaFileManager.FileSystem.GetUrl(filepath); return editorJson.ToString(); } @@ -163,14 +163,14 @@ namespace Umbraco.Cms.Core.PropertyEditors // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) - var filepath = _mediaFileSystem.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path + var filepath = _mediaFileManager.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { // 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 - _mediaFileSystem.AddFile(filepath, filestream, true); // must overwrite! + _mediaFileManager.FileSystem.AddFile(filepath, filestream, true); // must overwrite! } return filepath; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index 94140d00f2..f92b2911dd 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -27,21 +27,30 @@ namespace Umbraco.Cms.Core.PropertyEditors private readonly IHostingEnvironment _hostingEnvironment; private readonly IMediaService _mediaService; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly IShortStringHelper _shortStringHelper; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IJsonSerializer _serializer; const string TemporaryImageDataAttribute = "data-tmpimg"; - public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IHostingEnvironment hostingEnvironment, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IPublishedUrlProvider publishedUrlProvider, IJsonSerializer serializer) + public RichTextEditorPastedImages( + IUmbracoContextAccessor umbracoContextAccessor, + ILogger logger, + IHostingEnvironment hostingEnvironment, + IMediaService mediaService, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + MediaFileManager mediaFileManager, + IShortStringHelper shortStringHelper, + IPublishedUrlProvider publishedUrlProvider, + IJsonSerializer serializer) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _hostingEnvironment = hostingEnvironment; _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider ?? throw new ArgumentNullException(nameof(contentTypeBaseServiceProvider)); - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _shortStringHelper = shortStringHelper; _publishedUrlProvider = publishedUrlProvider; _serializer = serializer; @@ -98,7 +107,7 @@ namespace Umbraco.Cms.Core.PropertyEditors if (fileStream == null) throw new InvalidOperationException("Could not acquire file stream"); using (fileStream) { - mediaFile.SetValue(_mediaFileSystem, _shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File, safeFileName, fileStream); + mediaFile.SetValue(_mediaFileManager, _shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File, safeFileName, fileStream); } _mediaService.Save(mediaFile, userId); diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 386bd7c06e..9d58cab2b4 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Core.Scoping { private readonly ScopeProvider _scopeProvider; private readonly CoreDebugSettings _coreDebugSettings; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly IEventAggregator _eventAggregator; private readonly ILogger _logger; @@ -55,7 +55,7 @@ namespace Umbraco.Cms.Core.Scoping private Scope( ScopeProvider scopeProvider, CoreDebugSettings coreDebugSettings, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IEventAggregator eventAggregator, ILogger logger, FileSystems fileSystems, @@ -71,7 +71,7 @@ namespace Umbraco.Cms.Core.Scoping { _scopeProvider = scopeProvider; _coreDebugSettings = coreDebugSettings; - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _eventAggregator = eventAggregator; _logger = logger; @@ -163,7 +163,7 @@ namespace Umbraco.Cms.Core.Scoping public Scope( ScopeProvider scopeProvider, CoreDebugSettings coreDebugSettings, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IEventAggregator eventAggregator, ILogger logger, FileSystems fileSystems, @@ -175,14 +175,14 @@ namespace Umbraco.Cms.Core.Scoping bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) - : this(scopeProvider, coreDebugSettings, mediaFileSystem, eventAggregator, logger, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) + : this(scopeProvider, coreDebugSettings, mediaFileManager, eventAggregator, logger, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } // initializes a new scope in a nested scopes chain, with its parent public Scope( ScopeProvider scopeProvider, CoreDebugSettings coreDebugSettings, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IEventAggregator eventAggregator, ILogger logger, FileSystems fileSystems, @@ -193,7 +193,7 @@ namespace Umbraco.Cms.Core.Scoping bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) - : this(scopeProvider, coreDebugSettings, mediaFileSystem, eventAggregator, logger, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) + : this(scopeProvider, coreDebugSettings, mediaFileManager, eventAggregator, logger, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } public Guid InstanceId { get; } = Guid.NewGuid(); @@ -397,7 +397,7 @@ namespace Umbraco.Cms.Core.Scoping return ParentScope.Events; } - return _eventDispatcher ??= new QueuingEventDispatcher(_mediaFileSystem); + return _eventDispatcher ??= new QueuingEventDispatcher(_mediaFileManager); } } diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index c9e8b39947..cc365beb9b 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -29,19 +29,19 @@ namespace Umbraco.Cms.Core.Scoping private readonly IRequestCache _requestCache; private readonly FileSystems _fileSystems; private readonly CoreDebugSettings _coreDebugSettings; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private static readonly AsyncLocal> s_scopeStack = new AsyncLocal>(); private static readonly AsyncLocal> s_scopeContextStack = new AsyncLocal>(); private static readonly string s_scopeItemKey = typeof(Scope).FullName; private static readonly string s_contextItemKey = typeof(ScopeProvider).FullName; private readonly IEventAggregator _eventAggregator; - public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, IOptions coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ILoggerFactory loggerFactory, IRequestCache requestCache, IEventAggregator eventAggregator) + public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, IOptions coreDebugSettings, MediaFileManager mediaFileManager, ILogger logger, ILoggerFactory loggerFactory, IRequestCache requestCache, IEventAggregator eventAggregator) { DatabaseFactory = databaseFactory; _fileSystems = fileSystems; _coreDebugSettings = coreDebugSettings.Value; - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _logger = logger; _loggerFactory = loggerFactory; _requestCache = requestCache; @@ -381,7 +381,7 @@ namespace Umbraco.Cms.Core.Scoping RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null) - => new Scope(this, _coreDebugSettings, _mediaFileSystem, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); + => new Scope(this, _coreDebugSettings, _mediaFileManager, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); /// public void AttachScope(IScope other, bool callContext = false) @@ -460,7 +460,7 @@ namespace Umbraco.Cms.Core.Scoping { IScopeContext ambientContext = AmbientContext; ScopeContext newContext = ambientContext == null ? new ScopeContext() : null; - var scope = new Scope(this, _coreDebugSettings, _mediaFileSystem, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var scope = new Scope(this, _coreDebugSettings, _mediaFileManager, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); // assign only if scope creation did not throw! PushAmbientScope(scope); if (newContext != null) @@ -470,7 +470,7 @@ namespace Umbraco.Cms.Core.Scoping return scope; } - var nested = new Scope(this, _coreDebugSettings, _mediaFileSystem, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var nested = new Scope(this, _coreDebugSettings, _mediaFileManager, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); PushAmbientScope(nested); return nested; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs index 831cbb1b01..3f12d94cf1 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs @@ -29,16 +29,16 @@ namespace Umbraco.Cms.Core.Services.Implement private readonly IEntityRepository _entityRepository; private readonly IShortStringHelper _shortStringHelper; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; #region Constructors - public MediaService(IScopeProvider provider, IMediaFileSystem mediaFileSystem, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, + public MediaService(IScopeProvider provider, MediaFileManager mediaFileManager, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMediaRepository mediaRepository, IAuditRepository auditRepository, IMediaTypeRepository mediaTypeRepository, IEntityRepository entityRepository, IShortStringHelper shortStringHelper) : base(provider, loggerFactory, eventMessagesFactory) { - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _mediaRepository = mediaRepository; _auditRepository = auditRepository; _mediaTypeRepository = mediaTypeRepository; @@ -1183,12 +1183,12 @@ namespace Umbraco.Cms.Core.Services.Implement public Stream GetMediaFileContentStream(string filepath) { - if (_mediaFileSystem.FileExists(filepath) == false) + if (_mediaFileManager.FileSystem.FileExists(filepath) == false) return null; try { - return _mediaFileSystem.OpenFile(filepath); + return _mediaFileManager.FileSystem.OpenFile(filepath); } catch { @@ -1198,17 +1198,17 @@ namespace Umbraco.Cms.Core.Services.Implement public void SetMediaFileContent(string filepath, Stream stream) { - _mediaFileSystem.AddFile(filepath, stream, true); + _mediaFileManager.FileSystem.AddFile(filepath, stream, true); } public void DeleteMediaFile(string filepath) { - _mediaFileSystem.DeleteFile(filepath); + _mediaFileManager.FileSystem.DeleteFile(filepath); } public long GetMediaFileSize(string filepath) { - return _mediaFileSystem.GetSize(filepath); + return _mediaFileManager.FileSystem.GetSize(filepath); } #endregion diff --git a/src/Umbraco.Tests.Common/TestHelpers/FileSystemsCreator.cs b/src/Umbraco.Tests.Common/TestHelpers/FileSystemsCreator.cs new file mode 100644 index 0000000000..d9d5de1ebd --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelpers/FileSystemsCreator.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; + +namespace Umbraco.Cms.Tests.Common.TestHelpers +{ + public static class FileSystemsCreator + { + /// + /// Create an instance FileSystems where you can set the individual filesystems. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static FileSystems CreateTestFileSystems( + ILoggerFactory loggerFactory, + IIOHelper ioHelper, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IFileSystem macroPartialFileSystem, + IFileSystem partialViewsFileSystem, + IFileSystem stylesheetFileSystem, + IFileSystem scriptsFileSystem, + IFileSystem mvcViewFileSystem) => + new FileSystems(loggerFactory, ioHelper, globalSettings, hostingEnvironment, macroPartialFileSystem, + partialViewsFileSystem, stylesheetFileSystem, scriptsFileSystem, mvcViewFileSystem); + } +} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs index 358a5fb350..ce361e59b6 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs @@ -19,52 +19,35 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO public class FileSystemsTests : UmbracoIntegrationTest { [Test] - public void Can_Get_MediaFileSystem() + public void Can_Get_MediaFileManager() { - IMediaFileSystem fileSystem = GetRequiredService(); + MediaFileManager fileSystem = GetRequiredService(); Assert.NotNull(fileSystem); } [Test] - public void Can_Get_IMediaFileSystem() + public void MediaFileManager_Is_Singleton() { - IMediaFileSystem fileSystem = GetRequiredService(); - Assert.NotNull(fileSystem); - } - - [Test] - public void IMediaFileSystem_Is_Singleton() - { - IMediaFileSystem fileSystem1 = GetRequiredService(); - IMediaFileSystem fileSystem2 = GetRequiredService(); - Assert.AreSame(fileSystem1, fileSystem2); - } - - [Test] - public void Can_Unwrap_MediaFileSystem() - { - IMediaFileSystem fileSystem = GetRequiredService(); - IFileSystem unwrapped = fileSystem.Unwrap(); - Assert.IsNotNull(unwrapped); - var physical = unwrapped as PhysicalFileSystem; - Assert.IsNotNull(physical); + MediaFileManager fileManager1 = GetRequiredService(); + MediaFileManager fileManager2 = GetRequiredService(); + Assert.AreSame(fileManager1, fileManager2); } [Test] public void Can_Delete_MediaFiles() { - IMediaFileSystem fs = GetRequiredService(); - var ms = new MemoryStream(Encoding.UTF8.GetBytes("test")); - string virtPath = fs.GetMediaPath("file.txt", Guid.NewGuid(), Guid.NewGuid()); - fs.AddFile(virtPath, ms); + MediaFileManager mediaFileManager = GetRequiredService(); + var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes("test")); + string virtualPath = mediaFileManager.GetMediaPath("file.txt", Guid.NewGuid(), Guid.NewGuid()); + mediaFileManager.FileSystem.AddFile(virtualPath, memoryStream); // ~/media/1234/file.txt exists IHostingEnvironment hostingEnvironment = GetRequiredService(); - string physPath = hostingEnvironment.MapPathWebRoot(Path.Combine("media", virtPath)); + string physPath = hostingEnvironment.MapPathWebRoot(Path.Combine("media", virtualPath)); Assert.IsTrue(File.Exists(physPath)); // ~/media/1234/file.txt is gone - fs.DeleteMediaFiles(new[] { virtPath }); + mediaFileManager.DeleteMediaFiles(new[] { virtualPath }); Assert.IsFalse(File.Exists(physPath)); IMediaPathScheme scheme = GetRequiredService(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/ShadowFileSystemTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/ShadowFileSystemTests.cs index 276d7a267e..751430a824 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/ShadowFileSystemTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/ShadowFileSystemTests.cs @@ -35,14 +35,12 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO public void SetUp() { ClearFiles(HostingEnvironment); - FileSystems.ResetShadowId(); } [TearDown] public void TearDown() { ClearFiles(HostingEnvironment); - FileSystems.ResetShadowId(); } private void ClearFiles(IHostingEnvironment hostingEnvironment) @@ -383,13 +381,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/sub/f2.txt")); } - class FS : FileSystemWrapper - { - public FS(IFileSystem innerFileSystem) - : base(innerFileSystem) - { } - } - [Test] public void ShadowScopeComplete() { @@ -403,11 +394,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO var phy = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, path, "ignore"); - var container = Mock.Of(); var globalSettings = Options.Create(new GlobalSettings()); - var fileSystems = new FileSystems(container, Mock.Of>(), loggerFactory, IOHelper, globalSettings, HostingEnvironment) { IsScoped = () => scopedFileSystems }; - var fs = fileSystems.GetFileSystem(phy); - var sw = (ShadowWrapper) fs.InnerFileSystem; + var fileSystems = new FileSystems(loggerFactory, IOHelper, globalSettings, HostingEnvironment) { IsScoped = () => scopedFileSystems }; + var shadowPath = $"x/{Guid.NewGuid().ToString("N").Substring(0, 6)}"; + var sw = (ShadowWrapper)fileSystems.CreateShadowWrapper(phy, shadowPath); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f1.txt", ms); @@ -439,8 +429,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO var typedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/x")); Assert.IsNotNull(typedDir); dirs = Directory.GetDirectories(typedDir); - var suid = fileSystems.Paths[typeof(FS)]; - var scopedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/" + suid)); // this is where files go + var scopedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/" + shadowPath)); // this is where files go Assert.IsNotNull(scopedDir); scope.Dispose(); scopedFileSystems = false; @@ -496,11 +485,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO var phy = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, path, "ignore"); - var container = Mock.Of(); var globalSettings = Options.Create(new GlobalSettings()); - var fileSystems = new FileSystems(container, Mock.Of>(), NullLoggerFactory.Instance, IOHelper, globalSettings, HostingEnvironment) { IsScoped = () => scopedFileSystems }; - var fs = fileSystems.GetFileSystem( phy); - var sw = (ShadowWrapper) fs.InnerFileSystem; + var fileSystems = new FileSystems(NullLoggerFactory.Instance, IOHelper, globalSettings, HostingEnvironment) { IsScoped = () => scopedFileSystems }; + var shadowPath = $"x/{Guid.NewGuid().ToString("N").Substring(0, 6)}"; + var sw = fileSystems.CreateShadowWrapper(phy, shadowPath); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f1.txt", ms); @@ -548,11 +536,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO var phy = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, path, "ignore"); - var container = Mock.Of(); var globalSettings = Options.Create(new GlobalSettings()); - var fileSystems = new FileSystems(container, Mock.Of>(), NullLoggerFactory.Instance, IOHelper, globalSettings, HostingEnvironment) { IsScoped = () => scopedFileSystems }; - var fs = fileSystems.GetFileSystem( phy); - var sw = (ShadowWrapper)fs.InnerFileSystem; + var fileSystems = new FileSystems(NullLoggerFactory.Instance, IOHelper, globalSettings, HostingEnvironment) { IsScoped = () => scopedFileSystems }; + var shadowPath = $"x/{Guid.NewGuid().ToString("N").Substring(0, 6)}"; + var sw = fileSystems.CreateShadowWrapper(phy, shadowPath); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f1.txt", ms); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs index fd27dda811..a72e8c6c55 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -32,7 +32,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos private ContentType _simpleContentType; private ContentType _textpageContentType; - private IFileSystems FileSystems => GetRequiredService(); + private FileSystems FileSystems => GetRequiredService(); private IUmbracoMapper Mapper => GetRequiredService(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index 7857115241..8cf2c8c932 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -49,7 +49,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos private IDataTypeService DataTypeService => GetRequiredService(); - private IFileSystems FileSystems => GetRequiredService(); + private FileSystems FileSystems => GetRequiredService(); private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs index 44947b45cc..b0769f68ed 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/PartialViewRepositoryTests.cs @@ -5,13 +5,15 @@ using System; using System.Collections.Generic; using System.IO; using Microsoft.Extensions.Logging; -using Moq; +using Microsoft.Extensions.Options; using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; +using Umbraco.Cms.Tests.Common.TestHelpers; using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; using Constants = Umbraco.Cms.Core.Constants; @@ -42,8 +44,9 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos public void PathTests() { // unless noted otherwise, no changes / 7.2.8 - IFileSystems fileSystems = Mock.Of(); - Mock.Get(fileSystems).Setup(x => x.PartialViewsFileSystem).Returns(_fileSystem); + FileSystems fileSystems = FileSystemsCreator.CreateTestFileSystems(LoggerFactory, IOHelper, + GetRequiredService>(), HostingEnvironment, + null, _fileSystem, null, null, null); IScopeProvider provider = ScopeProvider; using (IScope scope = provider.CreateScope()) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs index 35e53905a0..001fd89f03 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ScriptRepositoryTest.cs @@ -7,7 +7,7 @@ using System.IO; using System.Linq; using System.Text; using Microsoft.Extensions.Logging; -using Moq; +using Microsoft.Extensions.Options; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; @@ -16,6 +16,7 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; +using Umbraco.Cms.Tests.Common.TestHelpers; using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; @@ -27,16 +28,18 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos { private IHostingEnvironment HostingEnvironment => GetRequiredService(); - private IFileSystems _fileSystems; + private FileSystems _fileSystems; private IFileSystem _fileSystem; [SetUp] public void SetUpFileSystem() { - _fileSystems = Mock.Of(); string path = GlobalSettings.UmbracoScriptsPath; _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, LoggerFactory.CreateLogger(), HostingEnvironment.MapPathWebRoot(path), HostingEnvironment.ToAbsolute(path)); - Mock.Get(_fileSystems).Setup(x => x.ScriptsFileSystem).Returns(_fileSystem); + + _fileSystems = FileSystemsCreator.CreateTestFileSystems(LoggerFactory, IOHelper, GetRequiredService>(), + HostingEnvironment, + null, null, null, _fileSystem, null); using (Stream stream = CreateStream("Umbraco.Sys.registerNamespace(\"Umbraco.Utils\");")) { _fileSystem.AddFile("test-script.js", stream); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs index 6f6d6e3e71..9b2acd17c1 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/StylesheetRepositoryTest.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; using System.Text; using Microsoft.Extensions.Logging; -using Moq; +using Microsoft.Extensions.Options; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; @@ -16,6 +16,7 @@ using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; +using Umbraco.Cms.Tests.Common.TestHelpers; using Umbraco.Cms.Tests.Common.Testing; using Umbraco.Cms.Tests.Integration.Testing; @@ -25,7 +26,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos [UmbracoTest(Database = UmbracoTestOptions.Database.None, Logger = UmbracoTestOptions.Logger.Console)] public class StylesheetRepositoryTest : UmbracoIntegrationTest { - private IFileSystems _fileSystems; + private FileSystems _fileSystems; private IFileSystem _fileSystem; private IHostingEnvironment HostingEnvironment => GetRequiredService(); @@ -33,10 +34,13 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos [SetUp] public void SetUpFileSystem() { - _fileSystems = Mock.Of(); string path = HostingEnvironment.MapPathWebRoot(GlobalSettings.UmbracoCssPath); _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, GetRequiredService>(), path, "/css"); - Mock.Get(_fileSystems).Setup(x => x.StylesheetsFileSystem).Returns(_fileSystem); + + _fileSystems = FileSystemsCreator.CreateTestFileSystems(LoggerFactory, IOHelper, GetRequiredService>(), + HostingEnvironment, + null, null, _fileSystem, null, null); + Stream stream = CreateStream("body {background:#EE7600; color:#FFF;}"); _fileSystem.AddFile("styles.css", stream); } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index 7b4150c897..646367c99a 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -36,7 +36,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repos { private IHostingEnvironment HostingEnvironment => GetRequiredService(); - private IFileSystems FileSystems => GetRequiredService(); + private FileSystems FileSystems => GetRequiredService(); private ITemplateRepository CreateRepository(IScopeProvider provider) => new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeFileSystemsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeFileSystemsTests.cs index f96852faeb..4fb20cde98 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeFileSystemsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeFileSystemsTests.cs @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping [UmbracoTest(Database = UmbracoTestOptions.Database.NewEmptyPerTest)] public class ScopeFileSystemsTests : UmbracoIntegrationTest { - private IMediaFileSystem MediaFileSystem => GetRequiredService(); + private MediaFileManager MediaFileManager => GetRequiredService(); private IHostingEnvironment HostingEnvironment => GetRequiredService(); @@ -35,7 +35,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping [TearDown] public void Teardown() { - FileSystems.ResetShadowId(); ClearFiles(IOHelper); } @@ -47,12 +46,12 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping } [Test] - public void MediaFileSystem_does_not_write_to_physical_file_system_when_scoped_if_scope_does_not_complete() + public void MediaFileManager_does_not_write_to_physical_file_system_when_scoped_if_scope_does_not_complete() { string rootPath = HostingEnvironment.MapPathWebRoot(GlobalSettings.UmbracoMediaPath); string rootUrl = HostingEnvironment.ToAbsolute(GlobalSettings.UmbracoMediaPath); var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, GetRequiredService>(), rootPath, rootUrl); - IMediaFileSystem mediaFileSystem = MediaFileSystem; + MediaFileManager mediaFileManager = MediaFileManager; Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); @@ -60,28 +59,28 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping { using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) { - mediaFileSystem.AddFile("f1.txt", ms); + MediaFileManager.FileSystem.AddFile("f1.txt", ms); } - Assert.IsTrue(mediaFileSystem.FileExists("f1.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); - Assert.IsTrue(mediaFileSystem.FileExists("f1.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); } // After scope is disposed ensure shadow wrapper didn't commit to physical - Assert.IsFalse(MediaFileSystem.FileExists("f1.txt")); + Assert.IsFalse(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); } [Test] - public void MediaFileSystem_writes_to_physical_file_system_when_scoped_and_scope_is_completed() + public void MediaFileManager_writes_to_physical_file_system_when_scoped_and_scope_is_completed() { string rootPath = HostingEnvironment.MapPathWebRoot(GlobalSettings.UmbracoMediaPath); string rootUrl = HostingEnvironment.ToAbsolute(GlobalSettings.UmbracoMediaPath); var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, GetRequiredService>(), rootPath, rootUrl); - IMediaFileSystem mediaFileSystem = MediaFileSystem; + MediaFileManager mediaFileManager = MediaFileManager; Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); @@ -89,20 +88,20 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping { using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) { - mediaFileSystem.AddFile("f1.txt", ms); + mediaFileManager.FileSystem.AddFile("f1.txt", ms); } - Assert.IsTrue(mediaFileSystem.FileExists("f1.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); scope.Complete(); - Assert.IsTrue(mediaFileSystem.FileExists("f1.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); } // After scope is disposed ensure shadow wrapper writes to physical file system - Assert.IsTrue(MediaFileSystem.FileExists("f1.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsTrue(physMediaFileSystem.FileExists("f1.txt")); } @@ -112,7 +111,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping string rootPath = HostingEnvironment.MapPathWebRoot(GlobalSettings.UmbracoMediaPath); string rootUrl = HostingEnvironment.ToAbsolute(GlobalSettings.UmbracoMediaPath); var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, GetRequiredService>(), rootPath, rootUrl); - IMediaFileSystem mediaFileSystem = MediaFileSystem; + MediaFileManager mediaFileManager = MediaFileManager; var taskHelper = new TaskHelper(Mock.Of>()); IScopeProvider scopeProvider = ScopeProvider; @@ -120,23 +119,23 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping { using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) { - mediaFileSystem.AddFile("f1.txt", ms); + mediaFileManager.FileSystem.AddFile("f1.txt", ms); } - Assert.IsTrue(mediaFileSystem.FileExists("f1.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f1.txt")); Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); // execute on another disconnected thread (execution context will not flow) Task t = taskHelper.ExecuteBackgroundTask(() => { - Assert.IsFalse(mediaFileSystem.FileExists("f1.txt")); + Assert.IsFalse(mediaFileManager.FileSystem.FileExists("f1.txt")); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) { - mediaFileSystem.AddFile("f2.txt", ms); + mediaFileManager.FileSystem.AddFile("f2.txt", ms); } - Assert.IsTrue(mediaFileSystem.FileExists("f2.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f2.txt")); Assert.IsTrue(physMediaFileSystem.FileExists("f2.txt")); return Task.CompletedTask; @@ -144,7 +143,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping Task.WaitAll(t); - Assert.IsTrue(mediaFileSystem.FileExists("f2.txt")); + Assert.IsTrue(mediaFileManager.FileSystem.FileExists("f2.txt")); Assert.IsTrue(physMediaFileSystem.FileExists("f2.txt")); } } @@ -170,7 +169,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping // not ok to create a 'scoped filesystems' other scope // we will get a "Already shadowing." exception. Assert.Throws(() => - { + { using IScope other = scopeProvider.CreateScope(scopeFileSystems: true); }); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index e1a65d1541..44eabbac6f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -22,6 +22,7 @@ using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.Mappers; @@ -48,11 +49,12 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components var connectionStrings = new ConnectionStrings(); var f = new UmbracoDatabaseFactory(loggerFactory.CreateLogger(), loggerFactory, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.DbProviderFactoryCreator, new DatabaseSchemaCreatorFactory(loggerFactory.CreateLogger(), loggerFactory, new UmbracoVersion(), Mock.Of())); - var fs = new FileSystems(mock.Object, loggerFactory.CreateLogger(), loggerFactory, IOHelper, Options.Create(globalSettings), Mock.Of()); + var fs = new FileSystems(loggerFactory, IOHelper, Options.Create(globalSettings), Mock.Of()); var coreDebug = new CoreDebugSettings(); - IMediaFileSystem mediaFileSystem = Mock.Of(); + MediaFileManager mediaFileManager = new MediaFileManager(Mock.Of(), + Mock.Of(), Mock.Of>(), Mock.Of()); IEventAggregator eventAggregator = Mock.Of(); - var p = new ScopeProvider(f, fs, Options.Create(coreDebug), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance, eventAggregator); + var p = new ScopeProvider(f, fs, Options.Create(coreDebug), mediaFileManager, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance, eventAggregator); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(logger); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(loggerFactory.CreateLogger); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopeEventDispatcherTests.cs index 43d14677fa..9820bef8c2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopeEventDispatcherTests.cs @@ -13,6 +13,7 @@ using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Tests.Common.Builders; @@ -73,18 +74,19 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Scoping private ScopeProvider GetScopeProvider(NullLoggerFactory instance) { var fileSystems = new FileSystems( - Mock.Of(), - Mock.Of>(), instance, Mock.Of(), Options.Create(new GlobalSettings()), Mock.Of()); + var mediaFileManager = new MediaFileManager(Mock.Of(), Mock.Of(), + instance.CreateLogger(), Mock.Of()); + return new ScopeProvider( Mock.Of(), fileSystems, Options.Create(new CoreDebugSettings()), - Mock.Of(), + mediaFileManager, Mock.Of>(), instance, Mock.Of(), diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs index 8bfced3b61..6995be88b7 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs @@ -14,6 +14,7 @@ using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; @@ -30,7 +31,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Scoping private ScopeProvider GetScopeProvider(out Mock syntaxProviderMock) { var loggerFactory = NullLoggerFactory.Instance; - var fileSystem = new FileSystems(Mock.Of(), loggerFactory.CreateLogger(), loggerFactory, Mock.Of(), Mock.Of>(), Mock.Of()); + var fileSystems = new FileSystems(loggerFactory, + Mock.Of(), Mock.Of>(), Mock.Of()); + var mediaFileManager = new MediaFileManager(Mock.Of(), Mock.Of(), + loggerFactory.CreateLogger(), Mock.Of()); var databaseFactory = new Mock(); var database = new Mock(); var sqlContext = new Mock(); @@ -47,9 +51,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Scoping return new ScopeProvider( databaseFactory.Object, - fileSystem, + fileSystems, Options.Create(new CoreDebugSettings()), - Mock.Of(), + mediaFileManager, loggerFactory.CreateLogger(), loggerFactory, Mock.Of(), diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index bb26b2e70e..fbcfdb91ed 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -3,6 +3,7 @@ using System.Xml.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; @@ -35,8 +36,9 @@ namespace Umbraco.Tests.Models var scheme = Mock.Of(); var contentSettings = new ContentSettings(); - var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, loggerFactory.CreateLogger(), ShortStringHelper); - var ignored = new FileUploadPropertyEditor(loggerFactory, mediaFileSystem, Microsoft.Extensions.Options.Options.Create(contentSettings), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties, JsonNetSerializer, ContentService); + var mediaFileManager = new MediaFileManager(Mock.Of(), scheme, + loggerFactory.CreateLogger(), ShortStringHelper); + var ignored = new FileUploadPropertyEditor(loggerFactory, mediaFileManager, Microsoft.Extensions.Options.Options.Create(contentSettings), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties, JsonNetSerializer, ContentService); var media = MockedMedia.CreateMediaImage(mediaType, -1); media.WriterId = -1; // else it's zero and that's not a user and it breaks the tests diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index c285deee65..53b8666889 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -13,6 +13,7 @@ using Umbraco.Cms.Core.PropertyEditors.ValueConverters; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Core.Templates; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Serialization; @@ -50,7 +51,9 @@ namespace Umbraco.Tests.PublishedContent var serializer = new ConfigurationEditorJsonSerializer(); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), HostingEnvironment, Mock.Of(), Mock.Of(), Mock.Of(), ShortStringHelper, publishedUrlProvider, serializer); + var mediaFileManager = new MediaFileManager(Mock.Of(), Mock.Of(), + loggerFactory.CreateLogger(), Mock.Of()); + var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), HostingEnvironment, Mock.Of(), Mock.Of(), mediaFileManager, ShortStringHelper, publishedUrlProvider, serializer); var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new RichTextPropertyEditor( diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 1179887e32..1cb238b0c2 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -51,13 +51,14 @@ namespace Umbraco.Tests.PublishedContent var loggerFactory = NullLoggerFactory.Instance; var mediaService = Mock.Of(); - var mediaFileService = Mock.Of(); var contentTypeBaseServiceProvider = Mock.Of(); var umbracoContextAccessor = Mock.Of(); var backOfficeSecurityAccessor = Mock.Of(); var publishedUrlProvider = Mock.Of(); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); var serializer = new ConfigurationEditorJsonSerializer(); + var mediaFileService = new MediaFileManager(Mock.Of(), Mock.Of(), + loggerFactory.CreateLogger(), Mock.Of()); var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), HostingEnvironment, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider, serializer); var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var localizationService = Mock.Of(); diff --git a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs index 7149938b39..d6b7b58c15 100644 --- a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs @@ -13,6 +13,7 @@ using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PropertyEditors.ValueConverters; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Tests.Common; using Umbraco.Cms.Tests.Common.Testing; @@ -33,13 +34,14 @@ namespace Umbraco.Tests.Routing base.SetUp(); var loggerFactory = NullLoggerFactory.Instance; - var mediaFileSystemMock = Mock.Of(); + var mediaFileManager = new MediaFileManager(Mock.Of(), Mock.Of(), + loggerFactory.CreateLogger(), Mock.Of()); var contentSettings = new ContentSettings(); var dataTypeService = Mock.Of(); var propertyEditors = new MediaUrlGeneratorCollection(new IMediaUrlGenerator[] { - new FileUploadPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties, JsonNetSerializer, ContentService), - new ImageCropperPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, UploadAutoFillProperties, JsonNetSerializer, ContentService), + new FileUploadPropertyEditor(loggerFactory, mediaFileManager, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties, JsonNetSerializer, ContentService), + new ImageCropperPropertyEditor(loggerFactory, mediaFileManager, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, UploadAutoFillProperties, JsonNetSerializer, ContentService), }); _mediaUrlProvider = new DefaultMediaUrlProvider(propertyEditors, UriUtility); } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 94b4f5500b..1f32e73916 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Linq.Expressions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; using Umbraco.Cms.Core; @@ -18,6 +19,7 @@ using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Persistence.SqlCe; using Umbraco.Cms.Tests.Common; +using Umbraco.Cms.Tests.Common.TestHelpers; using Umbraco.Extensions; using Umbraco.Web; @@ -142,25 +144,23 @@ namespace Umbraco.Tests.TestHelpers { return new GlobalSettings(); } - public IFileSystems GetFileSystemsMock() + public FileSystems GetFileSystemsMock() { - var fileSystems = Mock.Of(); - - MockFs(fileSystems, x => x.MacroPartialsFileSystem); - MockFs(fileSystems, x => x.MvcViewsFileSystem); - MockFs(fileSystems, x => x.PartialViewsFileSystem); - MockFs(fileSystems, x => x.ScriptsFileSystem); - MockFs(fileSystems, x => x.StylesheetsFileSystem); + var fileSystems = FileSystemsCreator.CreateTestFileSystems( + NullLoggerFactory.Instance, + Mock.Of(), + Mock.Of>(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of() + ); return fileSystems; } - private void MockFs(IFileSystems fileSystems, Expression> fileSystem) - { - var fs = Mock.Of(); - Mock.Get(fileSystems).Setup(fileSystem).Returns(fs); - } - #region Inner classes private class MockDbConnection : DbConnection diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 524644874c..6f7fcfe2dd 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -84,11 +84,11 @@ namespace Umbraco.Tests.TestHelpers new DatabaseSchemaCreatorFactory(Mock.Of>(),loggerFactory, new UmbracoVersion(), Mock.Of())); } - fileSystems ??= new FileSystems(Current.Factory, loggerFactory.CreateLogger(), loggerFactory, TestHelper.IOHelper, globalSettings, TestHelper.GetHostingEnvironment()); + fileSystems ??= new FileSystems(loggerFactory, TestHelper.IOHelper, globalSettings, TestHelper.GetHostingEnvironment()); var coreDebug = TestHelper.CoreDebugSettings; - var mediaFileSystem = Mock.Of(); + var mediaFileManager = Mock.Of(); var eventAggregator = Mock.Of(); - return new ScopeProvider(databaseFactory, fileSystems, Options.Create(coreDebugSettings), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance, eventAggregator); + return new ScopeProvider(databaseFactory, fileSystems, Options.Create(coreDebugSettings), mediaFileManager, loggerFactory.CreateLogger(), loggerFactory, NoAppCache.Instance, eventAggregator); } } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index a33b3f6c10..243e92ad53 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Serilog; @@ -462,8 +463,8 @@ namespace Umbraco.Tests.Testing var scheme = Mock.Of(); - var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, _loggerFactory.CreateLogger(), TestHelper.ShortStringHelper); - Builder.Services.AddUnique(factory => mediaFileSystem); + var mediaFileManager = new MediaFileManager(Mock.Of(), scheme, Mock.Of>(), Mock.Of()); + Builder.Services.AddUnique(factory => mediaFileManager); // no factory (noop) Builder.Services.AddUnique(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs index 710fb5aeb8..822f5a4911 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public class CodeFileController : BackOfficeNotificationsController { private readonly IHostingEnvironment _hostingEnvironment; - private readonly IFileSystems _fileSystems; + private readonly FileSystems _fileSystems; private readonly IFileService _fileService; private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public CodeFileController( IHostingEnvironment hostingEnvironment, - IFileSystems fileSystems, + FileSystems fileSystems, IFileService fileService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ILocalizedTextService localizedTextService, diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 080f84009a..49bff529bd 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -39,7 +39,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class CurrentUserController : UmbracoAuthorizedJsonController { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ContentSettings _contentSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IImageUrlGenerator _imageUrlGenerator; @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers private readonly IPasswordChanger _passwordChanger; public CurrentUserController( - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IOptions contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, @@ -68,7 +68,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers IShortStringHelper shortStringHelper, IPasswordChanger passwordChanger) { - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _contentSettings = contentSettings.Value; _hostingEnvironment = hostingEnvironment; _imageUrlGenerator = imageUrlGenerator; @@ -210,7 +210,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public IActionResult PostSetAvatar(IList file) { //borrow the logic from the user controller - return UsersController.PostSetAvatarInternal(file, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0)); + return UsersController.PostSetAvatarInternal(file, _userService, _appCaches.RuntimeCache, _mediaFileManager, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0)); } /// diff --git a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs index 8b9ab5652c..24135bcbe6 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs @@ -16,14 +16,14 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class ImagesController : UmbracoAuthorizedApiController { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly IImageUrlGenerator _imageUrlGenerator; public ImagesController( - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IImageUrlGenerator imageUrlGenerator) { - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _imageUrlGenerator = imageUrlGenerator; } @@ -63,7 +63,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers DateTimeOffset? imageLastModified = null; try { - imageLastModified = _mediaFileSystem.GetLastModified(imagePath); + imageLastModified = _mediaFileManager.FileSystem.GetLastModified(imagePath); } catch (Exception) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/LogController.cs b/src/Umbraco.Web.BackOffice/Controllers/LogController.cs index 2d8f2fa82b..3c3eaa4eff 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/LogController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/LogController.cs @@ -24,7 +24,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class LogController : UmbracoAuthorizedJsonController { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly IImageUrlGenerator _imageUrlGenerator; private readonly IAuditService _auditService; private readonly IUmbracoMapper _umbracoMapper; @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers private readonly ISqlContext _sqlContext; public LogController( - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileSystem, IImageUrlGenerator imageUrlGenerator, IAuditService auditService, IUmbracoMapper umbracoMapper, @@ -43,7 +43,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers AppCaches appCaches, ISqlContext sqlContext) { - _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); + _mediaFileManager = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator)); _auditService = auditService ?? throw new ArgumentNullException(nameof(auditService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); @@ -111,7 +111,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers { var mappedItems = items.ToList(); var userIds = mappedItems.Select(x => x.UserId).ToArray(); - var userAvatars = Enumerable.ToDictionary(_userService.GetUsersById(userIds), x => x.Id, x => x.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator)); + var userAvatars = Enumerable.ToDictionary(_userService.GetUsersById(userIds), x => x.Id, x => x.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator)); var userNames = Enumerable.ToDictionary(_userService.GetUsersById(userIds), x => x.Id, x => x.Name); foreach (var item in mappedItems) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index 9d176277ec..88114f673c 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -89,7 +89,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IRelationService relationService, PropertyEditorCollection propertyEditors, - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, IJsonSerializer serializer, @@ -110,7 +110,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; _relationService = relationService; _propertyEditors = propertyEditors; - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _hostingEnvironment = hostingEnvironment; _logger = loggerFactory.CreateLogger(); _imageUrlGenerator = imageUrlGenerator; @@ -288,7 +288,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers private int[] _userStartNodes; private readonly PropertyEditorCollection _propertyEditors; - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly IHostingEnvironment _hostingEnvironment; @@ -806,7 +806,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers await using (var stream = formFile.OpenReadStream()) { - f.SetValue(_mediaFileSystem,_shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File,fileName, stream); + f.SetValue(_mediaFileManager,_shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File,fileName, stream); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index 6e7e5f2ed1..2d7418b6bd 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -52,7 +52,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [IsCurrentUserModelFilter] public class UsersController : UmbracoAuthorizedJsonController { - private readonly IMediaFileSystem _mediaFileSystem; + private readonly MediaFileManager _mediaFileManager; private readonly ContentSettings _contentSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly ISqlContext _sqlContext; @@ -75,7 +75,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers private readonly ILogger _logger; public UsersController( - IMediaFileSystem mediaFileSystem, + MediaFileManager mediaFileManager, IOptions contentSettings, IHostingEnvironment hostingEnvironment, ISqlContext sqlContext, @@ -96,7 +96,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers UserEditorAuthorizationHelper userEditorAuthorizationHelper, IPasswordChanger passwordChanger) { - _mediaFileSystem = mediaFileSystem; + _mediaFileManager = mediaFileManager; _contentSettings = contentSettings.Value; _hostingEnvironment = hostingEnvironment; _sqlContext = sqlContext; @@ -125,7 +125,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers /// public ActionResult GetCurrentUserAvatarUrls() { - var urls = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + var urls = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator); if (urls == null) return new ValidationErrorResult("Could not access Gravatar endpoint"); @@ -136,10 +136,10 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)] public IActionResult PostSetAvatar(int id, IList file) { - return PostSetAvatarInternal(file, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, id); + return PostSetAvatarInternal(file, _userService, _appCaches.RuntimeCache, _mediaFileManager, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, id); } - internal static IActionResult PostSetAvatarInternal(IList files, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, ContentSettings contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, int id) + internal static IActionResult PostSetAvatarInternal(IList files, IUserService userService, IAppCache cache, MediaFileManager mediaFileManager, IShortStringHelper shortStringHelper, ContentSettings contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, int id) { if (files is null) { @@ -176,13 +176,13 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers using (var fs = file.OpenReadStream()) { - mediaFileSystem.AddFile(user.Avatar, fs, true); + mediaFileManager.FileSystem.AddFile(user.Avatar, fs, true); } userService.Save(user); } - return new OkObjectResult(user.GetUserAvatarUrls(cache, mediaFileSystem, imageUrlGenerator)); + return new OkObjectResult(user.GetUserAvatarUrls(cache, mediaFileManager, imageUrlGenerator)); } [AppendUserModifiedHeader("id")] @@ -212,11 +212,11 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers if (filePath.IsNullOrWhiteSpace() == false) { - if (_mediaFileSystem.FileExists(filePath)) - _mediaFileSystem.DeleteFile(filePath); + if (_mediaFileManager.FileSystem.FileExists(filePath)) + _mediaFileManager.FileSystem.DeleteFile(filePath); } - return found.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + return found.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator); } /// diff --git a/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs index 6403ec009d..96d9004635 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, - IFileSystems fileSystems, + FileSystems fileSystems, IEventAggregator eventAggregator) : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, fileSystems, eventAggregator) { diff --git a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs index ad8b9f16b4..c79175dba8 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, - IFileSystems fileSystems, + FileSystems fileSystems, IEventAggregator eventAggregator) : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator) { diff --git a/src/Umbraco.Web.BackOffice/Trees/ScriptsTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ScriptsTreeController.cs index 56f1b0ac1d..89e767c124 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ScriptsTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ScriptsTreeController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, - IFileSystems fileSystems, + FileSystems fileSystems, IEventAggregator eventAggregator) : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator) { diff --git a/src/Umbraco.Web.BackOffice/Trees/StylesheetsTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/StylesheetsTreeController.cs index 18d1be6a67..08dd8f2cde 100644 --- a/src/Umbraco.Web.BackOffice/Trees/StylesheetsTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/StylesheetsTreeController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, - IFileSystems fileSystems, + FileSystems fileSystems, IEventAggregator eventAggregator) : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, eventAggregator) { diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 0863d843fa..6240ba27bb 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -144,7 +144,7 @@ namespace Umbraco.Web.Composing // proxy Core for convenience - public static IMediaFileSystem MediaFileSystem => Factory.GetRequiredService(); + public static MediaFileManager MediaFileManager => Factory.GetRequiredService(); public static UmbracoMapper Mapper => Factory.GetRequiredService();