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 ;
2019-01-11 14:30:04 +11:00
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 ;
2018-01-15 11:32:30 +01:00
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
{
2019-01-10 12:44:57 +11:00
2019-01-14 17:46:12 +11:00
private readonly IPackageInstallation _packageInstallation ;
2019-01-11 14:30:04 +11:00
private readonly IAuditService _auditService ;
2019-01-11 10:35:37 +11:00
private readonly ICreatedPackagesRepository _createdPackages ;
2019-01-11 14:30:04 +11:00
private readonly IInstalledPackagesRepository _installedPackages ;
2018-10-01 14:32:46 +02:00
private static HttpClient _httpClient ;
2017-12-28 09:18:09 +01:00
public PackagingService (
2019-01-11 14:30:04 +11:00
IAuditService auditService ,
ICreatedPackagesRepository createdPackages ,
2019-01-14 17:46:12 +11:00
IInstalledPackagesRepository installedPackages ,
IPackageInstallation packageInstallation )
{
2019-01-11 14:30:04 +11:00
_auditService = auditService ;
2019-01-11 10:35:37 +11:00
_createdPackages = createdPackages ;
2019-01-11 14:30:04 +11:00
_installedPackages = installedPackages ;
2019-01-14 17:46:12 +11:00
_packageInstallation = packageInstallation ;
2017-12-28 09:18:09 +01:00
}
#region Package Files
2019-01-11 14:30:04 +11:00
/// <inheritdoc />
public async Task < string > FetchPackageFileAsync ( Guid packageId , Version umbracoVersion , int userId )
2017-12-28 09:18:09 +01:00
{
2019-01-11 14:30:04 +11: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
{
2019-01-11 14:30:04 +11:00
if ( _httpClient = = null )
2017-12-28 09:18:09 +01:00
{
2019-01-11 14:30:04 +11:00
_httpClient = new HttpClient ( ) ;
2017-12-28 09:18:09 +01:00
}
2019-01-11 14:30:04 +11: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
2019-01-11 14:30:04 +11:00
//successfull
if ( bytes . Length > 0 )
{
var packagePath = IOHelper . MapPath ( SystemDirectories . Packages ) ;
2017-12-28 09:18:09 +01:00
2019-01-11 14:30:04 +11:00
// Check for package directory
if ( Directory . Exists ( packagePath ) = = false )
Directory . CreateDirectory ( packagePath ) ;
2017-12-28 09:18:09 +01:00
2019-01-11 14:30:04 +11:00
var packageFilePath = Path . Combine ( packagePath , packageId + ".umb" ) ;
2017-12-28 09:18:09 +01:00
2019-01-11 14:30:04 +11:00
using ( var fs1 = new FileStream ( packageFilePath , FileMode . Create ) )
{
fs1 . Write ( bytes , 0 , bytes . Length ) ;
2019-01-14 14:28:00 +11:00
return packageId + ".umb" ;
2017-12-28 09:18:09 +01:00
}
}
2019-01-11 14:30:04 +11: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
2019-01-14 14:28:00 +11:00
public CompiledPackage GetCompiledPackageInfo ( string packageFileName ) = > _packageInstallation . ReadPackage ( packageFileName ) ;
2019-01-10 12:44:57 +11:00
2019-01-14 14:28:00 +11:00
public IEnumerable < string > InstallCompiledPackageFiles ( PackageDefinition packageDefinition , string packageFileName , int userId = 0 )
2017-12-28 09:18:09 +01:00
{
2019-01-14 14:28:00 +11: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
2019-01-14 14:28:00 +11: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
2019-01-14 14:28:00 +11:00
var files = _packageInstallation . InstallPackageFiles ( packageDefinition , compiledPackage , userId ) ;
2019-01-11 14:30:04 +11:00
2019-01-14 14:28:00 +11:00
SaveInstalledPackage ( packageDefinition ) ;
2017-12-28 09:18:09 +01:00
2019-01-14 17:46:12 +11:00
_auditService . Add ( AuditType . PackagerInstall , userId , - 1 , "Package" , $"Package files installed for package '{compiledPackage.Name}'." ) ;
2017-12-28 09:18:09 +01:00
2019-01-14 14:28:00 +11:00
return files ;
2017-12-28 09:18:09 +01:00
}
2019-01-14 14:28:00 +11:00
public InstallationSummary InstallCompiledPackageData ( PackageDefinition packageDefinition , string packageFileName , int userId = 0 )
2017-12-28 09:18:09 +01:00
{
2019-01-14 14:28:00 +11: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
2019-01-14 14:28:00 +11: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 ) ;
2019-01-14 17:46:12 +11:00
SaveInstalledPackage ( packageDefinition ) ;
2019-01-14 14:28:00 +11:00
_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
2019-01-11 14:30:04 +11:00
#region Created / Installed Package Repositories
2019-01-10 12:44:57 +11:00
2019-01-11 14:30:04 +11:00
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 ) ;
}
2019-01-10 17:18:47 +11:00
2019-01-11 10:35:37 +11:00
public IEnumerable < PackageDefinition > GetAllCreatedPackages ( ) = > _createdPackages . GetAll ( ) ;
2019-01-10 17:18:47 +11:00
2019-01-11 10:35:37 +11:00
public PackageDefinition GetCreatedPackageById ( int id ) = > _createdPackages . GetById ( id ) ;
2019-01-10 17:18:47 +11:00
2019-01-11 10:35:37 +11:00
public bool SaveCreatedPackage ( PackageDefinition definition ) = > _createdPackages . SavePackage ( definition ) ;
2019-01-10 17:18:47 +11:00
2019-01-11 10:35:37 +11:00
public string ExportCreatedPackage ( PackageDefinition definition ) = > _createdPackages . ExportPackage ( definition ) ;
2019-01-10 12:44:57 +11:00
2019-01-11 14:30:04 +11:00
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
2019-01-10 12:44:57 +11:00
2017-12-28 09:18:09 +01:00
}
}