From 44ab0991ceaa653befbd0eede1277902d047fff0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 15 Jan 2019 22:08:08 +1100 Subject: [PATCH] Package installing is working --- .../Composing/Composers/ServicesComposer.cs | 1 - src/Umbraco.Core/Composing/TypeLoader.cs | 2 +- src/Umbraco.Core/IO/IOHelper.cs | 54 --- src/Umbraco.Core/IO/ShadowWrapper.cs | 2 +- src/Umbraco.Core/IO/SystemDirectories.cs | 4 + .../Models/Packaging/CompiledPackage.cs | 3 +- .../Models/Packaging/InstallationSummary.cs | 2 +- .../Models/Packaging/PackageDefinition.cs | 3 + .../Models/Packaging/UninstallationSummary.cs | 6 +- .../Packaging/CompiledPackageXmlParser.cs | 4 +- .../Packaging/IPackageActionRunner.cs | 11 +- .../Packaging/IPackageInstallation.cs | 13 +- .../Packaging/PackageActionRunner.cs | 29 +- .../Packaging/PackageDataInstallation.cs | 127 ++++++- .../Packaging/PackageDefinitionXmlParser.cs | 2 +- .../Packaging/PackageFileInstallation.cs | 26 ++ .../Packaging/PackageInstallation.cs | 77 ++-- .../Packaging/PackagesRepository.cs | 2 +- .../Services/IPackagingService.cs | 16 +- .../Services/Implement/PackagingService.cs | 48 +-- .../Sync/DatabaseServerMessenger.cs | 2 +- src/Umbraco.Examine/LuceneIndexCreator.cs | 2 +- .../Composing/TypeLoaderTests.cs | 2 +- src/Umbraco.Tests/IO/ShadowFileSystemTests.cs | 8 +- .../Packaging/PackageInstallationTest.cs | 20 +- .../Scoping/ScopeFileSystemsTests.cs | 2 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 3 +- .../src/views/packages/edit.controller.js | 2 + .../src/views/packages/edit.html | 2 +- .../views/install-local.controller.js | 131 ++++--- .../Binders/ContentModelBinderHelper.cs | 3 +- .../Editors/ContentTypeController.cs | 19 +- src/Umbraco.Web/Editors/MediaController.cs | 2 +- src/Umbraco.Web/Editors/PackageController.cs | 2 +- .../Editors/PackageInstallController.cs | 258 +++---------- src/Umbraco.Web/Editors/UsersController.cs | 2 +- .../Controllers/InstallPackageController.cs | 346 +++++++++--------- src/Umbraco.Web/Install/InstallHelper.cs | 25 -- .../Install/InstallStatusTracker.cs | 4 +- .../InstallSteps/StarterKitDownloadStep.cs | 24 +- .../InstallSteps/StarterKitInstallStep.cs | 10 +- .../Models/ContentTypeImportModel.cs | 12 +- .../Models/LocalPackageInstallModel.cs | 10 +- src/Umbraco.Web/Models/PackageInstallModel.cs | 10 +- .../Runtime/WebRuntimeComponent.cs | 5 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 - .../FileUploadCleanupFilterAttribute.cs | 16 +- .../_Legacy/PackageActions/addApplication.cs | 2 +- .../PackageActions/addDashboardSection.cs | 98 ----- .../PackageActions/addProxyFeedHost.cs | 2 +- .../_Legacy/PackageActions/allowDoctype.cs | 3 +- .../PackageActions/publishRootDocument.cs | 4 +- 52 files changed, 669 insertions(+), 795 deletions(-) delete mode 100644 src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs diff --git a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs index a09462c806..bd07123fb2 100644 --- a/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs +++ b/src/Umbraco.Core/Composing/Composers/ServicesComposer.cs @@ -72,7 +72,6 @@ namespace Umbraco.Core.Composing.Composers new PackageInstallation( factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - SystemDirectories.Packages, appRoot, appRoot)); //TODO: These are replaced in the web project - we need to declare them so that diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 3121e869c3..acb12ab575 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -405,7 +405,7 @@ namespace Umbraco.Core.Composing break; case LocalTempStorage.Default: default: - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/TypesCache"); + var tempFolder = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache"); _fileBasePath = Path.Combine(tempFolder, "umbraco-types." + NetworkHelper.FileSafeMachineName); break; } diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 7773f378a5..76e7631482 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -31,16 +31,6 @@ namespace Umbraco.Core.IO public static char DirSepChar => Path.DirectorySeparatorChar; - internal static void UnZip(string zipFilePath, string unPackDirectory, bool deleteZipFile) - { - // Unzip - var tempDir = unPackDirectory; - Directory.CreateDirectory(tempDir); - ZipFile.ExtractToDirectory(zipFilePath, unPackDirectory); - if (deleteZipFile) - File.Delete(zipFilePath); - } - //helper to try and match the old path to a new virtual one public static string FindFile(string virtualPath) { @@ -123,11 +113,6 @@ namespace Umbraco.Core.IO return MapPath(path, true); } - public static string MapPathIfVirtual(string path) - { - return path.StartsWith("~/") ? MapPath(path) : path; - } - //use a tilde character instead of the complete path internal static string ReturnPath(string settingsKey, string standardPath, bool useTilde) { @@ -156,20 +141,6 @@ namespace Umbraco.Core.IO return VerifyEditPath(filePath, new[] { validDir }); } - /// - /// Validates that the current filepath matches a directory where the user is allowed to edit a file. - /// - /// The filepath to validate. - /// The valid directory. - /// True, if the filepath is valid, else an exception is thrown. - /// The filepath is invalid. - internal static bool ValidateEditPath(string filePath, string validDir) - { - if (VerifyEditPath(filePath, validDir) == false) - throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), ""))); - return true; - } - /// /// Verifies that the current filepath matches one of several directories where the user is allowed to edit a file. /// @@ -221,20 +192,6 @@ namespace Umbraco.Core.IO return ext != null && validFileExtensions.Contains(ext.TrimStart('.')); } - /// - /// Validates that the current filepath has one of several authorized extensions. - /// - /// The filepath to validate. - /// The valid extensions. - /// True, if the filepath is valid, else an exception is thrown. - /// The filepath is invalid. - internal static bool ValidateFileExtension(string filePath, List validFileExtensions) - { - if (VerifyFileExtension(filePath, validFileExtensions) == false) - throw new FileSecurityException(String.Format("The extension for the current file '{0}' is not of an allowed type for this editor. This is typically controlled from either the installed MacroEngines or based on configuration in /config/umbracoSettings.config", filePath.Replace(MapPath(SystemDirectories.Root), ""))); - return true; - } - public static bool PathStartsWith(string path, string root, char separator) { // either it is identical to root, @@ -329,17 +286,6 @@ namespace Umbraco.Core.IO Directory.CreateDirectory(absolutePath); } - public static void EnsureFileExists(string path, string contents) - { - var absolutePath = IOHelper.MapPath(path); - if (File.Exists(absolutePath)) return; - - using (var writer = File.CreateText(absolutePath)) - { - writer.Write(contents); - } - } - /// /// Checks if a given path is a full path including drive letter /// diff --git a/src/Umbraco.Core/IO/ShadowWrapper.cs b/src/Umbraco.Core/IO/ShadowWrapper.cs index 6493238391..d71f328713 100644 --- a/src/Umbraco.Core/IO/ShadowWrapper.cs +++ b/src/Umbraco.Core/IO/ShadowWrapper.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.IO { internal class ShadowWrapper : IFileSystem { - private const string ShadowFsPath = "~/App_Data/TEMP/ShadowFs"; + private static readonly string ShadowFsPath = SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"; private readonly Func _isScoped; private readonly IFileSystem _innerFileSystem; diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index 94aa7b16cc..4ea3ed64d5 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -12,6 +12,10 @@ namespace Umbraco.Core.IO public static string Data => "~/App_Data"; + public static string TempData => Data + "/TEMP"; + + public static string TempFileUploads => TempData + "/FileUploads"; + public static string Install => "~/install"; //fixme: remove this diff --git a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs index 266c1f5518..d458337bf9 100644 --- a/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs +++ b/src/Umbraco.Core/Models/Packaging/CompiledPackage.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Xml.Linq; @@ -10,7 +11,7 @@ namespace Umbraco.Core.Models.Packaging /// public class CompiledPackage : IPackageInfo { - public string PackageFileName { get; set; } + public FileInfo PackageFile { get; set; } public string Name { get; set; } public string Version { get; set; } diff --git a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs index 7d81f48dd2..1cab17e220 100644 --- a/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/InstallationSummary.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable StylesheetsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); public IEnumerable Actions { get; set; } = Enumerable.Empty(); - public bool PackageInstalled { get; set; } + public IEnumerable ActionErrors { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs index de8415ddd2..bab52c63f6 100644 --- a/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Models/Packaging/PackageDefinition.cs @@ -53,6 +53,9 @@ namespace Umbraco.Core.Models.Packaging [Url] public string Url { get; set; } = string.Empty; + /// + /// The full path to the package's zip file when it was installed (or is being installed) + /// [ReadOnly(true)] [DataMember(Name = "packagePath")] public string PackagePath { get; set; } = string.Empty; diff --git a/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs index 20cbedbcf0..fd39954f6b 100644 --- a/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs +++ b/src/Umbraco.Core/Models/Packaging/UninstallationSummary.cs @@ -16,9 +16,9 @@ namespace Umbraco.Core.Models.Packaging public IEnumerable MacrosUninstalled { get; set; } = Enumerable.Empty(); public IEnumerable FilesUninstalled { get; set; } = Enumerable.Empty(); public IEnumerable TemplatesUninstalled { get; set; } = Enumerable.Empty(); - public IEnumerable ContentTypesUninstalled { get; set; } = Enumerable.Empty(); + public IEnumerable DocumentTypesUninstalled { get; set; } = Enumerable.Empty(); public IEnumerable StylesheetsUninstalled { get; set; } = Enumerable.Empty(); - public IEnumerable ContentUninstalled { get; set; } = Enumerable.Empty(); - public bool PackageUninstalled { get; set; } + public IEnumerable Actions { get; set; } = Enumerable.Empty(); + public IEnumerable ActionErrors { get; set; } = Enumerable.Empty(); } } diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 0f3119f697..eb9cf46008 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Packaging _conflictingPackageData = conflictingPackageData; } - public CompiledPackage ToCompiledPackage(XDocument xml, string packageFileName, string applicationRootFolder) + public CompiledPackage ToCompiledPackage(XDocument xml, FileInfo packageFile, string applicationRootFolder) { if (xml == null) throw new ArgumentNullException(nameof(xml)); if (xml.Root == null) throw new ArgumentException(nameof(xml), "The xml document is invalid"); @@ -39,7 +39,7 @@ namespace Umbraco.Core.Packaging var def = new CompiledPackage { - PackageFileName = packageFileName, + PackageFile = packageFile, Name = package.Element("name")?.Value, Author = author.Element("name")?.Value, AuthorUrl = author.Element("website")?.Value, diff --git a/src/Umbraco.Core/Packaging/IPackageActionRunner.cs b/src/Umbraco.Core/Packaging/IPackageActionRunner.cs index d5c6327115..1f8c134364 100644 --- a/src/Umbraco.Core/Packaging/IPackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/IPackageActionRunner.cs @@ -1,4 +1,5 @@ -using System.Xml.Linq; +using System.Collections.Generic; +using System.Xml.Linq; namespace Umbraco.Core.Packaging { @@ -10,7 +11,8 @@ namespace Umbraco.Core.Packaging /// Name of the package. /// The action alias. /// The action XML. - void RunPackageAction(string packageName, string actionAlias, XElement actionXml); + /// + bool RunPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors); /// /// Undos the package action with the specified action alias. @@ -18,6 +20,7 @@ namespace Umbraco.Core.Packaging /// Name of the package. /// The action alias. /// The action XML. - void UndoPackageAction(string packageName, string actionAlias, XElement actionXml); + /// + bool UndoPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 83a21dcd2f..5dae76674d 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Xml.Linq; using Umbraco.Core.Models.Packaging; @@ -6,6 +7,14 @@ namespace Umbraco.Core.Packaging { public interface IPackageInstallation { + /// + /// Uninstalls a package including all data, entities and files + /// + /// + /// + /// + UninstallationSummary UninstallPackage(PackageDefinition packageDefinition, int userId); + /// /// Installs a packages data and entities /// @@ -27,8 +36,8 @@ namespace Umbraco.Core.Packaging /// /// Reads the package (zip) file and returns the model /// - /// + /// /// - CompiledPackage ReadPackage(string packageFileName); + CompiledPackage ReadPackage(FileInfo packageFile); } } diff --git a/src/Umbraco.Core/Packaging/PackageActionRunner.cs b/src/Umbraco.Core/Packaging/PackageActionRunner.cs index 37103b0473..38275d5f0a 100644 --- a/src/Umbraco.Core/Packaging/PackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/PackageActionRunner.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Xml.Linq; using Umbraco.Core.Logging; using Umbraco.Core._Legacy.PackageActions; @@ -19,15 +20,10 @@ namespace Umbraco.Core.Packaging _packageActions = packageActions; } - /// - /// Runs the package action with the specified action alias. - /// - /// Name of the package. - /// The action alias. - /// The action XML. - public void RunPackageAction(string packageName, string actionAlias, XElement actionXml) + /// + public bool RunPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors) { - + var e = new List(); foreach (var ipa in _packageActions) { try @@ -37,19 +33,19 @@ namespace Umbraco.Core.Packaging } catch (Exception ex) { + e.Add($"{ipa.Alias()} - {ex.Message}"); _logger.Error(ex, "Error loading package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } + + errors = e; + return e.Count == 0; } - /// - /// Undos the package action with the specified action alias. - /// - /// Name of the package. - /// The action alias. - /// The action XML. - public void UndoPackageAction(string packageName, string actionAlias, XElement actionXml) + /// + public bool UndoPackageAction(string packageName, string actionAlias, XElement actionXml, out IEnumerable errors) { + var e = new List(); foreach (var ipa in _packageActions) { try @@ -59,9 +55,12 @@ namespace Umbraco.Core.Packaging } catch (Exception ex) { + e.Add($"{ipa.Alias()} - {ex.Message}"); _logger.Error(ex, "Error undoing package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } + errors = e; + return e.Count == 0; } } diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index 8ef99502c8..1743bb0041 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Web; @@ -10,6 +11,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; @@ -43,6 +45,128 @@ namespace Umbraco.Core.Packaging _contentService = contentService; } + #region Uninstall + + public UninstallationSummary UninstallPackageData(PackageDefinition package, int userId) + { + if (package == null) throw new ArgumentNullException(nameof(package)); + + var removedTemplates = new List(); + var removedMacros = new List(); + var removedContentTypes = new List(); + var removedDictionaryItems = new List(); + var removedDataTypes = new List(); + var removedLanguages = new List(); + + + //Uninstall templates + foreach (var item in package.Templates.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var found = _fileService.GetTemplate(nId); + if (found != null) + { + removedTemplates.Add(found); + _fileService.DeleteTemplate(found.Alias, userId); + } + package.Templates.Remove(nId.ToString()); + } + + //Uninstall macros + foreach (var item in package.Macros.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var macro = _macroService.GetById(nId); + if (macro != null) + { + removedMacros.Add(macro); + _macroService.Delete(macro, userId); + } + package.Macros.Remove(nId.ToString()); + } + + //Remove Document Types + var contentTypes = new List(); + var contentTypeService = _contentTypeService; + foreach (var item in package.DocumentTypes.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var contentType = contentTypeService.Get(nId); + if (contentType == null) continue; + contentTypes.Add(contentType); + package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); + } + + //Order the DocumentTypes before removing them + if (contentTypes.Any()) + { + //TODO: I don't think this ordering is necessary + var orderedTypes = (from contentType in contentTypes + orderby contentType.ParentId descending, contentType.Id descending + select contentType).ToList(); + removedContentTypes.AddRange(orderedTypes); + contentTypeService.Delete(orderedTypes, userId); + } + + //Remove Dictionary items + foreach (var item in package.DictionaryItems.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var di = _localizationService.GetDictionaryItemById(nId); + if (di != null) + { + removedDictionaryItems.Add(di); + _localizationService.Delete(di, userId); + } + package.DictionaryItems.Remove(nId.ToString()); + } + + //Remove Data types + foreach (var item in package.DataTypes.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var dtd = _dataTypeService.GetDataType(nId); + if (dtd != null) + { + removedDataTypes.Add(dtd); + _dataTypeService.Delete(dtd, userId); + } + package.DataTypes.Remove(nId.ToString()); + } + + //Remove Langs + foreach (var item in package.Languages.ToArray()) + { + if (int.TryParse(item, out var nId) == false) continue; + var lang = _localizationService.GetLanguageById(nId); + if (lang != null) + { + removedLanguages.Add(lang); + _localizationService.Delete(lang, userId); + } + package.Languages.Remove(nId.ToString()); + } + + // create a summary of what was actually removed, for PackagingService.UninstalledPackage + var summary = new UninstallationSummary + { + MetaData = package, + TemplatesUninstalled = removedTemplates, + MacrosUninstalled = removedMacros, + DocumentTypesUninstalled = removedContentTypes, + DictionaryItemsUninstalled = removedDictionaryItems, + DataTypesUninstalled = removedDataTypes, + LanguagesUninstalled = removedLanguages, + + }; + + return summary; + + + } + + #endregion + #region Content @@ -201,7 +325,7 @@ namespace Umbraco.Core.Packaging #endregion - #region ContentTypes + #region DocumentTypes public IEnumerable ImportDocumentType(XElement docTypeElement, int userId) { @@ -576,6 +700,7 @@ namespace Umbraco.Core.Packaging // This means that the property will not be created. if (dataTypeDefinition == null) { + //TODO: We should expose this to the UI during install! _logger.Warn("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.", property.Element("Name").Value, dataTypeDefinitionId, property.Element("Type").Value.Trim()); diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index 1f0e5ec92e..0d7adf8ece 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -91,7 +91,7 @@ namespace Umbraco.Core.Packaging new XElement("datatypes", string.Join(",", def.DataTypes ?? Array.Empty())), new XElement("content", - new XAttribute("nodeId", def.ContentNodeId), + new XAttribute("nodeId", def.ContentNodeId ?? string.Empty), new XAttribute("loadChildNodes", def.ContentLoadChildNodes)), new XElement("templates", string.Join(",", def.Templates ?? Array.Empty())), diff --git a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs index 55b8bdc63e..7c0891175b 100644 --- a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs @@ -53,6 +53,32 @@ namespace Umbraco.Core.Packaging } } + public IEnumerable UninstallFiles(PackageDefinition package) + { + var removedFiles = new List(); + + foreach (var item in package.Files.ToArray()) + { + removedFiles.Add(item.GetRelativePath()); + + //here we need to try to find the file in question as most packages does not support the tilde char + var file = IOHelper.FindFile(item); + if (file != null) + { + //TODO: Surely this should be ~/ ? + file = file.EnsureStartsWith("/"); + var filePath = IOHelper.MapPath(file); + + if (File.Exists(filePath)) + File.Delete(filePath); + + } + package.Files.Remove(file); + } + + return removedFiles; + } + private static IEnumerable<(string packageUniqueFile, string appAbsolutePath)> AppendRootToDestination(string applicationRootFolder, IEnumerable<(string packageUniqueFile, string appRelativePath)> sourceDestination) { return diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 12d4769235..4563d31560 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -18,7 +18,6 @@ namespace Umbraco.Core.Packaging private readonly PackageFileInstallation _packageFileInstallation; private readonly CompiledPackageXmlParser _parser; private readonly IPackageActionRunner _packageActionRunner; - private readonly string _packagesFolderPath; private readonly DirectoryInfo _packageExtractionFolder; private readonly DirectoryInfo _applicationRootFolder; @@ -29,9 +28,6 @@ namespace Umbraco.Core.Packaging /// /// /// - /// - /// The relative path of the package storage folder (i.e. ~/App_Data/Packages ) - /// /// /// The root folder of the application /// @@ -39,27 +35,25 @@ namespace Umbraco.Core.Packaging /// The destination root folder to extract the package files (generally the same as applicationRoot) but can be modified for testing /// public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, - string packagesFolderPath, DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) + DirectoryInfo applicationRootFolder, DirectoryInfo packageExtractionFolder) { _packageExtraction = new PackageExtraction(); _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); _packageDataInstallation = packageDataInstallation ?? throw new ArgumentNullException(nameof(packageDataInstallation)); - _parser = parser; - _packageActionRunner = packageActionRunner; - _packagesFolderPath = packagesFolderPath; - _applicationRootFolder = applicationRootFolder; - _packageExtractionFolder = packageExtractionFolder; + _parser = parser ?? throw new ArgumentNullException(nameof(parser)); + _packageActionRunner = packageActionRunner ?? throw new ArgumentNullException(nameof(packageActionRunner)); + _applicationRootFolder = applicationRootFolder ?? throw new ArgumentNullException(nameof(applicationRootFolder)); + _packageExtractionFolder = packageExtractionFolder ?? throw new ArgumentNullException(nameof(packageExtractionFolder)); } - public CompiledPackage ReadPackage(string packageFileName) + public CompiledPackage ReadPackage(FileInfo packageFile) { - if (packageFileName == null) throw new ArgumentNullException(nameof(packageFileName)); - var packageZipFile = GetPackageZipFile(packageFileName); - var doc = GetConfigXmlDoc(packageZipFile); + if (packageFile == null) throw new ArgumentNullException(nameof(packageFile)); + var doc = GetConfigXmlDoc(packageFile); - var compiledPackage = _parser.ToCompiledPackage(doc, Path.GetFileName(packageZipFile.FullName), _applicationRootFolder.FullName); + var compiledPackage = _parser.ToCompiledPackage(doc, packageFile, _applicationRootFolder.FullName); - ValidatePackageFile(packageZipFile, compiledPackage); + ValidatePackageFile(packageFile, compiledPackage); return compiledPackage; } @@ -73,15 +67,28 @@ namespace Umbraco.Core.Packaging if (packageDefinition.Name != compiledPackage.Name) throw new InvalidOperationException("The package definition does not match the compiled package manifest"); - var packageZipFile = GetPackageZipFile(compiledPackage.PackageFileName); + var packageZipFile = compiledPackage.PackageFile; return _packageFileInstallation.InstallFiles(compiledPackage, packageZipFile, _packageExtractionFolder.FullName); } + public UninstallationSummary UninstallPackage(PackageDefinition package, int userId) + { + //running this will update the PackageDefinition with the items being removed + var summary = _packageDataInstallation.UninstallPackageData(package, userId); + summary.Actions = _parser.GetPackageActions(XElement.Parse(package.Actions), package.Name); + + //run actions before files are removed + summary.ActionErrors = UndoPackageActions(package, summary.Actions).ToList(); + + var filesRemoved = _packageFileInstallation.UninstallFiles(package); + summary.FilesUninstalled = filesRemoved; + + return summary; + } + public InstallationSummary InstallPackageData(PackageDefinition packageDefinition, CompiledPackage compiledPackage, int userId) { - //TODO: Update the PackageDefinition! - var installationSummary = new InstallationSummary { DataTypesInstalled = _packageDataInstallation.ImportDataTypes(compiledPackage.DataTypes.ToList(), userId), @@ -101,10 +108,8 @@ namespace Umbraco.Core.Packaging installationSummary.MetaData = compiledPackage; //fixme: Verify that this will work! installationSummary.FilesInstalled = packageDefinition.Files; - installationSummary.PackageInstalled = true; - + //make sure the definition is up to date with everything - foreach (var x in installationSummary.DataTypesInstalled) packageDefinition.DataTypes.Add(x.Id.ToInvariantString()); foreach (var x in installationSummary.LanguagesInstalled) packageDefinition.Languages.Add(x.Id.ToInvariantString()); foreach (var x in installationSummary.DictionaryItemsInstalled) packageDefinition.DictionaryItems.Add(x.Id.ToInvariantString()); @@ -115,15 +120,17 @@ namespace Umbraco.Core.Packaging var contentInstalled = installationSummary.ContentInstalled.ToList(); packageDefinition.ContentNodeId = contentInstalled.Count > 0 ? contentInstalled[0].Id.ToInvariantString() : null; - RunPackageActions(packageDefinition, installationSummary.Actions); + //run package actions + installationSummary.ActionErrors = RunPackageActions(packageDefinition, installationSummary.Actions).ToList(); return installationSummary; } - private void RunPackageActions(PackageDefinition packageDefinition, IEnumerable actions) + private IEnumerable RunPackageActions(PackageDefinition packageDefinition, IEnumerable actions) { foreach (var n in actions) { + //if there is an undo section then save it to the definition so we can run it at uninstallation var undo = n.Undo; if (undo) packageDefinition.Actions += n.XmlData.ToString(); @@ -131,12 +138,28 @@ namespace Umbraco.Core.Packaging //Run the actions tagged only for 'install' if (n.RunAt != ActionRunAt.Install) continue; - if (n.Alias.IsNullOrWhiteSpace() == false) - _packageActionRunner.RunPackageAction(packageDefinition.Name, n.Alias, n.XmlData); + if (n.Alias.IsNullOrWhiteSpace()) continue; + + //run the actions and report errors + if (!_packageActionRunner.RunPackageAction(packageDefinition.Name, n.Alias, n.XmlData, out var err)) + foreach (var e in err) yield return e; } } - private FileInfo GetPackageZipFile(string packageFileName) => new FileInfo(IOHelper.MapPath(_packagesFolderPath).EnsureEndsWith('\\') + packageFileName); + private IEnumerable UndoPackageActions(IPackageInfo packageDefinition, IEnumerable actions) + { + foreach (var n in actions) + { + //Run the actions tagged only for 'uninstall' + if (n.RunAt != ActionRunAt.Uninstall) continue; + + if (n.Alias.IsNullOrWhiteSpace()) continue; + + //run the actions and report errors + if (!_packageActionRunner.UndoPackageAction(packageDefinition.Name, n.Alias, n.XmlData, out var err)) + foreach (var e in err) yield return e; + } + } private XDocument GetConfigXmlDoc(FileInfo packageFile) { diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index c0620820a2..af5c7ffded 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -69,7 +69,7 @@ namespace Umbraco.Core.Packaging _logger = logger; _packageRepositoryFileName = packageRepositoryFileName; - _tempFolderPath = tempFolderPath ?? SystemDirectories.Data + "/TEMP/PackageFiles"; + _tempFolderPath = tempFolderPath ?? SystemDirectories.TempData.EnsureEndsWith('/') + "PackageFiles"; _packagesFolderPath = packagesFolderPath ?? SystemDirectories.Packages; _mediaFolderPath = mediaFolderPath ?? SystemDirectories.Media + "/created-packages"; diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 8aa936c8ff..a31fc2d6cf 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -16,25 +16,27 @@ namespace Umbraco.Core.Services /// /// Returns a result from an umbraco package file (zip) /// - /// + /// /// - CompiledPackage GetCompiledPackageInfo(string packageFileName); + CompiledPackage GetCompiledPackageInfo(FileInfo packageFile); /// /// Installs the package files contained in an umbraco package file (zip) /// /// - /// + /// /// - IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0); + IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); /// /// Installs the data, entities, objects contained in an umbraco package file (zip) /// /// - /// + /// /// - InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0); + InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0); + + UninstallationSummary UninstallPackage(PackageDefinition packageDefinition, int userId = 0); #endregion @@ -81,6 +83,6 @@ namespace Umbraco.Core.Services /// /// The file name of the downloaded package which will exist in ~/App_Data/packages /// - Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId); + Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId); } } diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs index ba5d30f8d7..362b1fc67b 100644 --- a/src/Umbraco.Core/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs @@ -53,7 +53,7 @@ namespace Umbraco.Core.Services.Implement #region Package Files /// - public async Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId) + public async Task FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId) { //includeHidden = true because we don't care if it's hidden we want to get the file regardless var url = $"{Constants.PackageRepository.RestApiBaseUrl}/{packageId}?version={umbracoVersion.ToString(3)}&includeHidden=true&asFile=true"; @@ -85,7 +85,7 @@ namespace Umbraco.Core.Services.Implement using (var fs1 = new FileStream(packageFilePath, FileMode.Create)) { fs1.Write(bytes, 0, bytes.Length); - return packageId + ".umb"; + return new FileInfo(packageFilePath); } } @@ -97,18 +97,19 @@ namespace Umbraco.Core.Services.Implement #region Installation - public CompiledPackage GetCompiledPackageInfo(string packageFileName) => _packageInstallation.ReadPackage(packageFileName); + public CompiledPackage GetCompiledPackageInfo(FileInfo packageFile) => _packageInstallation.ReadPackage(packageFile); - public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0) + public IEnumerable InstallCompiledPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); if (packageDefinition.Name == default) throw new ArgumentException("The package definition has incomplete information"); - var compiledPackage = GetCompiledPackageInfo(packageFileName); - if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName); + var compiledPackage = GetCompiledPackageInfo(packageFile); + if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFile); - var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId); + var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId).ToList(); + packageDefinition.Files = files; SaveInstalledPackage(packageDefinition); @@ -117,16 +118,16 @@ namespace Umbraco.Core.Services.Implement return files; } - public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0) + public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, FileInfo packageFile, int userId = 0) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); if (packageDefinition.Id == default) throw new ArgumentException("The package definition has not been persisted"); if (packageDefinition.Name == default) throw new ArgumentException("The package definition has incomplete information"); - var compiledPackage = GetCompiledPackageInfo(packageFileName); - if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName); + var compiledPackage = GetCompiledPackageInfo(packageFile); + if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFile); - if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFileName, compiledPackage), this)) + if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs(packageFile.Name, compiledPackage), this)) return new InstallationSummary { MetaData = compiledPackage }; var summary = _packageInstallation.InstallPackageData(packageDefinition, compiledPackage, userId); @@ -140,6 +141,20 @@ namespace Umbraco.Core.Services.Implement return summary; } + public UninstallationSummary UninstallPackage(PackageDefinition package, int userId = 0) + { + var summary = _packageInstallation.UninstallPackage(package, userId); + + SaveInstalledPackage(package); + + DeleteInstalledPackage(package.Id, userId); + + // trigger the UninstalledPackage event + UninstalledPackage.RaiseEvent(new UninstallPackageEventArgs(summary, package, false), this); + + return summary; + } + #endregion #region Created/Installed Package Repositories @@ -179,21 +194,12 @@ namespace Umbraco.Core.Services.Implement #endregion - /// - /// This method can be used to trigger the 'UninstalledPackage' event when a package is uninstalled by something else but this service. - /// - /// - internal static void OnUninstalledPackage(UninstallPackageEventArgs args) - { - UninstalledPackage.RaiseEvent(args, null); - } - #region Event Handlers /// /// Occurs before Importing umbraco package /// - internal static event TypedEventHandler> ImportingPackage; + public static event TypedEventHandler> ImportingPackage; /// /// Occurs after a package is imported diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs index 5cfcb501e5..6844e6e75c 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs @@ -551,7 +551,7 @@ namespace Umbraco.Core.Sync break; case LocalTempStorage.Default: default: - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/DistCache"); + var tempFolder = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "DistCache"); distCacheFilePath = Path.Combine(tempFolder, fileName); break; } diff --git a/src/Umbraco.Examine/LuceneIndexCreator.cs b/src/Umbraco.Examine/LuceneIndexCreator.cs index 0e83b37dc5..806d0edc7a 100644 --- a/src/Umbraco.Examine/LuceneIndexCreator.cs +++ b/src/Umbraco.Examine/LuceneIndexCreator.cs @@ -29,7 +29,7 @@ namespace Umbraco.Examine public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string folderName) { - var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Data), "TEMP", "ExamineIndexes", folderName)); + var dirInfo = new DirectoryInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.TempData), "ExamineIndexes", folderName)); if (!dirInfo.Exists) System.IO.Directory.CreateDirectory(dirInfo.FullName); diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 5148c7eb1b..1649f3675d 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -30,7 +30,7 @@ namespace Umbraco.Tests.Composing // this ensures it's reset _typeLoader = new TypeLoader(NullCacheProvider.Instance, LocalTempStorage.Default, new ProfilingLogger(Mock.Of(), Mock.Of())); - foreach (var file in Directory.GetFiles(IOHelper.MapPath("~/App_Data/TEMP/TypesCache"))) + foreach (var file in Directory.GetFiles(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache"))) File.Delete(file); // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver diff --git a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs index 262b026cae..2244f9085d 100644 --- a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.IO private static void ClearFiles() { TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests")); - TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data/TEMP/ShadowFs")); + TestHelper.DeleteDirectory(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); } private static string NormPath(string path) @@ -388,7 +388,7 @@ namespace Umbraco.Tests.IO var logger = Mock.Of(); var path = IOHelper.MapPath("FileSysTests"); - var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs"); + var shadowfs = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); Directory.CreateDirectory(shadowfs); @@ -482,7 +482,7 @@ namespace Umbraco.Tests.IO var logger = Mock.Of(); var path = IOHelper.MapPath("FileSysTests"); - var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs"); + var shadowfs = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; @@ -535,7 +535,7 @@ namespace Umbraco.Tests.IO var logger = Mock.Of(); var path = IOHelper.MapPath("FileSysTests"); - var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs"); + var shadowfs = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 609d26aec9..7514eea00b 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -50,11 +50,10 @@ namespace Umbraco.Tests.Packaging PackageDataInstallation, new PackageFileInstallation(Parser, ProfilingLogger), Parser, Mock.Of(), - packagesFolderPath: "~/Packaging/packages",//this is where our test zip file is applicationRootFolder: new DirectoryInfo(IOHelper.GetRootDirectorySafe()), packageExtractionFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder - const string documentTypePickerUmb = "Document_Type_Picker_1.1.umb"; + private const string DocumentTypePickerUmb = "Document_Type_Picker_1.1.umb"; //[Test] //public void PackagingService_Can_ImportPackage() @@ -72,7 +71,9 @@ namespace Umbraco.Tests.Packaging [Test] public void Can_Read_Compiled_Package() { - var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); Assert.IsNotNull(package); Assert.AreEqual(1, package.Files.Count); Assert.AreEqual("095e064b-ba4d-442d-9006-3050983c13d8.dll", package.Files[0].UniqueFileName); @@ -95,7 +96,10 @@ namespace Umbraco.Tests.Packaging { - var preInstallWarnings = PackageInstallation.ReadPackage(documentTypePickerUmb).Warnings; + var preInstallWarnings = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))) + .Warnings; Assert.IsNotNull(preInstallWarnings); //TODO: Assert! @@ -104,7 +108,9 @@ namespace Umbraco.Tests.Packaging [Test] public void Install_Files() { - var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); @@ -122,7 +128,9 @@ namespace Umbraco.Tests.Packaging [Test] public void Install_Data() { - var package = PackageInstallation.ReadPackage(documentTypePickerUmb); + var package = PackageInstallation.ReadPackage( + //this is where our test zip file is + new FileInfo(Path.Combine(IOHelper.MapPath("~/Packaging/packages"), DocumentTypePickerUmb))); var def = PackageDefinition.FromCompiledPackage(package); def.Id = 1; def.PackageId = Guid.NewGuid(); diff --git a/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs b/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs index 0ef0e9362b..0a23e4a1b9 100644 --- a/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Scoping { TestHelper.DeleteDirectory(IOHelper.MapPath("media")); TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests")); - TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data/TEMP/ShadowFs")); + TestHelper.DeleteDirectory(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); } [TestCase(true)] diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 412a492376..684da2599e 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -185,7 +185,8 @@ namespace Umbraco.Tests.TestHelpers new PackageDataInstallation(logger, fileService.Value, macroService.Value, localizationService.Value, dataTypeService.Value, entityService.Value, contentTypeService.Value, contentService.Value, propertyEditorCollection), new PackageFileInstallation(compiledPackageXmlParser, new ProfilingLogger(logger, new TestProfiler())), compiledPackageXmlParser, Mock.Of(), - "", null, null)); + new DirectoryInfo(IOHelper.GetRootDirectorySafe()), + new DirectoryInfo(IOHelper.GetRootDirectorySafe()))); }); var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c))); var treeService = GetLazyService(factory, c => new ApplicationTreeService(logger, cache, typeLoader)); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js index 057f1160c2..4afe62786e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.controller.js @@ -144,6 +144,8 @@ vm.package = updatedPackage; vm.buttonState = "success"; + formHelper.resetForm({ scope: $scope }); + if (create) { //if we are creating, then redirect to the correct url and reload $location.path("packages/packages/edit/" + vm.package.id).search("subview", "created").search("create", null); diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html index 955676b806..a66eb94746 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/edit.html @@ -138,7 +138,7 @@ {{doctype.name}} diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js index 8be7d1b17a..9c6c2bb7c5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/install-local.controller.js @@ -10,7 +10,7 @@ vm.installPackage = installPackage; vm.installState = { status: "", - progress:0 + progress: 0 }; vm.installCompleted = false; vm.zipFile = { @@ -27,6 +27,23 @@ } }; + var labels = {}; + var labelKeys = [ + "packager_installStateImporting", + "packager_installStateInstalling", + "packager_installStateRestarting", + "packager_installStateComplete", + "packager_installStateCompleted" + ]; + + localizationService.localizeMany(labelKeys).then(function (values) { + labels.installStateImporting = values[0]; + labels.installStateInstalling = values[1]; + labels.installStateRestarting = values[2]; + labels.installStateComplete = values[3]; + labels.installStateCompleted = values[4]; + }); + function upload(file) { Upload.upload({ @@ -34,10 +51,10 @@ fields: {}, file: file }).progress(function (evt) { - + // hack: in some browsers the progress event is called after success // this prevents the UI from going back to a uploading state - if(vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") { + if (vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") { // set view state to uploading vm.state = 'uploading'; @@ -110,83 +127,85 @@ } function installPackage() { - vm.installState.status = localizationService.localize("packager_installStateImporting"); + + vm.installState.status = labels.installStateImporting; vm.installState.progress = "0"; packageResource - .import(vm.localPackage) - .then(function(pack) { - vm.installState.progress = "25"; - vm.installState.status = localizationService.localize("packager_installStateInstalling"); - return packageResource.installFiles(pack); - }, + .import(vm.localPackage) + .then(function (pack) { + vm.installState.progress = "25"; + vm.installState.status = labels.installStateInstalling; + return packageResource.installFiles(pack); + }, installError) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateRestarting"); - vm.installState.progress = "50"; - var deferred = $q.defer(); + .then(function (pack) { + vm.installState.status = labels.installStateRestarting; + vm.installState.progress = "50"; + var deferred = $q.defer(); - //check if the app domain is restarted ever 2 seconds - var count = 0; - function checkRestart() { - $timeout(function () { + //check if the app domain is restarted ever 2 seconds + var count = 0; + + function checkRestart() { + $timeout(function () { packageResource.checkRestart(pack).then(function (d) { count++; //if there is an id it means it's not restarted yet but we'll limit it to only check 10 times if (d.isRestarting && count < 10) { - checkRestart(); + checkRestart(); } else { - //it's restarted! - deferred.resolve(d); + //it's restarted! + deferred.resolve(d); } - }, - installError); - }, 2000); - } + }, + installError); + }, + 2000); + } - checkRestart(); - - return deferred.promise; - }, installError) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateRestarting"); - vm.installState.progress = "75"; - return packageResource.installData(pack); - }, + checkRestart(); + + return deferred.promise; + }, installError) - .then(function(pack) { - vm.installState.status = localizationService.localize("packager_installStateComplete"); - vm.installState.progress = "100"; - return packageResource.cleanUp(pack); - }, + .then(function (pack) { + vm.installState.status = labels.installStateRestarting; + vm.installState.progress = "75"; + return packageResource.installData(pack); + }, installError) - .then(function(result) { + .then(function (pack) { + vm.installState.status = labels.installStateComplete; + vm.installState.progress = "100"; + return packageResource.cleanUp(pack); + }, + installError) + .then(function (result) { - if (result.postInstallationPath) { - //Put the redirect Uri in a cookie so we can use after reloading - localStorageService.set("packageInstallUri", result.postInstallationPath); - } - else { - //set to a constant value so it knows to just go to the installed view - localStorageService.set("packageInstallUri", "installed"); - } + if (result.postInstallationPath) { + //Put the redirect Uri in a cookie so we can use after reloading + localStorageService.set("packageInstallUri", result.postInstallationPath); + } + else { + //set to a constant value so it knows to just go to the installed view + localStorageService.set("packageInstallUri", "installed"); + } - vm.installState.status = localizationService.localize("packager_installStateCompleted"); - vm.installCompleted = true; - - + vm.installState.status = labels.installStateCompleted; + vm.installCompleted = true; - }, - installError); + + }, installError); } - + function installError() { //This will return a rejection meaning that the promise change above will stop return $q.reject(); } - vm.reloadPage = function() { + vm.reloadPage = function () { //reload on next digest (after cookie) $timeout(function () { $window.location.reload(true); diff --git a/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs b/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs index 8c3edd915d..dd6d22a967 100644 --- a/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs +++ b/src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Web.Http; using System.Web.Http.Controllers; using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Web.Models.ContentEditing; @@ -19,7 +20,7 @@ namespace Umbraco.Web.Editors.Binders public TModelSave BindModelFromMultipartRequest(HttpActionContext actionContext, ModelBindingContext bindingContext) where TModelSave : IHaveUploadedFiles { - var result = actionContext.ReadAsMultipart("~/App_Data/TEMP/FileUploads"); + var result = actionContext.ReadAsMultipart(SystemDirectories.TempFileUploads); var model = actionContext.GetModelFromMultipartRequest(result, "contentItem"); diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 97f7ff3589..670d37e7a7 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; @@ -532,7 +533,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "FileUploads"); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); @@ -545,26 +546,24 @@ namespace Umbraco.Web.Editors } var model = new ContentTypeImportModel(); + var file = result.FileData[0]; var fileName = file.Headers.ContentDisposition.FileName.Trim('\"'); var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower(); if (ext.InvariantEquals("udt")) { - //TODO: Currently it has to be here, it's not ideal but that's the way it is right now - var tempDir = IOHelper.MapPath(SystemDirectories.Data); + model.TempFileName = Path.Combine(root, model.TempFileName); - //ensure it's there - Directory.CreateDirectory(tempDir); - - model.TempFileName = "justDelete_" + Guid.NewGuid() + ".udt"; - var tempFileLocation = Path.Combine(tempDir, model.TempFileName); - System.IO.File.Copy(file.LocalFileName, tempFileLocation, true); + model.UploadedFiles.Add(new ContentPropertyFile + { + TempFilePath = model.TempFileName + }); var xd = new XmlDocument { XmlResolver = null }; - xd.Load(tempFileLocation); + xd.Load(model.TempFileName); model.Alias = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Alias")?.FirstChild.Value; model.Name = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Name")?.FirstChild.Value; diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 2c6ba06dc2..ce088e0caa 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -626,7 +626,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); diff --git a/src/Umbraco.Web/Editors/PackageController.cs b/src/Umbraco.Web/Editors/PackageController.cs index 4b452ac6a6..063dcf483e 100644 --- a/src/Umbraco.Web/Editors/PackageController.cs +++ b/src/Umbraco.Web/Editors/PackageController.cs @@ -13,7 +13,7 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { /// - /// A controller used for installing packages and managing all of the data in the packages section in the back office + /// A controller used for managing packages in the back office /// [PluginController("UmbracoApi")] [SerializeVersion] diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index bfaec3f82c..38b75a27f8 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; @@ -42,14 +43,11 @@ namespace Umbraco.Web.Editors [UmbracoApplicationAuthorize(Core.Constants.Applications.Packages)] public class PackageInstallController : UmbracoAuthorizedJsonController { - private readonly IPackageActionRunner _packageActionRunner; - public PackageInstallController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, CacheHelper applicationCache, - IProfilingLogger logger, IRuntimeState runtimeState, IPackageActionRunner packageActionRunner) + IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContextAccessor, sqlContext, services, applicationCache, logger, runtimeState) { - _packageActionRunner = packageActionRunner; } /// @@ -75,7 +73,7 @@ namespace Umbraco.Web.Editors var package = Services.PackagingService.GetInstalledPackageById(packageId); if (package == null) return NotFound(); - PerformUninstall(package); + var summary = Services.PackagingService.UninstallPackage(package); //now get all other packages by this name since we'll uninstall all versions foreach (var installed in Services.PackagingService.GetAllInstalledPackages() @@ -94,176 +92,6 @@ namespace Umbraco.Web.Editors return Ok(); } - /// - /// SORRY :( I didn't have time to put this in a service somewhere - the old packager did this all manually too - /// - /// - protected void PerformUninstall(PackageDefinition package) - { - if (package == null) throw new ArgumentNullException("package"); - - var removedTemplates = new List(); - var removedMacros = new List(); - var removedContentTypes = new List(); - var removedDictionaryItems = new List(); - var removedDataTypes = new List(); - var removedFiles = new List(); - - //Uninstall templates - foreach (var item in package.Templates.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var found = Services.FileService.GetTemplate(nId); - if (found != null) - { - removedTemplates.Add(found); - Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId().ResultOr(0)); - } - package.Templates.Remove(nId.ToString()); - } - - //Uninstall macros - foreach (var item in package.Macros.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var macro = Services.MacroService.GetById(nId); - if (macro != null) - { - removedMacros.Add(macro); - Services.MacroService.Delete(macro); - } - package.Macros.Remove(nId.ToString()); - } - - //Remove Document Types - var contentTypes = new List(); - var contentTypeService = Services.ContentTypeService; - foreach (var item in package.DocumentTypes.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var contentType = contentTypeService.Get(nId); - if (contentType == null) continue; - contentTypes.Add(contentType); - package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); - } - - //Order the DocumentTypes before removing them - if (contentTypes.Any()) - { - //TODO: I don't think this ordering is necessary - var orderedTypes = from contentType in contentTypes - orderby contentType.ParentId descending, contentType.Id descending - select contentType; - removedContentTypes.AddRange(orderedTypes); - contentTypeService.Delete(orderedTypes); - } - - //Remove Dictionary items - foreach (var item in package.DictionaryItems.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var di = Services.LocalizationService.GetDictionaryItemById(nId); - if (di != null) - { - removedDictionaryItems.Add(di); - Services.LocalizationService.Delete(di); - } - package.DictionaryItems.Remove(nId.ToString()); - } - - //Remove Data types - foreach (var item in package.DataTypes.ToArray()) - { - int nId; - if (int.TryParse(item, out nId) == false) continue; - var dtd = Services.DataTypeService.GetDataType(nId); - if (dtd != null) - { - removedDataTypes.Add(dtd); - Services.DataTypeService.Delete(dtd); - } - package.DataTypes.Remove(nId.ToString()); - } - - Services.PackagingService.SaveInstalledPackage(package); - - // uninstall actions - //TODO: We should probably report errors to the UI!! - // This never happened before though, but we should do something now - if (package.Actions.IsNullOrWhiteSpace() == false) - { - try - { - var actionsXml = XDocument.Parse("" + package.Actions + ""); - - Logger.Debug("Executing undo actions: {UndoActionsXml}", actionsXml.ToString(SaveOptions.DisableFormatting)); - - foreach (var n in actionsXml.Root.Elements("Action")) - { - try - { - _packageActionRunner.UndoPackageAction(package.Name, n.AttributeValue("alias"), n); - } - catch (Exception ex) - { - Logger.Error(ex, "An error occurred running undo actions"); - } - } - } - catch (Exception ex) - { - Logger.Error(ex, "An error occurred running undo actions"); - } - } - - //moved remove of files here so custom package actions can still undo - //Remove files - foreach (var item in package.Files.ToArray()) - { - removedFiles.Add(item.GetRelativePath()); - - //here we need to try to find the file in question as most packages does not support the tilde char - var file = IOHelper.FindFile(item); - if (file != null) - { - if (file.StartsWith("/") == false) - file = string.Format("/{0}", file); - var filePath = IOHelper.MapPath(file); - - if (File.Exists(filePath)) - File.Delete(filePath); - - } - package.Files.Remove(file); - } - - Services.PackagingService.SaveInstalledPackage(package); - - Services.PackagingService.DeleteInstalledPackage(package.Id, Security.GetUserId().ResultOr(0)); - - // create a summary of what was actually removed, for PackagingService.UninstalledPackage - var summary = new UninstallationSummary - { - MetaData = package, - TemplatesUninstalled = removedTemplates, - MacrosUninstalled = removedMacros, - ContentTypesUninstalled = removedContentTypes, - DictionaryItemsUninstalled = removedDictionaryItems, - DataTypesUninstalled = removedDataTypes, - FilesUninstalled = removedFiles, - PackageUninstalled = true - }; - - // trigger the UninstalledPackage event - // fixme: This all needs to be part of the service! - PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs(summary, package, false)); - - } - /// /// Returns all installed packages - only shows their latest versions /// @@ -302,7 +130,9 @@ namespace Umbraco.Web.Editors private void PopulateFromPackageData(LocalPackageInstallModel model) { - var ins = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); + var zipFile = new FileInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), model.ZipFileName)); + + var ins = Services.PackagingService.GetCompiledPackageInfo(zipFile); model.Name = ins.Name; model.Author = ins.Author; @@ -365,11 +195,9 @@ namespace Umbraco.Web.Editors public async Task UploadLocalPackage() { if (Request.Content.IsMimeMultipartContent() == false) - { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); - } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); @@ -378,38 +206,36 @@ namespace Umbraco.Web.Editors //must have a file if (result.FileData.Count == 0) - { throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); - } - //TODO: App/Tree Permissions? var model = new LocalPackageInstallModel { + //Generate a new package Id for this, we'll use this later for tracking, when persisting, saving the file, etc... PackageGuid = Guid.NewGuid() }; //get the files foreach (var file in result.FileData) { - var fileName = file.Headers.ContentDisposition.FileName.Trim(new[] { '\"' }); + var fileName = file.Headers.ContentDisposition.FileName.Trim('\"'); var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower(); - //TODO: Only allow .zip if (ext.InvariantEquals("zip") || ext.InvariantEquals("umb")) { - //TODO: Currently it has to be here, it's not ideal but that's the way it is right now - var packageTempDir = IOHelper.MapPath(SystemDirectories.Data); + //we always save package files to /App_Data/packages/package-guid.umb for processing as a standard so lets copy. + + var packagesFolder = IOHelper.MapPath(SystemDirectories.Packages); + Directory.CreateDirectory(packagesFolder); + var packageFile = Path.Combine(packagesFolder, model.PackageGuid + ".umb"); + File.Copy(file.LocalFileName, packageFile); - //ensure it's there - Directory.CreateDirectory(packageTempDir); + model.ZipFileName = Path.GetFileName(packageFile); - //copy it - must always be '.umb' for the installer thing to work - //the file name must be a GUID - this is what the packager expects (strange yes) - //because essentially this is creating a temporary package Id that will be used - //for unpacking/installing/etc... - model.ZipFilePath = model.PackageGuid + ".umb"; - var packageTempFileLocation = Path.Combine(packageTempDir, model.ZipFilePath); - File.Copy(file.LocalFileName, packageTempFileLocation, true); + //add to the outgoing model so that all temp files are cleaned up + model.UploadedFiles.Add(new ContentPropertyFile + { + TempFilePath = file.LocalFileName + }); //Populate the model from the metadata in the package file (zip file) PopulateFromPackageData(model); @@ -447,17 +273,22 @@ namespace Umbraco.Web.Editors public async Task Fetch(string packageGuid) { //Default path - string path = Path.Combine("packages", packageGuid + ".umb"); - if (File.Exists(IOHelper.MapPath(Path.Combine(SystemDirectories.Data, path))) == false) + string fileName = packageGuid + ".umb"; + if (File.Exists(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), fileName)) == false) { - path = await Services.PackagingService.FetchPackageFileAsync(Guid.Parse(packageGuid), UmbracoVersion.Current, Security.GetUserId().ResultOr(0)); + var packageFile = await Services.PackagingService.FetchPackageFileAsync( + Guid.Parse(packageGuid), + UmbracoVersion.Current, + Security.GetUserId().ResultOr(0)); + + fileName = packageFile.Name; } var model = new LocalPackageInstallModel { PackageGuid = Guid.Parse(packageGuid), - RepositoryGuid = Guid.Parse("65194810-1f85-11dd-bd0b-0800200c9a66"), - ZipFilePath = path + //RepositoryGuid = Guid.Parse("65194810-1f85-11dd-bd0b-0800200c9a66"), + ZipFileName = fileName }; //Populate the model from the metadata in the package file (zip file) @@ -483,7 +314,9 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallModel Import(PackageInstallModel model) { - var packageInfo = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); + var zipFile = new FileInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), model.ZipFileName)); + + var packageInfo = Services.PackagingService.GetCompiledPackageInfo(zipFile); //now we need to check for version comparison if (packageInfo.UmbracoVersionRequirementsType == RequirementsType.Strict) @@ -497,9 +330,10 @@ namespace Umbraco.Web.Editors } var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); + packageDefinition.PackageId = model.PackageGuid; //We must re-map the original package GUID that was generated + packageDefinition.PackagePath = zipFile.FullName; //save to the installedPackages.config - packageDefinition.PackageId = model.PackageGuid; //fixme: why are we doing this? Services.PackagingService.SaveInstalledPackage(packageDefinition); model.Id = packageDefinition.Id; @@ -518,7 +352,9 @@ namespace Umbraco.Web.Editors var definition = Services.PackagingService.GetInstalledPackageById(model.Id); if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); - Services.PackagingService.InstallCompiledPackageFiles(definition, model.ZipFilePath, Security.GetUserId().ResultOr(0)); + var zipFile = new FileInfo(definition.PackagePath); + + var installedFiles = Services.PackagingService.InstallCompiledPackageFiles(definition, zipFile, Security.GetUserId().ResultOr(0)); //set a restarting marker and reset the app pool Current.RestartAppPool(Request.TryGetHttpContext().Result); @@ -553,7 +389,10 @@ namespace Umbraco.Web.Editors var definition = Services.PackagingService.GetInstalledPackageById(model.Id); if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); - Services.PackagingService.InstallCompiledPackageData(definition, model.ZipFilePath, Security.GetUserId().ResultOr(0)); + var zipFile = new FileInfo(definition.PackagePath); + + var installSummary = Services.PackagingService.InstallCompiledPackageData(definition, zipFile, Security.GetUserId().ResultOr(0)); + return model; } @@ -565,7 +404,12 @@ namespace Umbraco.Web.Editors [HttpPost] public PackageInstallResult CleanUp(PackageInstallModel model) { - var packageInfo = Services.PackagingService.GetCompiledPackageInfo(model.ZipFilePath); + var definition = Services.PackagingService.GetInstalledPackageById(model.Id); + if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); + + var zipFile = new FileInfo(definition.PackagePath); + + var packageInfo = Services.PackagingService.GetCompiledPackageInfo(zipFile); var clientDependencyConfig = new ClientDependencyConfiguration(Logger); var clientDependencyUpdated = clientDependencyConfig.UpdateVersionNumber( @@ -585,9 +429,9 @@ namespace Umbraco.Web.Editors return new PackageInstallResult { Id = model.Id, - ZipFilePath = model.ZipFilePath, + ZipFileName = model.ZipFileName, PackageGuid = model.PackageGuid, - RepositoryGuid = model.RepositoryGuid, + //RepositoryGuid = model.RepositoryGuid, PostInstallationPath = redirectUrl }; diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 7577624621..e46e83c6e4 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -70,7 +70,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } - var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads"); + var root = IOHelper.MapPath(SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); var provider = new MultipartFormDataStreamProvider(root); diff --git a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs index dd9b0a42d0..81cb1e2e39 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallPackageController.cs @@ -1,196 +1,196 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Web.Http; -using Newtonsoft.Json.Linq; -using umbraco; -using Umbraco.Core; -using Umbraco.Web.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Services; -using Umbraco.Web.Composing; -using Umbraco.Web.Install.Models; -using Umbraco.Web.WebApi; +//using System; +//using System.Linq; +//using System.Net; +//using System.Net.Http; +//using System.Text; +//using System.Threading.Tasks; +//using System.Web; +//using System.Web.Http; +//using Newtonsoft.Json.Linq; +//using umbraco; +//using Umbraco.Core; +//using Umbraco.Web.Cache; +//using Umbraco.Core.Configuration; +//using Umbraco.Core.Models.Packaging; +//using Umbraco.Core.Services; +//using Umbraco.Web.Composing; +//using Umbraco.Web.Install.Models; +//using Umbraco.Web.WebApi; -namespace Umbraco.Web.Install.Controllers -{ - /// - /// A controller for the installation process regarding packages - /// - /// - /// Currently this is used for web services however we should/could eventually migrate the whole installer to MVC as it - /// is a bit of a mess currently. - /// - [HttpInstallAuthorize] - [AngularJsonOnlyConfiguration] - [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] - //fixme: Is this used anymore?? - public class InstallPackageController : ApiController - { - private readonly IPackagingService _packagingService; - private readonly UmbracoContext _umbracoContext; +//namespace Umbraco.Web.Install.Controllers +//{ +// /// +// /// A controller for the installation process regarding packages +// /// +// /// +// /// Currently this is used for web services however we should/could eventually migrate the whole installer to MVC as it +// /// is a bit of a mess currently. +// /// +// [HttpInstallAuthorize] +// [AngularJsonOnlyConfiguration] +// [Obsolete("This is only used for the legacy way of installing starter kits in the back office")] +// //fixme: Is this used anymore?? +// public class InstallPackageController : ApiController +// { +// private readonly IPackagingService _packagingService; +// private readonly UmbracoContext _umbracoContext; - public InstallPackageController(IPackagingService packagingService, UmbracoContext umbracoContext) - { - _packagingService = packagingService; - _umbracoContext = umbracoContext; - } +// public InstallPackageController(IPackagingService packagingService, UmbracoContext umbracoContext) +// { +// _packagingService = packagingService; +// _umbracoContext = umbracoContext; +// } - /// - /// Empty action, useful for retrieving the base url for this controller - /// - /// - [HttpGet] - public HttpResponseMessage Index() - { - throw new NotImplementedException(); - } +// /// +// /// Empty action, useful for retrieving the base url for this controller +// /// +// /// +// [HttpGet] +// public HttpResponseMessage Index() +// { +// throw new NotImplementedException(); +// } - /// - /// Connects to the repo, downloads the package and creates the definition - /// - /// - /// - [HttpPost] - public async Task DownloadPackageFiles(InstallPackageModel model) - { - var packageFile = await _packagingService.FetchPackageFileAsync( - model.KitGuid, - UmbracoVersion.Current, - UmbracoContext.Current.Security.CurrentUser.Id); +// /// +// /// Connects to the repo, downloads the package and creates the definition +// /// +// /// +// /// +// [HttpPost] +// public async Task DownloadPackageFiles(InstallPackageModel model) +// { +// var packageFile = await _packagingService.FetchPackageFileAsync( +// model.KitGuid, +// UmbracoVersion.Current, +// UmbracoContext.Current.Security.CurrentUser.Id); - var packageInfo = _packagingService.GetCompiledPackageInfo(packageFile); - if (packageInfo == null) throw new InvalidOperationException("Could not read package file " + packageFile); +// var packageInfo = _packagingService.GetCompiledPackageInfo(packageFile); +// if (packageInfo == null) throw new InvalidOperationException("Could not read package file " + packageFile); - //save to the installedPackages.config - var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); - _packagingService.SaveInstalledPackage(packageDefinition); +// //save to the installedPackages.config +// var packageDefinition = PackageDefinition.FromCompiledPackage(packageInfo); +// _packagingService.SaveInstalledPackage(packageDefinition); - return Json(new - { - success = true, - packageId = packageDefinition.Id, - packageFile = packageInfo.PackageFileName, - percentage = 10, - message = "Downloading starter kit files..." - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// packageId = packageDefinition.Id, +// packageFile = packageInfo.PackageFileName, +// percentage = 10, +// message = "Downloading starter kit files..." +// }, HttpStatusCode.OK); +// } - /// - /// Installs the files in the package - /// - /// - [HttpPost] - public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) - { - model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); +// /// +// /// Installs the files in the package +// /// +// /// +// [HttpPost] +// public HttpResponseMessage InstallPackageFiles(InstallPackageModel model) +// { +// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var definition = _packagingService.GetInstalledPackageById(model.PackageId); - if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); +// var definition = _packagingService.GetInstalledPackageById(model.PackageId); +// if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); - _packagingService.InstallCompiledPackageFiles(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); +// _packagingService.InstallCompiledPackageFiles(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - return Json(new - { - success = true, - ManifestId = model.PackageId, - model.PackageFile, - percentage = 20, - message = "Installing starter kit files" - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// ManifestId = model.PackageId, +// model.PackageFile, +// percentage = 20, +// message = "Installing starter kit files" +// }, HttpStatusCode.OK); +// } - /// - /// Ensures the app pool is restarted - /// - /// - [HttpPost] - public HttpResponseMessage RestartAppPool() - { - Current.RestartAppPool(Request.TryGetHttpContext().Result); - return Json(new - { - success = true, - percentage = 25, - message = "Installing starter kit files" - }, HttpStatusCode.OK); - } +// /// +// /// Ensures the app pool is restarted +// /// +// /// +// [HttpPost] +// public HttpResponseMessage RestartAppPool() +// { +// Current.RestartAppPool(Request.TryGetHttpContext().Result); +// return Json(new +// { +// success = true, +// percentage = 25, +// message = "Installing starter kit files" +// }, HttpStatusCode.OK); +// } - /// - /// Checks if the app pool has completed restarted - /// - /// - [HttpPost] - public HttpResponseMessage CheckAppPoolRestart() - { - if (Request.TryGetHttpContext().Result.Application.AllKeys.Contains("AppPoolRestarting")) - { - return Request.CreateResponse(HttpStatusCode.BadRequest); - } +// /// +// /// Checks if the app pool has completed restarted +// /// +// /// +// [HttpPost] +// public HttpResponseMessage CheckAppPoolRestart() +// { +// if (Request.TryGetHttpContext().Result.Application.AllKeys.Contains("AppPoolRestarting")) +// { +// return Request.CreateResponse(HttpStatusCode.BadRequest); +// } - return Json(new - { - percentage = 30, - success = true, - }, HttpStatusCode.OK); - } +// return Json(new +// { +// percentage = 30, +// success = true, +// }, HttpStatusCode.OK); +// } - /// - /// Installs the business logic portion of the package after app restart - /// - /// - [HttpPost] - public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) - { - model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); +// /// +// /// Installs the business logic portion of the package after app restart +// /// +// /// +// [HttpPost] +// public HttpResponseMessage InstallBusinessLogic(InstallPackageModel model) +// { +// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - var definition = _packagingService.GetInstalledPackageById(model.PackageId); - if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); +// var definition = _packagingService.GetInstalledPackageById(model.PackageId); +// if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.PackageId); - _packagingService.InstallCompiledPackageData(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); +// _packagingService.InstallCompiledPackageData(definition, model.PackageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - return Json(new - { - success = true, - ManifestId = model.PackageId, - model.PackageFile, - percentage = 70, - message = "Installing starter kit files" - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// ManifestId = model.PackageId, +// model.PackageFile, +// percentage = 70, +// message = "Installing starter kit files" +// }, HttpStatusCode.OK); +// } - /// - /// Cleans up the package installation - /// - /// - [HttpPost] - public HttpResponseMessage CleanupInstallation(InstallPackageModel model) - { - model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); +// /// +// /// Cleans up the package installation +// /// +// /// +// [HttpPost] +// public HttpResponseMessage CleanupInstallation(InstallPackageModel model) +// { +// model.PackageFile = HttpUtility.UrlDecode(model.PackageFile); - return Json(new - { - success = true, - ManifestId = model.PackageId, - model.PackageFile, - percentage = 100, - message = "Starter kit has been installed" - }, HttpStatusCode.OK); - } +// return Json(new +// { +// success = true, +// ManifestId = model.PackageId, +// model.PackageFile, +// percentage = 100, +// message = "Starter kit has been installed" +// }, HttpStatusCode.OK); +// } - private HttpResponseMessage Json(object jsonObject, HttpStatusCode status) - { - var response = Request.CreateResponse(status); - var json = JObject.FromObject(jsonObject); - response.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json"); - return response; - } - } +// private HttpResponseMessage Json(object jsonObject, HttpStatusCode status) +// { +// var response = Request.CreateResponse(status); +// var json = JObject.FromObject(jsonObject); +// response.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json"); +// return response; +// } +// } -} +//} diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index 08a552d4d4..36fb384655 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -41,31 +41,6 @@ namespace Umbraco.Web.Install return _installationType ?? (_installationType = IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value; } - internal static void DeleteLegacyInstaller() - { - if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Install))) - { - if (Directory.Exists(IOHelper.MapPath("~/app_data/temp/install_backup"))) - { - //this means the backup already exists with files but there's no files in it, so we'll delete the backup and re-run it - if (Directory.GetFiles(IOHelper.MapPath("~/app_data/temp/install_backup")).Any() == false) - { - Directory.Delete(IOHelper.MapPath("~/app_data/temp/install_backup"), true); - Directory.Move(IOHelper.MapPath(SystemDirectories.Install), IOHelper.MapPath("~/app_data/temp/install_backup")); - } - } - else - { - Directory.Move(IOHelper.MapPath(SystemDirectories.Install), IOHelper.MapPath("~/app_data/temp/install_backup")); - } - } - - if (Directory.Exists(IOHelper.MapPath("~/Areas/UmbracoInstall"))) - { - Directory.Delete(IOHelper.MapPath("~/Areas/UmbracoInstall"), true); - } - } - internal void InstallStatus(bool isCompleted, string errorMsg) { try diff --git a/src/Umbraco.Web/Install/InstallStatusTracker.cs b/src/Umbraco.Web/Install/InstallStatusTracker.cs index 7944100648..d93eb9a06c 100644 --- a/src/Umbraco.Web/Install/InstallStatusTracker.cs +++ b/src/Umbraco.Web/Install/InstallStatusTracker.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Install private static string GetFile(Guid installId) { - var file = IOHelper.MapPath("~/App_Data/TEMP/Install/" + var file = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "Install/" + "install_" + installId.ToString("N") + ".txt"); @@ -39,7 +39,7 @@ namespace Umbraco.Web.Install public static void ClearFiles() { - var dir = IOHelper.MapPath("~/App_Data/TEMP/Install/"); + var dir = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "Install/"); if (Directory.Exists(dir)) { var files = Directory.GetFiles(dir); diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 0fe1e333d3..0349bb4ec7 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Web; @@ -49,39 +50,38 @@ namespace Umbraco.Web.Install.InstallSteps return null; } - var result = await DownloadPackageFilesAsync(starterKitId.Value); + var (packageFile, packageId) = await DownloadPackageFilesAsync(starterKitId.Value); Current.RestartAppPool(); return new InstallSetupResult(new Dictionary { - {"packageId", result.Item2}, - {"packageFile", result.Item1} + {"packageId", packageId}, + {"packageFile", packageFile} }); } - private async Task> DownloadPackageFilesAsync(Guid kitGuid) + private async Task<(string packageFile, int packageId)> DownloadPackageFilesAsync(Guid kitGuid) { //Go get the package file from the package repo - var packageFileName = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); - if (packageFileName == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); + var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, UmbracoVersion.Current, _umbracoContext.Security.GetUserId().ResultOr(0)); + if (packageFile == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); //add an entry to the installedPackages.config - var compiledPackage = _packageService.GetCompiledPackageInfo(packageFileName); + var compiledPackage = _packageService.GetCompiledPackageInfo(packageFile); var packageDefinition = PackageDefinition.FromCompiledPackage(compiledPackage); _packageService.SaveInstalledPackage(packageDefinition); - InstallPackageFiles(packageDefinition, compiledPackage.PackageFileName); + InstallPackageFiles(packageDefinition, compiledPackage.PackageFile); - return new Tuple(compiledPackage.PackageFileName, packageDefinition.Id); + return (compiledPackage.PackageFile.Name, packageDefinition.Id); } - private void InstallPackageFiles(PackageDefinition packageDefinition, string packageFileName) + private void InstallPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile) { if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); - packageFileName = HttpUtility.UrlDecode(packageFileName); - _packageService.InstallCompiledPackageData(packageDefinition, packageFileName, _umbracoContext.Security.GetUserId().ResultOr(0)); + _packageService.InstallCompiledPackageData(packageDefinition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); } public override string View => _packageService.GetAllInstalledPackages().Any() ? string.Empty : base.View; diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 9d3f38b061..805041391f 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Web; @@ -30,22 +31,21 @@ namespace Umbraco.Web.Install.InstallSteps var installSteps = InstallStatusTracker.GetStatus().ToArray(); var previousStep = installSteps.Single(x => x.Name == "StarterKitDownload"); var packageId = Convert.ToInt32(previousStep.AdditionalData["packageId"]); - var packageFile = (string)previousStep.AdditionalData["packageFile"]; - InstallBusinessLogic(packageId, packageFile); + InstallBusinessLogic(packageId); Current.RestartAppPool(_httContext); return Task.FromResult(null); } - private void InstallBusinessLogic(int packageId, string packageFile) + private void InstallBusinessLogic(int packageId) { - packageFile = HttpUtility.UrlDecode(packageFile); - var definition = _packagingService.GetInstalledPackageById(packageId); if (definition == null) throw new InvalidOperationException("Not package definition found with id " + packageId); + var packageFile = new FileInfo(definition.PackagePath); + _packagingService.InstallCompiledPackageData(definition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); } diff --git a/src/Umbraco.Web/Models/ContentTypeImportModel.cs b/src/Umbraco.Web/Models/ContentTypeImportModel.cs index 961476e5f0..f6f9a5926d 100644 --- a/src/Umbraco.Web/Models/ContentTypeImportModel.cs +++ b/src/Umbraco.Web/Models/ContentTypeImportModel.cs @@ -1,17 +1,13 @@ using System.Collections.Generic; using System.Runtime.Serialization; +using Umbraco.Core.Models.Editors; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models { [DataContract(Name = "contentTypeImportModel")] - public class ContentTypeImportModel : INotificationModel + public class ContentTypeImportModel : INotificationModel, IHaveUploadedFiles { - public ContentTypeImportModel() - { - Notifications = new List(); - } - [DataMember(Name = "alias")] public string Alias { get; set; } @@ -19,9 +15,11 @@ namespace Umbraco.Web.Models public string Name { get; set; } [DataMember(Name = "notifications")] - public List Notifications { get; } + public List Notifications { get; } = new List(); [DataMember(Name = "tempFileName")] public string TempFileName { get; set; } + + public List UploadedFiles => new List(); } } diff --git a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs index d1d51e1fcc..8adc9acf30 100644 --- a/src/Umbraco.Web/Models/LocalPackageInstallModel.cs +++ b/src/Umbraco.Web/Models/LocalPackageInstallModel.cs @@ -11,16 +11,10 @@ namespace Umbraco.Web.Models [DataContract(Name = "localPackageInstallModel")] public class LocalPackageInstallModel : PackageInstallModel, IHaveUploadedFiles, INotificationModel { - public LocalPackageInstallModel() - { - UploadedFiles = new List(); - Notifications = new List(); - } - - public List UploadedFiles { get; } + public List UploadedFiles { get; } = new List(); [DataMember(Name = "notifications")] - public List Notifications { get; } + public List Notifications { get; } = new List(); /// /// A flag to determine if this package is compatible to be installed diff --git a/src/Umbraco.Web/Models/PackageInstallModel.cs b/src/Umbraco.Web/Models/PackageInstallModel.cs index 1cf4a483ae..2decaeb098 100644 --- a/src/Umbraco.Web/Models/PackageInstallModel.cs +++ b/src/Umbraco.Web/Models/PackageInstallModel.cs @@ -15,13 +15,13 @@ namespace Umbraco.Web.Models [DataMember(Name = "packageGuid")] public Guid PackageGuid { get; set; } - //TODO: Do we need this? - [DataMember(Name = "repositoryGuid")] - public Guid RepositoryGuid { get; set; } + ////TODO: Do we need this? + //[DataMember(Name = "repositoryGuid")] + //public Guid RepositoryGuid { get; set; } - [DataMember(Name = "zipFilePath")] - public string ZipFilePath { get; set; } + [DataMember(Name = "zipFileName")] + public string ZipFileName { get; set; } /// /// During installation this can be used to track any pending appdomain restarts diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 0199a34579..422b502f80 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Components; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Profiling; using Umbraco.Core.Services; @@ -77,8 +78,6 @@ namespace Umbraco.Web.Runtime // Disable the X-AspNetMvc-Version HTTP Header MvcHandler.DisableMvcResponseHeader = true; - InstallHelper.DeleteLegacyInstaller(); - // wrap view engines in the profiling engine WrapViewEngines(ViewEngines.Engines); @@ -245,7 +244,7 @@ namespace Umbraco.Web.Runtime private static void ConfigureClientDependency(IGlobalSettings globalSettings) { // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] - XmlFileMapper.FileMapDefaultFolder = "~/App_Data/TEMP/ClientDependency"; + XmlFileMapper.FileMapDefaultFolder = SystemDirectories.TempData.EnsureEndsWith('/') + "ClientDependency"; BaseCompositeFileProcessingProvider.UrlTypeDefault = CompositeUrlType.Base64QueryStrings; // Now we need to detect if we are running umbracoLocalTempStorage as EnvironmentTemp and in that case we want to change the CDF file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 89260e59f6..36550f9b54 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1132,7 +1132,6 @@ - diff --git a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs index b60545e3cb..233ce39e52 100644 --- a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs @@ -14,7 +14,7 @@ using File = System.IO.File; namespace Umbraco.Web.WebApi.Filters { /// - /// Checks if the parameter is ContentItemSave and then deletes any temporary saved files from file uploads associated with the request + /// Checks if the parameter is IHaveUploadedFiles and then deletes any temporary saved files from file uploads associated with the request /// internal sealed class FileUploadCleanupFilterAttribute : ActionFilterAttribute { @@ -29,14 +29,6 @@ namespace Umbraco.Web.WebApi.Filters _incomingModel = incomingModel; } - /// - /// Returns true so that other filters can execute along with this one - /// - public override bool AllowMultiple - { - get { return true; } - } - public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); @@ -47,8 +39,7 @@ namespace Umbraco.Web.WebApi.Filters { if (actionExecutedContext.ActionContext.ActionArguments.Any()) { - var contentItem = actionExecutedContext.ActionContext.ActionArguments.First().Value as IHaveUploadedFiles; - if (contentItem != null) + if (actionExecutedContext.ActionContext.ActionArguments.First().Value is IHaveUploadedFiles contentItem) { //cleanup any files associated foreach (var f in contentItem.UploadedFiles) @@ -104,8 +95,7 @@ namespace Umbraco.Web.WebApi.Filters if (objectContent != null) { - var uploadedFiles = objectContent.Value as IHaveUploadedFiles; - if (uploadedFiles != null) + if (objectContent.Value is IHaveUploadedFiles uploadedFiles) { if (uploadedFiles.UploadedFiles != null) { diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs index 75614f68aa..26116820e6 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addApplication.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// This class implements the IPackageAction Interface, used to execute code when packages are installed. /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. /// - public class addApplication : IPackageAction + public class AddApplication : IPackageAction { #region IPackageAction Members diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs b/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs deleted file mode 100644 index 1e2e396d2c..0000000000 --- a/src/Umbraco.Web/_Legacy/PackageActions/addDashboardSection.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Linq; -using System.Xml; -using System.Xml.Linq; -using System.Xml.XPath; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Xml; -using Umbraco.Core._Legacy.PackageActions; - -namespace Umbraco.Web._Legacy.PackageActions -{ - /// - /// - /// - public class addDashboardSection : IPackageAction - { - #region IPackageAction Members - - /// - /// Installs a dashboard section. This action reuses the action XML, so it has to be valid dashboard markup. - /// - /// Name of the package. - /// The XML data. - /// true if successfull - /// - /// - /// - ///
- /// - /// default - /// content - /// - /// - /// /usercontrols/dashboard/latestEdits.ascx - /// /usercontrols/umbracoBlog/dashboardBlogPostCreate.ascx - /// - /// - /// /usercontrols/umbracoBlog/dashboardBlogPostCreate.ascx - /// - ///
- ///
- ///
- ///
- public bool Execute(string packageName, XElement xmlData) - { - //this will need a complete section node to work... - - if (xmlData.HasElements) - { - string sectionAlias = xmlData.AttributeValue("dashboardAlias"); - string dbConfig = SystemFiles.DashboardConfig; - - var section = xmlData.Element("section"); - var dashboardFile = XDocument.Load(IOHelper.MapPath(dbConfig)); - - //don't continue if it already exists - var found = dashboardFile.XPathSelectElements("//section[@alias='" + sectionAlias + "']"); - if (!found.Any()) - { - dashboardFile.Root.Add(section); - dashboardFile.Save(IOHelper.MapPath(dbConfig)); - } - - return true; - } - - return false; - } - - - public string Alias() - { - return "addDashboardSection"; - } - - public bool Undo(string packageName, XElement xmlData) - { - - string sectionAlias = xmlData.AttributeValue("dashboardAlias"); - string dbConfig = SystemFiles.DashboardConfig; - var dashboardFile = XDocument.Load(IOHelper.MapPath(dbConfig)); - - var section = dashboardFile.XPathSelectElement("//section [@alias = '" + sectionAlias + "']"); - - if (section != null) - { - section.Remove(); - dashboardFile.Save(IOHelper.MapPath(dbConfig)); - } - - return true; - } - - #endregion - - } -} diff --git a/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs b/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs index bcd7d7c52f..f53adb3be0 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/addProxyFeedHost.cs @@ -7,7 +7,7 @@ using Umbraco.Core._Legacy.PackageActions; namespace Umbraco.Web._Legacy.PackageActions { - public class addProxyFeedHost : IPackageAction + public class AddProxyFeedHost : IPackageAction { #region IPackageAction Members diff --git a/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs b/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs index 2ed16e3842..f4b206a9ad 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/allowDoctype.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// This class implements the IPackageAction Interface, used to execute code when packages are installed. /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. ///
- public class allowDoctype : IPackageAction + public class AllowDoctype : IPackageAction { #region IPackageAction Members @@ -68,7 +68,6 @@ namespace Umbraco.Web._Legacy.PackageActions return false; } - //this has no undo. /// /// This action has no undo. /// diff --git a/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs b/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs index f4fe17e999..f4bd7dd4fc 100644 --- a/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs +++ b/src/Umbraco.Web/_Legacy/PackageActions/publishRootDocument.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web._Legacy.PackageActions /// This class implements the IPackageAction Interface, used to execute code when packages are installed. /// All IPackageActions only takes a PackageName and a XmlNode as input, and executes based on the data in the xmlnode. ///
- public class publishRootDocument : IPackageAction + public class PublishRootDocument : IPackageAction { #region IPackageAction Members @@ -29,7 +29,6 @@ namespace Umbraco.Web._Legacy.PackageActions string documentName = xmlData.AttributeValue("documentName"); - //global::umbraco.cms.businesslogic.web.Document[] rootDocs = global::umbraco.cms.businesslogic.web.Document.GetRootDocuments(); var rootDocs = Current.Services.ContentService.GetRootContent(); foreach (var rootDoc in rootDocs) @@ -44,7 +43,6 @@ namespace Umbraco.Web._Legacy.PackageActions return true; } - //this has no undo. /// /// This action has no undo. ///