2019-01-10 12:44:57 +11:00
using System ;
using System.Collections.Generic ;
2019-01-10 17:18:47 +11:00
using System.ComponentModel.DataAnnotations ;
2019-01-10 12:44:57 +11:00
using System.IO ;
using System.IO.Compression ;
using System.Linq ;
using System.Xml.Linq ;
using Umbraco.Core.Configuration ;
using Umbraco.Core.IO ;
using Umbraco.Core.Logging ;
using Umbraco.Core.Models ;
using Umbraco.Core.Models.Packaging ;
using Umbraco.Core.Services ;
using File = System . IO . File ;
namespace Umbraco.Core.Packaging
{
2019-01-11 14:30:04 +11:00
/// <summary>
/// Manages the storage of installed/created package definitions
/// </summary>
internal class PackagesRepository : ICreatedPackagesRepository , IInstalledPackagesRepository
2019-01-10 12:44:57 +11:00
{
private readonly IContentService _contentService ;
private readonly IContentTypeService _contentTypeService ;
private readonly IDataTypeService _dataTypeService ;
private readonly IFileService _fileService ;
private readonly IMacroService _macroService ;
private readonly ILocalizationService _languageService ;
private readonly IEntityXmlSerializer _serializer ;
private readonly ILogger _logger ;
2019-01-11 14:30:04 +11:00
private readonly string _packageRepositoryFileName ;
2019-01-10 17:18:47 +11:00
private readonly string _mediaFolderPath ;
private readonly string _packagesFolderPath ;
private readonly string _tempFolderPath ;
2019-01-11 14:30:04 +11:00
private readonly PackageDefinitionXmlParser _parser ;
/// <summary>
/// Constructor
/// </summary>
/// <param name="contentService"></param>
/// <param name="contentTypeService"></param>
/// <param name="dataTypeService"></param>
/// <param name="fileService"></param>
/// <param name="macroService"></param>
/// <param name="languageService"></param>
/// <param name="serializer"></param>
/// <param name="logger"></param>
/// <param name="packageRepositoryFileName">
/// The file name for storing the package definitions (i.e. "createdPackages.config")
/// </param>
/// <param name="tempFolderPath"></param>
/// <param name="packagesFolderPath"></param>
/// <param name="mediaFolderPath"></param>
public PackagesRepository ( IContentService contentService , IContentTypeService contentTypeService ,
2019-01-10 12:44:57 +11:00
IDataTypeService dataTypeService , IFileService fileService , IMacroService macroService ,
ILocalizationService languageService ,
2019-01-10 17:18:47 +11:00
IEntityXmlSerializer serializer , ILogger logger ,
2019-01-11 14:30:04 +11:00
string packageRepositoryFileName ,
2019-01-10 17:18:47 +11:00
string tempFolderPath = null , string packagesFolderPath = null , string mediaFolderPath = null )
2019-01-10 12:44:57 +11:00
{
2019-01-11 14:30:04 +11:00
if ( string . IsNullOrWhiteSpace ( packageRepositoryFileName ) ) throw new ArgumentException ( "Value cannot be null or whitespace." , nameof ( packageRepositoryFileName ) ) ;
2019-01-10 12:44:57 +11:00
_contentService = contentService ;
_contentTypeService = contentTypeService ;
_dataTypeService = dataTypeService ;
_fileService = fileService ;
_macroService = macroService ;
_languageService = languageService ;
_serializer = serializer ;
_logger = logger ;
2019-01-11 14:30:04 +11:00
_packageRepositoryFileName = packageRepositoryFileName ;
2019-01-15 22:08:08 +11:00
_tempFolderPath = tempFolderPath ? ? SystemDirectories . TempData . EnsureEndsWith ( '/' ) + "PackageFiles" ;
2019-01-10 17:18:47 +11:00
_packagesFolderPath = packagesFolderPath ? ? SystemDirectories . Packages ;
_mediaFolderPath = mediaFolderPath ? ? SystemDirectories . Media + "/created-packages" ;
2019-01-11 14:30:04 +11:00
_parser = new PackageDefinitionXmlParser ( logger ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-11 14:30:04 +11:00
private string CreatedPackagesFile = > _packagesFolderPath . EnsureEndsWith ( '/' ) + _packageRepositoryFileName ;
2019-01-10 17:18:47 +11:00
public IEnumerable < PackageDefinition > GetAll ( )
{
var packagesXml = EnsureStorage ( out _ ) ;
2019-01-11 14:30:04 +11:00
if ( packagesXml ? . Root = = null )
yield break ; ;
2019-01-10 17:18:47 +11:00
foreach ( var packageXml in packagesXml . Root . Elements ( "package" ) )
2019-01-11 14:30:04 +11:00
yield return _parser . ToPackageDefinition ( packageXml ) ;
2019-01-10 17:18:47 +11:00
}
public PackageDefinition GetById ( int id )
{
var packagesXml = EnsureStorage ( out _ ) ;
2019-01-11 14:30:04 +11:00
var packageXml = packagesXml ? . Root ? . Elements ( "package" ) . FirstOrDefault ( x = > x . AttributeValue < int > ( "id" ) = = id ) ;
return packageXml = = null ? null : _parser . ToPackageDefinition ( packageXml ) ;
2019-01-10 17:18:47 +11:00
}
2019-01-10 12:44:57 +11:00
2019-01-10 17:18:47 +11:00
public void Delete ( int id )
{
var packagesXml = EnsureStorage ( out var packagesFile ) ;
2019-01-11 14:30:04 +11:00
var packageXml = packagesXml ? . Root ? . Elements ( "package" ) . FirstOrDefault ( x = > x . AttributeValue < int > ( "id" ) = = id ) ;
2019-01-10 17:18:47 +11:00
if ( packageXml = = null ) return ;
packageXml . Remove ( ) ;
packagesXml . Save ( packagesFile ) ;
}
public bool SavePackage ( PackageDefinition definition )
2019-01-10 12:44:57 +11:00
{
if ( definition = = null ) throw new ArgumentNullException ( nameof ( definition ) ) ;
var packagesXml = EnsureStorage ( out var packagesFile ) ;
2019-01-11 14:30:04 +11:00
if ( packagesXml ? . Root = = null )
return false ;
2019-01-10 17:18:47 +11:00
//ensure it's valid
ValidatePackage ( definition ) ;
2019-01-10 12:44:57 +11:00
if ( definition . Id = = default )
{
//need to gen an id and persist
// Find max id
2019-01-10 17:18:47 +11:00
var maxId = packagesXml . Root . Elements ( "package" ) . Max ( x = > x . AttributeValue < int? > ( "id" ) ) ? ? 0 ;
2019-01-10 12:44:57 +11:00
var newId = maxId + 1 ;
definition . Id = newId ;
2019-01-11 14:30:04 +11:00
definition . PackageId = definition . PackageId = = default ? Guid . NewGuid ( ) : definition . PackageId ;
var packageXml = _parser . ToXml ( definition ) ;
2019-01-10 17:18:47 +11:00
packagesXml . Root . Add ( packageXml ) ;
2019-01-10 12:44:57 +11:00
}
else
{
//existing
var packageXml = packagesXml . Root . Elements ( "package" ) . FirstOrDefault ( x = > x . AttributeValue < int > ( "id" ) = = definition . Id ) ;
if ( packageXml = = null )
2019-01-10 17:18:47 +11:00
return false ;
2019-01-10 12:44:57 +11:00
2019-01-11 14:30:04 +11:00
var updatedXml = _parser . ToXml ( definition ) ;
2019-01-10 12:44:57 +11:00
packageXml . ReplaceWith ( updatedXml ) ;
}
packagesXml . Save ( packagesFile ) ;
2019-01-10 17:18:47 +11:00
return true ;
2019-01-10 12:44:57 +11:00
}
2019-01-10 17:18:47 +11:00
public string ExportPackage ( PackageDefinition definition )
2019-01-10 12:44:57 +11:00
{
if ( definition . Id = = default ) throw new ArgumentException ( "The package definition does not have an ID, it must be saved before being exported" ) ;
2019-01-10 17:18:47 +11:00
if ( definition . PackageId = = default ) throw new ArgumentException ( "the package definition does not have a GUID, it must be saved before being exported" ) ;
//ensure it's valid
ValidatePackage ( definition ) ;
2019-01-10 12:44:57 +11:00
//Create a folder for building this package
2019-01-14 18:03:06 +11:00
var temporaryPath = IOHelper . MapPath ( _tempFolderPath . EnsureEndsWith ( '/' ) + Guid . NewGuid ( ) ) ;
2019-01-10 12:44:57 +11:00
if ( Directory . Exists ( temporaryPath ) = = false )
Directory . CreateDirectory ( temporaryPath ) ;
try
{
//Init package file
2019-01-16 21:27:14 +11:00
var compiledPackageXml = CreateCompiledPackageXml ( out var root , out var filesXml ) ;
2019-01-10 12:44:57 +11:00
//Info section
2019-01-16 21:27:14 +11:00
root . Add ( GetPackageInfoXml ( definition ) ) ;
2019-01-10 12:44:57 +11:00
2019-01-16 21:27:14 +11:00
PackageDocumentsAndTags ( definition , root ) ;
PackageDocumentTypes ( definition , root ) ;
PackageTemplates ( definition , root ) ;
PackageStylesheets ( definition , root ) ;
PackageMacros ( definition , root , filesXml , temporaryPath ) ;
PackageDictionaryItems ( definition , root ) ;
PackageLanguages ( definition , root ) ;
PackageDataTypes ( definition , root ) ;
2019-01-10 12:44:57 +11:00
//Files
foreach ( var fileName in definition . Files )
2019-01-16 21:27:14 +11:00
AppendFileToPackage ( fileName , temporaryPath , filesXml ) ;
2019-01-10 12:44:57 +11:00
2019-01-16 21:27:14 +11:00
//Load view on install...
2019-01-16 19:30:07 +11:00
if ( ! string . IsNullOrEmpty ( definition . PackageView ) )
2019-01-10 12:44:57 +11:00
{
2019-01-16 19:30:07 +11:00
var control = new XElement ( "view" , definition . PackageView ) ;
2019-01-16 21:27:14 +11:00
AppendFileToPackage ( definition . PackageView , temporaryPath , filesXml ) ;
root . Add ( control ) ;
2019-01-10 12:44:57 +11:00
}
//Actions
if ( string . IsNullOrEmpty ( definition . Actions ) = = false )
{
var actionsXml = new XElement ( "Actions" ) ;
try
{
2019-01-10 18:51:02 +11:00
//this will be formatted like a full xml block like <actions>...</actions> and we want the child nodes
var parsed = XElement . Parse ( definition . Actions ) ;
actionsXml . Add ( parsed . Elements ( ) ) ;
2019-01-16 21:27:14 +11:00
root . Add ( actionsXml ) ;
2019-01-10 12:44:57 +11:00
}
catch ( Exception e )
{
2019-01-16 21:27:14 +11:00
_logger . Warn < PackagesRepository > ( e , "Could not add package actions to the package, the xml did not parse" ) ;
2019-01-10 12:44:57 +11:00
}
}
2019-01-16 21:27:14 +11:00
var packageXmlFileName = temporaryPath + "/package.xml" ;
2019-01-10 12:44:57 +11:00
2019-01-16 21:27:14 +11:00
if ( File . Exists ( packageXmlFileName ) )
File . Delete ( packageXmlFileName ) ;
2019-01-10 12:44:57 +11:00
2019-01-16 21:27:14 +11:00
compiledPackageXml . Save ( packageXmlFileName ) ;
2019-01-10 12:44:57 +11:00
// check if there's a packages directory below media
2019-01-10 17:18:47 +11:00
if ( Directory . Exists ( IOHelper . MapPath ( _mediaFolderPath ) ) = = false )
Directory . CreateDirectory ( IOHelper . MapPath ( _mediaFolderPath ) ) ;
2019-01-10 12:44:57 +11:00
2019-01-10 17:18:47 +11:00
var packPath = _mediaFolderPath . EnsureEndsWith ( '/' ) + ( definition . Name + "_" + definition . Version ) . Replace ( ' ' , '_' ) + ".zip" ;
2019-01-10 12:44:57 +11:00
ZipPackage ( temporaryPath , IOHelper . MapPath ( packPath ) ) ;
2019-01-10 17:18:47 +11:00
//we need to update the package path and save it
definition . PackagePath = packPath ;
SavePackage ( definition ) ;
2019-01-10 12:44:57 +11:00
return packPath ;
}
finally
{
//Clean up
Directory . Delete ( temporaryPath , true ) ;
}
}
2019-01-10 17:18:47 +11:00
private void ValidatePackage ( PackageDefinition definition )
{
//ensure it's valid
var context = new ValidationContext ( definition , serviceProvider : null , items : null ) ;
var results = new List < ValidationResult > ( ) ;
var isValid = Validator . TryValidateObject ( definition , context , results ) ;
if ( ! isValid )
throw new InvalidOperationException ( "Validation failed, there is invalid data on the model: " + string . Join ( ", " , results . Select ( x = > x . ErrorMessage ) ) ) ;
}
2019-01-16 21:27:14 +11:00
private void PackageDataTypes ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
var dataTypes = new XElement ( "DataTypes" ) ;
foreach ( var dtId in definition . DataTypes )
{
if ( ! int . TryParse ( dtId , out var outInt ) ) continue ;
var dataType = _dataTypeService . GetDataType ( outInt ) ;
if ( dataType = = null ) continue ;
dataTypes . Add ( _serializer . Serialize ( dataType ) ) ;
}
2019-01-16 21:27:14 +11:00
root . Add ( dataTypes ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageLanguages ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
var languages = new XElement ( "Languages" ) ;
foreach ( var langId in definition . Languages )
{
if ( ! int . TryParse ( langId , out var outInt ) ) continue ;
var lang = _languageService . GetLanguageById ( outInt ) ;
if ( lang = = null ) continue ;
languages . Add ( _serializer . Serialize ( lang ) ) ;
}
2019-01-16 21:27:14 +11:00
root . Add ( languages ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageDictionaryItems ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
var dictionaryItems = new XElement ( "DictionaryItems" ) ;
foreach ( var dictionaryId in definition . DictionaryItems )
{
if ( ! int . TryParse ( dictionaryId , out var outInt ) ) continue ;
var di = _languageService . GetDictionaryItemById ( outInt ) ;
if ( di = = null ) continue ;
dictionaryItems . Add ( _serializer . Serialize ( di , false ) ) ;
}
2019-01-16 21:27:14 +11:00
root . Add ( dictionaryItems ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageMacros ( PackageDefinition definition , XContainer root , XContainer filesXml , string temporaryPath )
2019-01-10 12:44:57 +11:00
{
var macros = new XElement ( "Macros" ) ;
foreach ( var macroId in definition . Macros )
{
if ( ! int . TryParse ( macroId , out var outInt ) ) continue ;
var macroXml = GetMacroXml ( outInt , out var macro ) ;
if ( macroXml = = null ) continue ;
macros . Add ( macroXml ) ;
2019-01-16 21:27:14 +11:00
//if the macro has a file copy it to the xml
2019-01-10 12:44:57 +11:00
if ( ! string . IsNullOrEmpty ( macro . MacroSource ) )
2019-01-16 21:27:14 +11:00
AppendFileToPackage ( macro . MacroSource , temporaryPath , filesXml ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
root . Add ( macros ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageStylesheets ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
var stylesheetsXml = new XElement ( "Stylesheets" ) ;
foreach ( var stylesheetName in definition . Stylesheets )
{
if ( stylesheetName . IsNullOrWhiteSpace ( ) ) continue ;
var xml = GetStylesheetXml ( stylesheetName , true ) ;
if ( xml ! = null )
stylesheetsXml . Add ( xml ) ;
}
2019-01-16 21:27:14 +11:00
root . Add ( stylesheetsXml ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageTemplates ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
var templatesXml = new XElement ( "Templates" ) ;
foreach ( var templateId in definition . Templates )
{
if ( ! int . TryParse ( templateId , out var outInt ) ) continue ;
var template = _fileService . GetTemplate ( outInt ) ;
if ( template = = null ) continue ;
templatesXml . Add ( _serializer . Serialize ( template ) ) ;
}
2019-01-16 21:27:14 +11:00
root . Add ( templatesXml ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageDocumentTypes ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
var contentTypes = new HashSet < IContentType > ( ) ;
var docTypesXml = new XElement ( "DocumentTypes" ) ;
foreach ( var dtId in definition . DocumentTypes )
{
if ( ! int . TryParse ( dtId , out var outInt ) ) continue ;
var contentType = _contentTypeService . Get ( outInt ) ;
if ( contentType = = null ) continue ;
AddDocumentType ( contentType , contentTypes ) ;
}
foreach ( var contentType in contentTypes )
docTypesXml . Add ( _serializer . Serialize ( contentType ) ) ;
2019-01-16 21:27:14 +11:00
root . Add ( docTypesXml ) ;
2019-01-10 12:44:57 +11:00
}
2019-01-16 21:27:14 +11:00
private void PackageDocumentsAndTags ( PackageDefinition definition , XContainer root )
2019-01-10 12:44:57 +11:00
{
//Documents and tags
if ( string . IsNullOrEmpty ( definition . ContentNodeId ) = = false & & int . TryParse ( definition . ContentNodeId , out var contentNodeId ) )
{
if ( contentNodeId > 0 )
{
//load content from umbraco.
var content = _contentService . GetById ( contentNodeId ) ;
if ( content ! = null )
{
var contentXml = definition . ContentLoadChildNodes ? content . ToDeepXml ( _serializer ) : content . ToXml ( _serializer ) ;
//Create the Documents/DocumentSet node
2019-01-16 21:27:14 +11:00
root . Add (
2019-01-10 12:44:57 +11:00
new XElement ( "Documents" ,
new XElement ( "DocumentSet" ,
new XAttribute ( "importMode" , "root" ) ,
contentXml ) ) ) ;
2019-01-27 01:17:32 -05:00
// TODO: I guess tags has been broken for a very long time for packaging, we should get this working again sometime
2019-01-10 12:44:57 +11:00
////Create the TagProperties node - this is used to store a definition for all
//// document properties that are tags, this ensures that we can re-import tags properly
//XmlNode tagProps = new XElement("TagProperties");
////before we try to populate this, we'll do a quick lookup to see if any of the documents
//// being exported contain published tags.
//var allExportedIds = documents.SelectNodes("//@id").Cast<XmlNode>()
// .Select(x => x.Value.TryConvertTo<int>())
// .Where(x => x.Success)
// .Select(x => x.Result)
// .ToArray();
//var allContentTags = new List<ITag>();
//foreach (var exportedId in allExportedIds)
//{
// allContentTags.AddRange(
// Current.Services.TagService.GetTagsForEntity(exportedId));
//}
////This is pretty round-about but it works. Essentially we need to get the properties that are tagged
//// but to do that we need to lookup by a tag (string)
//var allTaggedEntities = new List<TaggedEntity>();
//foreach (var group in allContentTags.Select(x => x.Group).Distinct())
//{
// allTaggedEntities.AddRange(
// Current.Services.TagService.GetTaggedContentByTagGroup(group));
//}
////Now, we have all property Ids/Aliases and their referenced document Ids and tags
//var allExportedTaggedEntities = allTaggedEntities.Where(x => allExportedIds.Contains(x.EntityId))
// .DistinctBy(x => x.EntityId)
// .OrderBy(x => x.EntityId);
//foreach (var taggedEntity in allExportedTaggedEntities)
//{
// foreach (var taggedProperty in taggedEntity.TaggedProperties.Where(x => x.Tags.Any()))
// {
// XmlNode tagProp = new XElement("TagProperty");
// var docId = packageManifest.CreateAttribute("docId", "");
// docId.Value = taggedEntity.EntityId.ToString(CultureInfo.InvariantCulture);
// tagProp.Attributes.Append(docId);
// var propertyAlias = packageManifest.CreateAttribute("propertyAlias", "");
// propertyAlias.Value = taggedProperty.PropertyTypeAlias;
// tagProp.Attributes.Append(propertyAlias);
// var group = packageManifest.CreateAttribute("group", "");
// group.Value = taggedProperty.Tags.First().Group;
// tagProp.Attributes.Append(group);
// tagProp.AppendChild(packageManifest.CreateCDataSection(
// JsonConvert.SerializeObject(taggedProperty.Tags.Select(x => x.Text).ToArray())));
// tagProps.AppendChild(tagProp);
// }
//}
//manifestRoot.Add(tagProps);
}
}
}
}
/// <summary>
/// Zips the package.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="savePath">The save path.</param>
private static void ZipPackage ( string path , string savePath )
{
2019-01-10 17:18:47 +11:00
if ( File . Exists ( savePath ) )
File . Delete ( savePath ) ;
2019-01-10 12:44:57 +11:00
ZipFile . CreateFromDirectory ( path , savePath ) ;
}
/// <summary>
2019-01-16 21:27:14 +11:00
/// Appends a file to package and copies the file to the correct folder.
2019-01-10 12:44:57 +11:00
/// </summary>
/// <param name="path">The path.</param>
/// <param name="packageDirectory">The package directory.</param>
/// <param name="filesXml">The files xml node</param>
2019-01-16 21:27:14 +11:00
private static void AppendFileToPackage ( string path , string packageDirectory , XContainer filesXml )
2019-01-10 12:44:57 +11:00
{
if ( ! path . StartsWith ( "~/" ) & & ! path . StartsWith ( "/" ) )
path = "~/" + path ;
var serverPath = IOHelper . MapPath ( path ) ;
if ( File . Exists ( serverPath ) )
AppendFileXml ( new FileInfo ( serverPath ) , path , packageDirectory , filesXml ) ;
else if ( Directory . Exists ( serverPath ) )
ProcessDirectory ( new DirectoryInfo ( serverPath ) , path , packageDirectory , filesXml ) ;
}
//Process files in directory and add them to package
private static void ProcessDirectory ( DirectoryInfo directory , string dirPath , string packageDirectory , XContainer filesXml )
{
if ( directory = = null ) throw new ArgumentNullException ( nameof ( directory ) ) ;
if ( string . IsNullOrWhiteSpace ( packageDirectory ) ) throw new ArgumentException ( "Value cannot be null or whitespace." , nameof ( packageDirectory ) ) ;
if ( string . IsNullOrWhiteSpace ( dirPath ) ) throw new ArgumentException ( "Value cannot be null or whitespace." , nameof ( dirPath ) ) ;
if ( ! directory . Exists ) return ;
foreach ( var file in directory . GetFiles ( ) )
AppendFileXml ( new FileInfo ( Path . Combine ( directory . FullName , file . Name ) ) , dirPath + "/" + file . Name , packageDirectory , filesXml ) ;
foreach ( var dir in directory . GetDirectories ( ) )
ProcessDirectory ( dir , dirPath + "/" + dir . Name , packageDirectory , filesXml ) ;
}
private static void AppendFileXml ( FileInfo file , string filePath , string packageDirectory , XContainer filesXml )
{
if ( file = = null ) throw new ArgumentNullException ( nameof ( file ) ) ;
if ( string . IsNullOrWhiteSpace ( filePath ) ) throw new ArgumentException ( "Value cannot be null or whitespace." , nameof ( filePath ) ) ;
if ( string . IsNullOrWhiteSpace ( packageDirectory ) ) throw new ArgumentException ( "Value cannot be null or whitespace." , nameof ( packageDirectory ) ) ;
var orgPath = filePath . Substring ( 0 , ( filePath . LastIndexOf ( '/' ) ) ) ;
var orgName = filePath . Substring ( ( filePath . LastIndexOf ( '/' ) + 1 ) ) ;
var newFileName = orgName ;
if ( File . Exists ( packageDirectory . EnsureEndsWith ( '/' ) + orgName ) )
newFileName = Guid . NewGuid ( ) + "_" + newFileName ;
//Copy file to directory for zipping...
File . Copy ( file . FullName , packageDirectory + "/" + newFileName , true ) ;
filesXml . Add ( new XElement ( "file" ,
new XElement ( "guid" , newFileName ) ,
new XElement ( "orgPath" , orgPath = = "" ? "/" : orgPath ) ,
new XElement ( "orgName" , orgName ) ) ) ;
}
private XElement GetMacroXml ( int macroId , out IMacro macro )
{
macro = _macroService . GetById ( macroId ) ;
if ( macro = = null ) return null ;
var xml = _serializer . Serialize ( macro ) ;
return xml ;
}
/// <summary>
/// Converts a umbraco stylesheet to a package xml node
/// </summary>
/// <param name="name">The name of the stylesheet.</param>
2019-01-22 18:03:39 -05:00
/// <param name="includeProperties">if set to <c>true</c> [include properties].</param>
2019-01-10 12:44:57 +11:00
/// <returns></returns>
private XElement GetStylesheetXml ( string name , bool includeProperties )
{
if ( string . IsNullOrWhiteSpace ( name ) ) throw new ArgumentException ( "Value cannot be null or whitespace." , nameof ( name ) ) ;
;
var sts = _fileService . GetStylesheetByName ( name ) ;
if ( sts = = null ) return null ;
var stylesheetXml = new XElement ( "Stylesheet" ) ;
stylesheetXml . Add ( new XElement ( "Name" , sts . Alias ) ) ;
stylesheetXml . Add ( new XElement ( "FileName" , sts . Name ) ) ;
stylesheetXml . Add ( new XElement ( "Content" , new XCData ( sts . Content ) ) ) ;
if ( ! includeProperties ) return stylesheetXml ;
var properties = new XElement ( "Properties" ) ;
foreach ( var ssP in sts . Properties )
{
var property = new XElement ( "Property" ) ;
property . Add ( new XElement ( "Name" , ssP . Name ) ) ;
property . Add ( new XElement ( "Alias" , ssP . Alias ) ) ;
property . Add ( new XElement ( "Value" , ssP . Value ) ) ;
}
stylesheetXml . Add ( properties ) ;
return stylesheetXml ;
}
private void AddDocumentType ( IContentType dt , HashSet < IContentType > dtl )
{
if ( dt . ParentId > 0 )
{
var parent = _contentTypeService . Get ( dt . ParentId ) ;
if ( parent ! = null ) // could be a container
AddDocumentType ( parent , dtl ) ;
}
if ( ! dtl . Contains ( dt ) )
dtl . Add ( dt ) ;
}
private static XElement GetPackageInfoXml ( PackageDefinition definition )
{
var info = new XElement ( "info" ) ;
//Package info
var package = new XElement ( "package" ) ;
package . Add ( new XElement ( "name" , definition . Name ) ) ;
package . Add ( new XElement ( "version" , definition . Version ) ) ;
package . Add ( new XElement ( "iconUrl" , definition . IconUrl ) ) ;
var license = new XElement ( "license" , definition . License ) ;
license . Add ( new XAttribute ( "url" , definition . LicenseUrl ) ) ;
package . Add ( license ) ;
package . Add ( new XElement ( "url" , definition . Url ) ) ;
var requirements = new XElement ( "requirements" ) ;
requirements . Add ( new XElement ( "major" , definition . UmbracoVersion = = null ? UmbracoVersion . SemanticVersion . Major . ToInvariantString ( ) : definition . UmbracoVersion . Major . ToInvariantString ( ) ) ) ;
requirements . Add ( new XElement ( "minor" , definition . UmbracoVersion = = null ? UmbracoVersion . SemanticVersion . Minor . ToInvariantString ( ) : definition . UmbracoVersion . Minor . ToInvariantString ( ) ) ) ;
requirements . Add ( new XElement ( "patch" , definition . UmbracoVersion = = null ? UmbracoVersion . SemanticVersion . Patch . ToInvariantString ( ) : definition . UmbracoVersion . Build . ToInvariantString ( ) ) ) ;
if ( definition . UmbracoVersion ! = null )
2019-01-10 17:18:47 +11:00
requirements . Add ( new XAttribute ( "type" , RequirementsType . Strict . ToString ( ) ) ) ;
2019-01-10 12:44:57 +11:00
package . Add ( requirements ) ;
info . Add ( package ) ;
2019-02-14 16:00:58 +01:00
// Author
2019-01-10 12:44:57 +11:00
var author = new XElement ( "author" , "" ) ;
author . Add ( new XElement ( "name" , definition . Author ) ) ;
author . Add ( new XElement ( "website" , definition . AuthorUrl ) ) ;
info . Add ( author ) ;
2019-02-14 16:00:58 +01:00
// Contributors
var contributors = new XElement ( "contributors" , "" ) ;
if ( definition . Contributors ! = null & & definition . Contributors . Any ( ) )
{
foreach ( var contributor in definition . Contributors )
{
contributors . Add ( new XElement ( "contributor" , contributor ) ) ;
}
}
info . Add ( contributors ) ;
2019-01-10 12:44:57 +11:00
info . Add ( new XElement ( "readme" , new XCData ( definition . Readme ) ) ) ;
return info ;
}
2019-01-16 21:27:14 +11:00
private static XDocument CreateCompiledPackageXml ( out XElement root , out XElement files )
2019-01-10 12:44:57 +11:00
{
files = new XElement ( "files" ) ;
root = new XElement ( "umbPackage" , files ) ;
2019-01-16 21:27:14 +11:00
var compiledPackageXml = new XDocument ( root ) ;
return compiledPackageXml ;
2019-01-10 12:44:57 +11:00
}
2019-01-10 17:18:47 +11:00
private XDocument EnsureStorage ( out string packagesFile )
2019-01-10 12:44:57 +11:00
{
2019-01-10 17:18:47 +11:00
var packagesFolder = IOHelper . MapPath ( _packagesFolderPath ) ;
2019-01-10 12:44:57 +11:00
//ensure it exists
Directory . CreateDirectory ( packagesFolder ) ;
packagesFile = IOHelper . MapPath ( CreatedPackagesFile ) ;
if ( ! File . Exists ( packagesFile ) )
{
var xml = new XDocument ( new XElement ( "packages" ) ) ;
xml . Save ( packagesFile ) ;
}
var packagesXml = XDocument . Load ( packagesFile ) ;
return packagesXml ;
}
}
}