Files
Umbraco-CMS/src/Umbraco.Core/Services/Implement/PackagingService.cs

213 lines
8.8 KiB
C#
Raw Normal View History

2017-12-28 09:18:09 +01:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
2017-12-28 09:18:09 +01:00
using System.Web;
using System.Xml.Linq;
2018-02-05 17:48:54 +01:00
using Umbraco.Core.Collections;
2017-12-28 09:18:09 +01:00
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
2017-12-28 09:18:09 +01:00
using Umbraco.Core.Models.Packaging;
using Umbraco.Core.Packaging;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
2018-01-20 12:09:15 +01:00
using Umbraco.Core.PropertyEditors;
2017-12-28 09:18:09 +01:00
using Umbraco.Core.Scoping;
using Umbraco.Core.Strings;
using Content = Umbraco.Core.Models.Content;
namespace Umbraco.Core.Services.Implement
{
/// <summary>
/// Represents the Packaging Service, which provides import/export functionality for the Core models of the API
/// using xml representation. This is primarily used by the Package functionality.
/// </summary>
public class PackagingService : IPackagingService
{
private readonly IPackageInstallation _packageInstallation;
private readonly IAuditService _auditService;
private readonly ICreatedPackagesRepository _createdPackages;
private readonly IInstalledPackagesRepository _installedPackages;
Merge remote-tracking branch 'origin/dev-v7' into temp8 # Conflicts: # build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1 # build/NuSpecs/UmbracoCms.Core.nuspec # build/NuSpecs/UmbracoCms.nuspec # build/NuSpecs/tools/Readme.txt # src/Umbraco.Core/Configuration/UmbracoConfig.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs # src/Umbraco.Core/Constants-Conventions.cs # src/Umbraco.Core/Constants-System.cs # src/Umbraco.Core/IO/MediaFileSystem.cs # src/Umbraco.Core/Media/Exif/ImageFile.cs # src/Umbraco.Core/Models/Property.cs # src/Umbraco.Core/Models/PropertyTagBehavior.cs # src/Umbraco.Core/Models/PropertyTags.cs # src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenTwelveZero/SetDefaultTagsStorageType.cs # src/Umbraco.Core/Persistence/Repositories/AuditRepository.cs # src/Umbraco.Core/Persistence/Repositories/UserRepository.cs # src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs # src/Umbraco.Core/Security/AuthenticationExtensions.cs # src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs # src/Umbraco.Core/Services/Implement/PackagingService.cs # src/Umbraco.Core/Services/ServerRegistrationService.cs # src/Umbraco.Core/StringExtensions.cs # src/Umbraco.Core/packages.config # src/Umbraco.Tests/ApplicationUrlHelperTests.cs # src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs # src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs # src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs # src/Umbraco.Tests/packages.config # src/Umbraco.Web.UI.Client/package.json # src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js # src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagegravity.directive.js # src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js # src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js # src/Umbraco.Web.UI.Client/src/common/services/user.service.js # src/Umbraco.Web.UI.Client/src/less/belle.less # src/Umbraco.Web.UI.Client/src/less/components/card.less # src/Umbraco.Web.UI.Client/src/less/navs.less # src/Umbraco.Web.UI.Client/src/less/panel.less # src/Umbraco.Web.UI.Client/src/less/property-editors.less # src/Umbraco.Web.UI.Client/src/less/tree.less # src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js # src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html # src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/iconpicker/iconpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/iconpicker/iconpicker.html # src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html # src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html # src/Umbraco.Web.UI.Client/src/views/components/notifications/umb-notifications.html # src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html # src/Umbraco.Web.UI.Client/src/views/components/umb-table.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js # src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html # src/Umbraco.Web.UI/Umbraco/config/lang/en.xml # src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web.UI/packages.config # src/Umbraco.Web.UI/web.Template.Debug.config # src/Umbraco.Web.UI/web.Template.config # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/CanvasDesignerController.cs # src/Umbraco.Web/Editors/ContentController.cs # src/Umbraco.Web/Editors/DashboardController.cs # src/Umbraco.Web/Editors/LogController.cs # src/Umbraco.Web/Editors/MediaController.cs # src/Umbraco.Web/Install/InstallHelper.cs # src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs # src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs # src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs # src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs # src/Umbraco.Web/Mvc/MasterControllerFactory.cs # src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs # src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs # src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerPropertyConverter.cs # src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs # src/Umbraco.Web/Routing/RedirectTrackingEventHandler.cs # src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs # src/Umbraco.Web/Scheduling/KeepAlive.cs # src/Umbraco.Web/Scheduling/LogScrubber.cs # src/Umbraco.Web/Scheduling/ScheduledPublishing.cs # src/Umbraco.Web/Scheduling/ScheduledTasks.cs # src/Umbraco.Web/Scheduling/Scheduler.cs # src/Umbraco.Web/Templates/TemplateUtilities.cs # src/Umbraco.Web/Trees/DataTypeTreeController.cs # src/Umbraco.Web/UmbracoModule.cs # src/Umbraco.Web/_Legacy/Packager/Installer.cs # src/Umbraco.Web/packages.config # src/Umbraco.Web/umbraco.presentation/keepAliveService.cs # src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs # src/umbraco.businesslogic/IO/IOHelper.cs # src/umbraco.cms/packages.config # src/umbraco.cms/umbraco.cms.csproj # src/umbraco.controls/packages.config # src/umbraco.controls/umbraco.controls.csproj # src/umbraco.editorControls/packages.config # src/umbraco.editorControls/umbraco.editorControls.csproj
2018-10-01 14:32:46 +02:00
private static HttpClient _httpClient;
2017-12-28 09:18:09 +01:00
public PackagingService(
IAuditService auditService,
ICreatedPackagesRepository createdPackages,
IInstalledPackagesRepository installedPackages,
IPackageInstallation packageInstallation)
{
_auditService = auditService;
_createdPackages = createdPackages;
_installedPackages = installedPackages;
_packageInstallation = packageInstallation;
2017-12-28 09:18:09 +01:00
}
#region Package Files
/// <inheritdoc />
public async Task<string> FetchPackageFileAsync(Guid packageId, Version umbracoVersion, int userId)
2017-12-28 09:18:09 +01:00
{
//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";
byte[] bytes;
try
2017-12-28 09:18:09 +01:00
{
if (_httpClient == null)
2017-12-28 09:18:09 +01:00
{
_httpClient = new HttpClient();
2017-12-28 09:18:09 +01:00
}
bytes = await _httpClient.GetByteArrayAsync(url);
}
catch (HttpRequestException ex)
{
throw new ConnectionException("An error occuring downloading the package from " + url, ex);
}
2017-12-28 09:18:09 +01:00
//successfull
if (bytes.Length > 0)
{
var packagePath = IOHelper.MapPath(SystemDirectories.Packages);
2017-12-28 09:18:09 +01:00
// Check for package directory
if (Directory.Exists(packagePath) == false)
Directory.CreateDirectory(packagePath);
2017-12-28 09:18:09 +01:00
var packageFilePath = Path.Combine(packagePath, packageId + ".umb");
2017-12-28 09:18:09 +01:00
using (var fs1 = new FileStream(packageFilePath, FileMode.Create))
{
fs1.Write(bytes, 0, bytes.Length);
return packageId + ".umb";
2017-12-28 09:18:09 +01:00
}
}
_auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package {packageId} fetched from {Constants.PackageRepository.DefaultRepositoryId}");
return null;
2017-12-28 09:18:09 +01:00
}
#endregion
#region Installation
public CompiledPackage GetCompiledPackageInfo(string packageFileName) => _packageInstallation.ReadPackage(packageFileName);
public IEnumerable<string> InstallCompiledPackageFiles(PackageDefinition packageDefinition, string packageFileName, int userId = 0)
2017-12-28 09:18:09 +01:00
{
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");
2017-12-28 09:18:09 +01:00
var compiledPackage = GetCompiledPackageInfo(packageFileName);
if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName);
2018-03-22 17:41:13 +01:00
var files = _packageInstallation.InstallPackageFiles(packageDefinition, compiledPackage, userId);
SaveInstalledPackage(packageDefinition);
2017-12-28 09:18:09 +01:00
_auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package files installed for package '{compiledPackage.Name}'.");
2017-12-28 09:18:09 +01:00
return files;
2017-12-28 09:18:09 +01:00
}
public InstallationSummary InstallCompiledPackageData(PackageDefinition packageDefinition, string packageFileName, int userId = 0)
2017-12-28 09:18:09 +01:00
{
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");
2017-12-28 09:18:09 +01:00
var compiledPackage = GetCompiledPackageInfo(packageFileName);
if (compiledPackage == null) throw new InvalidOperationException("Could not read the package file " + packageFileName);
if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs<string>(packageFileName, compiledPackage), this))
return new InstallationSummary { MetaData = compiledPackage };
var summary = _packageInstallation.InstallPackageData(packageDefinition, compiledPackage, userId);
SaveInstalledPackage(packageDefinition);
_auditService.Add(AuditType.PackagerInstall, userId, -1, "Package", $"Package data installed for package '{compiledPackage.Name}'.");
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(summary, compiledPackage, false), this);
return summary;
2017-12-28 09:18:09 +01:00
}
#endregion
#region Created/Installed Package Repositories
public void DeleteCreatedPackage(int id, int userId = 0)
{
var package = GetCreatedPackageById(id);
if (package == null) return;
_auditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", $"Created package '{package.Name}' deleted. Package id: {package.Id}");
_createdPackages.Delete(id);
}
public IEnumerable<PackageDefinition> GetAllCreatedPackages() => _createdPackages.GetAll();
public PackageDefinition GetCreatedPackageById(int id) => _createdPackages.GetById(id);
public bool SaveCreatedPackage(PackageDefinition definition) => _createdPackages.SavePackage(definition);
public string ExportCreatedPackage(PackageDefinition definition) => _createdPackages.ExportPackage(definition);
public IEnumerable<PackageDefinition> GetAllInstalledPackages() => _installedPackages.GetAll();
public PackageDefinition GetInstalledPackageById(int id) => _installedPackages.GetById(id);
public bool SaveInstalledPackage(PackageDefinition definition) => _installedPackages.SavePackage(definition);
public void DeleteInstalledPackage(int packageId, int userId = 0)
{
var package = GetInstalledPackageById(packageId);
if (package == null) return;
_auditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", $"Installed package '{package.Name}' deleted. Package id: {package.Id}");
_installedPackages.Delete(packageId);
}
2017-12-28 09:18:09 +01:00
#endregion
/// <summary>
/// This method can be used to trigger the 'UninstalledPackage' event when a package is uninstalled by something else but this service.
/// </summary>
/// <param name="args"></param>
internal static void OnUninstalledPackage(UninstallPackageEventArgs<UninstallationSummary> args)
{
UninstalledPackage.RaiseEvent(args, null);
}
#region Event Handlers
/// <summary>
/// Occurs before Importing umbraco package
/// </summary>
internal static event TypedEventHandler<IPackagingService, ImportPackageEventArgs<string>> ImportingPackage;
/// <summary>
/// Occurs after a package is imported
/// </summary>
public static event TypedEventHandler<IPackagingService, ImportPackageEventArgs<InstallationSummary>> ImportedPackage;
/// <summary>
/// Occurs after a package is uninstalled
/// </summary>
public static event TypedEventHandler<IPackagingService, UninstallPackageEventArgs<UninstallationSummary>> UninstalledPackage;
#endregion
2017-12-28 09:18:09 +01:00
}
}