Merge pull request #1010 from umbraco/temp-U4-7557

U4-7557 Support folders for import/export, packaging
This commit is contained in:
Shannon Deminick
2016-01-12 16:17:14 +01:00
13 changed files with 351 additions and 60 deletions

View File

@@ -47,6 +47,12 @@ namespace Umbraco.Core.Persistence.Repositories
return nodeDto == null ? null : CreateEntity(nodeDto);
}
public IEnumerable<EntityContainer> Get(string name, int level, Guid umbracoObjectTypeId)
{
var sql = GetBaseQuery(false).Where("text=@name AND level=@level AND nodeObjectType=@umbracoObjectTypeId", new { name, level, umbracoObjectTypeId });
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
}
protected override IEnumerable<EntityContainer> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();

View File

@@ -142,16 +142,25 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<EntityContainer> GetMediaTypeContainers(string name, int level)
{
var uow = UowProvider.GetUnitOfWork();
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
{
return repo.Get(name, level, Constants.ObjectTypes.MediaTypeContainerGuid);
}
}
public EntityContainer GetContentTypeContainer(Guid containerId)
{
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeGuid);
}
public EntityContainer GetMediaTypeContainer(Guid containerId)
{
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeGuid);
}
private EntityContainer GetContainer(Guid containerId, Guid containedObjectType)
{
var uow = UowProvider.GetUnitOfWork();
@@ -164,6 +173,15 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<EntityContainer> GetContentTypeContainers(string name, int level)
{
var uow = UowProvider.GetUnitOfWork();
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
{
return repo.Get(name, level, Constants.ObjectTypes.DocumentTypeContainerGuid);
}
}
public void DeleteContentTypeContainer(int containerId, int userId = 0)
{
var uow = UowProvider.GetUnitOfWork();

View File

@@ -78,6 +78,15 @@ namespace Umbraco.Core.Services
}
}
public IEnumerable<EntityContainer> GetContainers(string name, int level)
{
var uow = UowProvider.GetUnitOfWork();
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
{
return repo.Get(name, level, Constants.ObjectTypes.DataTypeContainerGuid);
}
}
public void SaveContainer(EntityContainer container, int userId = 0)
{
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http.Formatting;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
@@ -138,6 +140,18 @@ namespace Umbraco.Core.Services
/// <param name="dataTypeDefinition">IDataTypeDefinition type to export</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IDataTypeDefinition dataTypeDefinition)
{
return Serialize(dataTypeService, dataTypeDefinition, string.Empty);
}
/// <summary>
/// Exports an <see cref="IDataTypeDefinition"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="dataTypeService"></param>
/// <param name="dataTypeDefinition">IDataTypeDefinition type to export</param>
/// <param name="folders">The path of folders for this data type separated by a backslash, for example: `SEO/Meta`</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IDataTypeDefinition dataTypeDefinition, string folders)
{
var prevalues = new XElement("PreValues");
var prevalueList = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id)
@@ -161,6 +175,8 @@ namespace Umbraco.Core.Services
xml.Add(new XAttribute("Id", dataTypeDefinition.PropertyEditorAlias));
xml.Add(new XAttribute("Definition", dataTypeDefinition.Key));
xml.Add(new XAttribute("DatabaseType", dataTypeDefinition.DatabaseType.ToString()));
if(string.IsNullOrWhiteSpace(folders) == false)
xml.Add(new XAttribute("Folders", folders));
return xml;
}
@@ -324,6 +340,18 @@ namespace Umbraco.Core.Services
/// <param name="contentType">Content type to export</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IContentType object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IContentType contentType)
{
return Serialize(dataTypeService, contentType, string.Empty);
}
/// <summary>
/// Exports an <see cref="IContentType"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="dataTypeService"></param>
/// <param name="contentType">Content type to export</param>
/// <param name="folders">The path of folders for this content type separated by a backslash, for example: `SEO/Meta`</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IContentType object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IContentType contentType, string folders)
{
var info = new XElement("Info",
new XElement("Name", contentType.Name),
@@ -397,11 +425,16 @@ namespace Umbraco.Core.Services
tabs.Add(tab);
}
return new XElement("DocumentType",
info,
structure,
genericProperties,
tabs);
var xml = new XElement("DocumentType",
info,
structure,
genericProperties,
tabs);
if(string.IsNullOrWhiteSpace(folders) == false)
xml.Add(new XAttribute("Folders", folders));
return xml;
}
/// <summary>

View File

@@ -27,8 +27,10 @@ namespace Umbraco.Core.Services
void SaveMediaTypeContainer(EntityContainer container, int userId = 0);
EntityContainer GetContentTypeContainer(int containerId);
EntityContainer GetContentTypeContainer(Guid containerId);
IEnumerable<EntityContainer> GetContentTypeContainers(string folderName, int level);
EntityContainer GetMediaTypeContainer(int containerId);
EntityContainer GetMediaTypeContainer(Guid containerId);
IEnumerable<EntityContainer> GetMediaTypeContainers(string folderName, int level);
void DeleteMediaTypeContainer(int folderId, int userId = 0);
void DeleteContentTypeContainer(int containerId, int userId = 0);

View File

@@ -14,6 +14,7 @@ namespace Umbraco.Core.Services
void SaveContainer(EntityContainer container, int userId = 0);
EntityContainer GetContainer(int containerId);
EntityContainer GetContainer(Guid containerId);
IEnumerable<EntityContainer> GetContainers(string folderName, int level);
void DeleteContainer(int containerId, int userId = 0);
/// <summary>

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using System.Xml.XPath;
using Newtonsoft.Json;
@@ -11,12 +13,14 @@ using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Packaging;
using Umbraco.Core.Packaging.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
using Content = Umbraco.Core.Models.Content;
namespace Umbraco.Core.Services
{
@@ -34,6 +38,7 @@ namespace Umbraco.Core.Services
private readonly IDataTypeService _dataTypeService;
private readonly IFileService _fileService;
private readonly ILocalizationService _localizationService;
private readonly IEntityService _entityService;
private readonly RepositoryFactory _repositoryFactory;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private Dictionary<string, IContentType> _importedContentTypes;
@@ -50,6 +55,7 @@ namespace Umbraco.Core.Services
IDataTypeService dataTypeService,
IFileService fileService,
ILocalizationService localizationService,
IEntityService entityService,
IUserService userService,
RepositoryFactory repositoryFactory,
IDatabaseUnitOfWorkProvider uowProvider)
@@ -62,6 +68,7 @@ namespace Umbraco.Core.Services
_dataTypeService = dataTypeService;
_fileService = fileService;
_localizationService = localizationService;
_entityService = entityService;
_repositoryFactory = repositoryFactory;
_uowProvider = uowProvider;
_userService = userService;
@@ -344,6 +351,9 @@ namespace Umbraco.Core.Services
//Otherwise something like uSync won't work.
var fields = new List<TopologicalSorter.DependencyField<XElement>>();
var isSingleDocTypeImport = unsortedDocumentTypes.Count == 1;
var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes);
if (isSingleDocTypeImport == false)
{
//NOTE Here we sort the doctype XElements based on dependencies
@@ -404,6 +414,15 @@ namespace Umbraco.Core.Services
}
}
foreach (var contentType in _importedContentTypes)
{
var ct = contentType.Value;
if (importedFolders.ContainsKey(ct.Alias))
{
ct.ParentId = importedFolders[ct.Alias];
}
}
//Save the newly created/updated IContentType objects
var list = _importedContentTypes.Select(x => x.Value).ToList();
_contentTypeService.Save(list, userId);
@@ -435,6 +454,65 @@ namespace Umbraco.Core.Services
return list;
}
private Dictionary<string, int> CreateContentTypeFolderStructure(IEnumerable<XElement> unsortedDocumentTypes)
{
var importedFolders = new Dictionary<string, int>();
foreach (var documentType in unsortedDocumentTypes)
{
var foldersAttribute = documentType.Attribute("Folders");
if (foldersAttribute != null)
{
var alias = documentType.Element("Info").Element("Alias").Value;
var folders = foldersAttribute.Value.Split('/');
var rootFolder = HttpUtility.UrlDecode(folders[0]);
//level 1 = root level folders, there can only be one with the same name
var current = _contentTypeService.GetContentTypeContainers(rootFolder, 1).FirstOrDefault();
if (current == null)
{
var tryCreateFolder = _contentTypeService.CreateContentTypeContainer(-1, rootFolder);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
throw tryCreateFolder.Exception;
}
var rootFolderId = tryCreateFolder.Result;
current = _contentTypeService.GetContentTypeContainer(rootFolderId);
}
importedFolders.Add(alias, current.Id);
for (var i = 1; i < folders.Length; i++)
{
var folderName = HttpUtility.UrlDecode(folders[i]);
current = CreateContentTypeChildFolder(folderName, current);
importedFolders[alias] = current.Id;
}
}
}
return importedFolders;
}
private EntityContainer CreateContentTypeChildFolder(string folderName, IUmbracoEntity current)
{
var children = _entityService.GetChildren(current.Id).ToArray();
var found = children.Any(x => x.Name.InvariantEquals(folderName));
if (found)
{
var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id;
return _contentTypeService.GetContentTypeContainer(containerId);
}
var tryCreateFolder = _contentTypeService.CreateContentTypeContainer(current.Id, folderName);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
throw tryCreateFolder.Exception;
}
return _contentTypeService.GetContentTypeContainer(tryCreateFolder.Result);
}
private IContentType CreateContentTypeFromXml(XElement documentType)
{
var infoElement = documentType.Element("Info");
@@ -657,13 +735,13 @@ namespace Umbraco.Core.Services
if (sortOrderElement != null)
int.TryParse(sortOrderElement.Value, out sortOrder);
var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value)
{
Name = property.Element("Name").Value,
Description = property.Element("Description") != null ? property.Element("Description").Value : null,
Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false,
ValidationRegExp = property.Element("Validation") != null ? property.Element("Validation").Value : null,
SortOrder = sortOrder
};
{
Name = property.Element("Name").Value,
Description = property.Element("Description") != null ? property.Element("Description").Value : null,
Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false,
ValidationRegExp = property.Element("Validation") != null ? property.Element("Validation").Value : null,
SortOrder = sortOrder
};
var tab = property.Element("Tab").Value;
if (string.IsNullOrEmpty(tab))
@@ -801,6 +879,8 @@ namespace Umbraco.Core.Services
? (from doc in element.Elements("DataType") select doc).ToList()
: new List<XElement> { element };
var importedFolders = CreateDataTypeFolderStructure(dataTypeElements);
foreach (var dataTypeElement in dataTypeElements)
{
var dataTypeDefinitionName = dataTypeElement.Attribute("Name").Value;
@@ -811,6 +891,10 @@ namespace Umbraco.Core.Services
var dataTypeDefinitionId = new Guid(dataTypeElement.Attribute("Definition").Value);
var databaseTypeAttribute = dataTypeElement.Attribute("DatabaseType");
var parentId = -1;
if (importedFolders.ContainsKey(dataTypeDefinitionName))
parentId = importedFolders[dataTypeDefinitionName];
var definition = _dataTypeService.GetDataTypeDefinitionById(dataTypeDefinitionId);
//If the datatypedefinition doesn't already exist we create a new new according to the one in the package xml
if (definition == null)
@@ -823,11 +907,12 @@ namespace Umbraco.Core.Services
if (legacyPropertyEditorId != Guid.Empty)
{
var dataTypeDefinition = new DataTypeDefinition(-1, legacyPropertyEditorId)
{
Key = dataTypeDefinitionId,
Name = dataTypeDefinitionName,
DatabaseType = databaseType
};
{
Key = dataTypeDefinitionId,
Name = dataTypeDefinitionName,
DatabaseType = databaseType,
ParentId = parentId
};
dataTypes.Add(dataTypeDefinitionName, dataTypeDefinition);
}
else
@@ -837,12 +922,18 @@ namespace Umbraco.Core.Services
{
Key = dataTypeDefinitionId,
Name = dataTypeDefinitionName,
DatabaseType = databaseType
DatabaseType = databaseType,
ParentId = parentId
};
dataTypes.Add(dataTypeDefinitionName, dataTypeDefinition);
}
}
else
{
definition.ParentId = parentId;
_dataTypeService.Save(definition, userId);
}
}
var list = dataTypes.Select(x => x.Value).ToList();
@@ -865,6 +956,64 @@ namespace Umbraco.Core.Services
return list;
}
private Dictionary<string, int> CreateDataTypeFolderStructure(IEnumerable<XElement> datatypeElements)
{
var importedFolders = new Dictionary<string, int>();
foreach (var datatypeElement in datatypeElements)
{
var foldersAttribute = datatypeElement.Attribute("Folders");
if (foldersAttribute != null)
{
var name = datatypeElement.Attribute("Name").Value;
var folders = foldersAttribute.Value.Split('/');
var rootFolder = HttpUtility.UrlDecode(folders[0]);
//there will only be a single result by name for level 1 (root) containers
var current = _dataTypeService.GetContainers(rootFolder, 1).FirstOrDefault();
if (current == null)
{
var tryCreateFolder = _dataTypeService.CreateContainer(-1, rootFolder);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + rootFolder, tryCreateFolder.Exception);
throw tryCreateFolder.Exception;
}
current = _dataTypeService.GetContainer(tryCreateFolder.Result);
}
importedFolders.Add(name, current.Id);
for (var i = 1; i < folders.Length; i++)
{
var folderName = HttpUtility.UrlDecode(folders[i]);
current = CreateDataTypeChildFolder(folderName, current);
importedFolders[name] = current.Id;
}
}
}
return importedFolders;
}
private EntityContainer CreateDataTypeChildFolder(string folderName, IUmbracoEntity current)
{
var children = _entityService.GetChildren(current.Id).ToArray();
var found = children.Any(x => x.Name.InvariantEquals(folderName));
if (found)
{
var containerId = children.Single(x => x.Name.InvariantEquals(folderName)).Id;
return _dataTypeService.GetContainer(containerId);
}
var tryCreateFolder = _dataTypeService.CreateContainer(current.Id, folderName);
if (tryCreateFolder == false)
{
_logger.Error<PackagingService>("Could not create folder: " + folderName, tryCreateFolder.Exception);
throw tryCreateFolder.Exception;
}
return _dataTypeService.GetContainer(tryCreateFolder.Result);
}
private void SavePrevaluesFromXml(List<IDataTypeDefinition> dataTypes, IEnumerable<XElement> dataTypeElements)
{
foreach (var dataTypeElement in dataTypeElements)
@@ -1104,9 +1253,9 @@ namespace Umbraco.Core.Services
if (existingLanguage == null)
{
var langauge = new Language(isoCode)
{
CultureName = languageElement.Attribute("FriendlyName").Value
};
{
CultureName = languageElement.Attribute("FriendlyName").Value
};
_localizationService.Save(langauge);
list.Add(langauge);
}
@@ -1388,11 +1537,11 @@ namespace Umbraco.Core.Services
}
var field = new TopologicalSorter.DependencyField<XElement>
{
Alias = elementCopy.Element("Alias").Value,
Item = new Lazy<XElement>(() => elementCopy),
DependsOn = dependencies.ToArray()
};
{
Alias = elementCopy.Element("Alias").Value,
Item = new Lazy<XElement>(() => elementCopy),
DependsOn = dependencies.ToArray()
};
fields.Add(field);
}

View File

@@ -279,15 +279,15 @@ namespace Umbraco.Core.Services
if (_localizationService == null)
_localizationService = new Lazy<ILocalizationService>(() => new LocalizationService(provider, repositoryFactory, logger, eventMessagesFactory));
if (_packagingService == null)
_packagingService = new Lazy<IPackagingService>(() => new PackagingService(logger, _contentService.Value, _contentTypeService.Value, _mediaService.Value, _macroService.Value, _dataTypeService.Value, _fileService.Value, _localizationService.Value, _userService.Value, repositoryFactory, provider));
if (_entityService == null)
_entityService = new Lazy<IEntityService>(() => new EntityService(
provider, repositoryFactory, logger, eventMessagesFactory,
provider, repositoryFactory, logger, eventMessagesFactory,
_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value,
//TODO: Consider making this an isolated cache instead of using the global one
cache.RuntimeCache));
if (_packagingService == null)
_packagingService = new Lazy<IPackagingService>(() => new PackagingService(logger, _contentService.Value, _contentTypeService.Value, _mediaService.Value, _macroService.Value, _dataTypeService.Value, _fileService.Value, _localizationService.Value, _entityService.Value, _userService.Value, repositoryFactory, provider));
if (_relationService == null)
_relationService = new Lazy<IRelationService>(() => new RelationService(provider, repositoryFactory, logger, eventMessagesFactory, _entityService.Value));