diff --git a/src/Umbraco.Core/IO/FileSystemExtensions.cs b/src/Umbraco.Core/IO/FileSystemExtensions.cs index 78f39466f8..a4a40d37ba 100644 --- a/src/Umbraco.Core/IO/FileSystemExtensions.cs +++ b/src/Umbraco.Core/IO/FileSystemExtensions.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.IO @@ -30,5 +31,17 @@ namespace Umbraco.Core.IO { return Path.GetFileName(fs.GetFullPath(path)); } + + //TODO: Currently this is the only way to do this + internal static void CreateFolder(this IFileSystem fs, string folderPath) + { + var path = fs.GetRelativePath(folderPath); + var tempFile = Path.Combine(path, Guid.NewGuid().ToString("N") + ".tmp"); + using (var s = new MemoryStream()) + { + fs.AddFile(tempFile, s); + } + fs.DeleteFile(tempFile); + } } } diff --git a/src/Umbraco.Core/IO/IFileSystem.cs b/src/Umbraco.Core/IO/IFileSystem.cs index 8e1753da6d..113f63565c 100644 --- a/src/Umbraco.Core/IO/IFileSystem.cs +++ b/src/Umbraco.Core/IO/IFileSystem.cs @@ -5,6 +5,8 @@ using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.IO { + //TODO: There is no way to create a directory here without creating a file in a directory and then deleting it + public interface IFileSystem { IEnumerable GetDirectories(string path); diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs index 978e54390f..f520b63210 100644 --- a/src/Umbraco.Core/Models/File.cs +++ b/src/Umbraco.Core/Models/File.cs @@ -6,6 +6,16 @@ using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Models { + internal sealed class Folder : Entity + { + public Folder(string folderPath) + { + Path = folderPath; + } + + public string Path { get; set; } + } + /// /// Represents an abstract file which provides basic functionality for a File with an Alias and Name /// @@ -23,6 +33,8 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo(x => x.Content); private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path); + private string _alias; + private string _name; /// /// Gets or sets the Name of the File including extension @@ -32,7 +44,11 @@ namespace Umbraco.Core.Models { get { - return new FileInfo(Path).Name; + if (_name == null) + { + _name = System.IO.Path.GetFileName(Path); + } + return _name; } } @@ -44,10 +60,14 @@ namespace Umbraco.Core.Models { get { - var fileInfo = new FileInfo(Path); - var name = fileInfo.Name; - int lastIndexOf = name.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase); - return name.Substring(0, lastIndexOf); + if (_alias == null) + { + var name = System.IO.Path.GetFileName(Path); + if (name == null) return string.Empty; + var lastIndexOf = name.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase); + _alias = name.Substring(0, lastIndexOf); + } + return _alias; } } @@ -60,6 +80,10 @@ namespace Umbraco.Core.Models get { return _path; } set { + //reset + _alias = null; + _name = null; + SetPropertyValueAndDetectChanges(o => { _path = value; diff --git a/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs b/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs index d70aa9510c..cd36f75369 100644 --- a/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs @@ -33,6 +33,16 @@ namespace Umbraco.Core.Persistence.Repositories get { return _fileSystem; } } + internal virtual void AddFolder(string folderPath) + { + _work.RegisterAdded(new Folder(folderPath), this); + } + + internal virtual void DeleteFolder(string folderPath) + { + _work.RegisterRemoved(new Folder(folderPath), this); + } + #region Implementation of IRepository public virtual void AddOrUpdate(TEntity entity) @@ -68,7 +78,16 @@ namespace Umbraco.Core.Persistence.Repositories public void PersistNewItem(IEntity entity) { - PersistNewItem((TEntity)entity); + //special case for folder + var folder = entity as Folder; + if (folder != null) + { + PersistNewFolder(folder); + } + else + { + PersistNewItem((TEntity)entity); + } } public void PersistUpdatedItem(IEntity entity) @@ -78,23 +97,46 @@ namespace Umbraco.Core.Persistence.Repositories public void PersistDeletedItem(IEntity entity) { - PersistDeletedItem((TEntity)entity); + //special case for folder + var folder = entity as Folder; + if (folder != null) + { + PersistDeletedFolder(folder); + } + else + { + PersistDeletedItem((TEntity)entity); + } } #endregion - #region Abstract IUnitOfWorkRepository Methods + internal virtual void PersistNewFolder(Folder entity) + { + _fileSystem.CreateFolder(entity.Path); + } + internal virtual void PersistDeletedFolder(Folder entity) + { + _fileSystem.DeleteDirectory(entity.Path); + } + + #region Abstract IUnitOfWorkRepository Methods + protected virtual void PersistNewItem(TEntity entity) { - var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content)); - FileSystem.AddFile(entity.Name, stream, true); + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content))) + { + FileSystem.AddFile(entity.Path, stream, true); + } } protected virtual void PersistUpdatedItem(TEntity entity) { - var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content)); - FileSystem.AddFile(entity.Name, stream, true); + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content))) + { + FileSystem.AddFile(entity.Path, stream, true); + } } protected virtual void PersistDeletedItem(TEntity entity) diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IScriptRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IScriptRepository.cs index 45bde95b3f..8c675a7d3a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IScriptRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IScriptRepository.cs @@ -4,6 +4,6 @@ namespace Umbraco.Core.Persistence.Repositories { public interface IScriptRepository : IRepository { - + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs index de7dd50223..f6af195b94 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs @@ -28,9 +28,10 @@ namespace Umbraco.Core.Persistence.Repositories public override Script Get(string id) { - if(!FileSystem.FileExists(id)) + if(FileSystem.FileExists(id) == false) { - throw new Exception(string.Format("The file {0} was not found", id)); + return null; + //throw new Exception(string.Format("The file {0} was not found", id)); } string content = string.Empty; diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs index 0de58b7c0f..9fe69a4ca9 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxContext.cs @@ -23,5 +23,4 @@ namespace Umbraco.Core.Persistence.SqlSyntax set { _sqlSyntaxProvider = value; } } } - } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderExtensions.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderExtensions.cs index fedd13dd8d..1fa235720f 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderExtensions.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderExtensions.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Persistence.SqlSyntax +namespace Umbraco.Core.Persistence.SqlSyntax { internal static class SqlSyntaxProviderExtensions { diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index 5d4f2b1da8..848097f6f0 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -4,6 +4,7 @@ using Umbraco.Core.Auditing; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Services @@ -195,6 +196,26 @@ namespace Umbraco.Core.Services return script.IsValid(); } + public void CreateScriptFolder(string folderPath) + { + var uow = _fileUowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateScriptRepository(uow)) + { + ((ScriptRepository)repository).AddFolder(folderPath); + uow.Commit(); + } + } + + public void DeleteScriptFolder(string folderPath) + { + var uow = _fileUowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateScriptRepository(uow)) + { + ((ScriptRepository)repository).DeleteFolder(folderPath); + uow.Commit(); + } + } + /// /// Gets a list of all objects /// diff --git a/src/Umbraco.Core/Services/IFileService.cs b/src/Umbraco.Core/Services/IFileService.cs index 2e1e2eef49..c59f80b2ff 100644 --- a/src/Umbraco.Core/Services/IFileService.cs +++ b/src/Umbraco.Core/Services/IFileService.cs @@ -76,6 +76,19 @@ namespace Umbraco.Core.Services /// True if Script is valid, otherwise false bool ValidateScript(Script script); + /// + /// Creates a folder for scripts + /// + /// + /// + void CreateScriptFolder(string folderPath); + + /// + /// Deletes a folder for scripts + /// + /// + void DeleteScriptFolder(string folderPath); + /// /// Gets a list of all objects /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index de40c4a1c0..ddc3cc2981 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -351,6 +351,7 @@ + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/ScriptTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/ScriptTasks.cs index 0a4b2dc1d3..70231c950c 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/ScriptTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/ScriptTasks.cs @@ -1,6 +1,8 @@ using Umbraco.Core.IO; using Umbraco.Web.UI; +using Umbraco.Core; using Umbraco.Core.Logging; +using Umbraco.Core.Models; using umbraco.BusinessLogic; using umbraco.BasePages; @@ -11,44 +13,43 @@ namespace umbraco public override bool PerformSave() { - string[] scriptFileAr = Alias.Split('\u00A4'); - + var scriptFileAr = _alias.Split('\u00A4'); + var relPath = scriptFileAr[0]; var fileName = scriptFileAr[1]; var fileType = scriptFileAr[2]; - + var createFolder = ParentID; - var basePath = IOHelper.MapPath(SystemDirectories.Scripts + "/" + relPath + fileName); - if (System.IO.File.Exists(basePath)) - { - _returnUrl = string.Format("settings/scripts/editScript.aspx?file={0}{1}.{2}", relPath, fileName, fileType); - return true; - } - if (createFolder == 1) { - System.IO.Directory.CreateDirectory(basePath); + ApplicationContext.Current.Services.FileService.CreateScriptFolder(relPath + fileName); + return true; } - else + + var found = ApplicationContext.Current.Services.FileService.GetScriptByName(relPath + fileName + "." + fileType); + if (found != null) { - System.IO.File.Create(basePath + "." + fileType).Close(); - _returnUrl = string.Format("settings/scripts/editScript.aspx?file={0}{1}.{2}", relPath, fileName, - fileType); + m_returnUrl = string.Format("settings/scripts/editScript.aspx?file={0}{1}.{2}", relPath, fileName, fileType); + return true; } + + ApplicationContext.Current.Services.FileService.SaveScript(new Script(relPath + fileName + "." + fileType)); + m_returnUrl = string.Format("settings/scripts/editScript.aspx?file={0}{1}.{2}", relPath, fileName, fileType); return true; } - public override bool PerformDelete() + public bool Delete() { - var path = IOHelper.MapPath(SystemDirectories.Scripts + "/" + Alias.TrimStart('/')); - - if (System.IO.File.Exists(path)) - System.IO.File.Delete(path); - else if (System.IO.Directory.Exists(path)) - System.IO.Directory.Delete(path, true); - - LogHelper.Info(string.Format("{0} Deleted by user {1}", Alias, User.Id)); + if (_alias.Contains(".") == false) + { + //there is no extension so we'll assume it's a folder + ApplicationContext.Current.Services.FileService.DeleteScriptFolder(_alias.TrimStart('/')); + } + else + { + ApplicationContext.Current.Services.FileService.DeleteScript(_alias.TrimStart('/')); + } return true; }