diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityContainerRepository.cs index 6fd5045e04..f782b47ac1 100644 --- a/src/Umbraco.Core/Persistence/Repositories/EntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/EntityContainerRepository.cs @@ -47,6 +47,12 @@ namespace Umbraco.Core.Persistence.Repositories return nodeDto == null ? null : CreateEntity(nodeDto); } + public IEnumerable 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(sql).Select(CreateEntity); + } + protected override IEnumerable PerformGetAll(params int[] ids) { throw new NotImplementedException(); diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index ab3be7aaeb..92a2d6516e 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -142,16 +142,25 @@ namespace Umbraco.Core.Services } } + public IEnumerable 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 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(); diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index bd505ec283..4259a17035 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -78,6 +78,15 @@ namespace Umbraco.Core.Services } } + public IEnumerable 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) diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 09c4dfcf48..193fa24577 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -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 /// IDataTypeDefinition type to export /// containing the xml representation of the IDataTypeDefinition object public XElement Serialize(IDataTypeService dataTypeService, IDataTypeDefinition dataTypeDefinition) + { + return Serialize(dataTypeService, dataTypeDefinition, string.Empty); + } + + /// + /// Exports an item to xml as an + /// + /// + /// IDataTypeDefinition type to export + /// The path of folders for this data type separated by a backslash, for example: `SEO/Meta` + /// containing the xml representation of the IDataTypeDefinition object + 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 /// Content type to export /// containing the xml representation of the IContentType object public XElement Serialize(IDataTypeService dataTypeService, IContentType contentType) + { + return Serialize(dataTypeService, contentType, string.Empty); + } + + /// + /// Exports an item to xml as an + /// + /// + /// Content type to export + /// The path of folders for this content type separated by a backslash, for example: `SEO/Meta` + /// containing the xml representation of the IContentType object + 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; } /// diff --git a/src/Umbraco.Core/Services/IContentTypeService.cs b/src/Umbraco.Core/Services/IContentTypeService.cs index 2fa92f2311..5fdadb6208 100644 --- a/src/Umbraco.Core/Services/IContentTypeService.cs +++ b/src/Umbraco.Core/Services/IContentTypeService.cs @@ -27,8 +27,10 @@ namespace Umbraco.Core.Services void SaveMediaTypeContainer(EntityContainer container, int userId = 0); EntityContainer GetContentTypeContainer(int containerId); EntityContainer GetContentTypeContainer(Guid containerId); + IEnumerable GetContentTypeContainers(string folderName, int level); EntityContainer GetMediaTypeContainer(int containerId); EntityContainer GetMediaTypeContainer(Guid containerId); + IEnumerable GetMediaTypeContainers(string folderName, int level); void DeleteMediaTypeContainer(int folderId, int userId = 0); void DeleteContentTypeContainer(int containerId, int userId = 0); diff --git a/src/Umbraco.Core/Services/IDataTypeService.cs b/src/Umbraco.Core/Services/IDataTypeService.cs index ce9e4a3901..6a204667b4 100644 --- a/src/Umbraco.Core/Services/IDataTypeService.cs +++ b/src/Umbraco.Core/Services/IDataTypeService.cs @@ -14,6 +14,7 @@ namespace Umbraco.Core.Services void SaveContainer(EntityContainer container, int userId = 0); EntityContainer GetContainer(int containerId); EntityContainer GetContainer(Guid containerId); + IEnumerable GetContainers(string folderName, int level); void DeleteContainer(int containerId, int userId = 0); /// diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index a3c4f0f8a2..e42cd02b4e 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -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 _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>(); 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 CreateContentTypeFolderStructure(IEnumerable unsortedDocumentTypes) + { + var importedFolders = new Dictionary(); + 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("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("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 { 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 CreateDataTypeFolderStructure(IEnumerable datatypeElements) + { + var importedFolders = new Dictionary(); + 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("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("Could not create folder: " + folderName, tryCreateFolder.Exception); + throw tryCreateFolder.Exception; + } + return _dataTypeService.GetContainer(tryCreateFolder.Result); + } + private void SavePrevaluesFromXml(List dataTypes, IEnumerable 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 - { - Alias = elementCopy.Element("Alias").Value, - Item = new Lazy(() => elementCopy), - DependsOn = dependencies.ToArray() - }; + { + Alias = elementCopy.Element("Alias").Value, + Item = new Lazy(() => elementCopy), + DependsOn = dependencies.ToArray() + }; fields.Add(field); } diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index 9d0da8aca2..395cb23e32 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -279,15 +279,15 @@ namespace Umbraco.Core.Services if (_localizationService == null) _localizationService = new Lazy(() => new LocalizationService(provider, repositoryFactory, logger, eventMessagesFactory)); - if (_packagingService == null) - _packagingService = new Lazy(() => 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(() => 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(() => 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(() => new RelationService(provider, repositoryFactory, logger, eventMessagesFactory, _entityService.Value)); diff --git a/src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs index fd2dc02292..e6c497d1b6 100644 --- a/src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs @@ -393,6 +393,7 @@ namespace Umbraco.Tests.Mvc new Mock().Object, new Mock().Object, new Mock().Object, + new Mock().Object, new Mock().Object, new RepositoryFactory(CacheHelper.CreateDisabledCacheHelper(), logger, Mock.Of(), umbracoSettings), new Mock().Object), diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/exportDocumenttype.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/exportDocumenttype.aspx.cs index 1baf170182..81c6835fcf 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/exportDocumenttype.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/exportDocumenttype.aspx.cs @@ -1,8 +1,10 @@ using System; using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; +using System.Linq; using System.Web; using System.Web.SessionState; using System.Web.UI; @@ -11,6 +13,7 @@ using System.Web.UI.HtmlControls; using umbraco.cms.businesslogic.web; using System.Xml; +using Umbraco.Core; namespace umbraco.presentation.dialogs { @@ -29,26 +32,42 @@ namespace umbraco.presentation.dialogs int documentTypeId = int.Parse(helper.Request("nodeID")); if (documentTypeId > 0) { - cms.businesslogic.web.DocumentType dt = new cms.businesslogic.web.DocumentType(documentTypeId); - if (dt != null) - { - Response.AddHeader("Content-Disposition", "attachment;filename=" + dt.Alias + ".udt"); - Response.ContentType = "application/octet-stream"; + var dt = new cms.businesslogic.web.DocumentType(documentTypeId); + var folderNames = string.Empty; + if (dt.Level != 1) + { + var folders = new List(); - XmlDocument doc = new XmlDocument(); - doc.AppendChild(dt.ToXml(doc)); + var current = dt.Parent; + while (current.Level >= 1) + { + if (current.nodeObjectType == Constants.ObjectTypes.DocumentTypeContainerGuid) + folders.Add(HttpUtility.UrlEncode(current.Text)); + + if (current.Level == 1) + break; + current = current.Parent; + } + + folderNames = string.Join("/", folders.ToArray().Reverse()); + } + + Response.AddHeader("Content-Disposition", "attachment;filename=" + dt.Alias + ".udt"); + Response.ContentType = "application/octet-stream"; + + XmlDocument doc = new XmlDocument(); + doc.AppendChild(dt.ToXml(doc, folderNames)); - XmlWriterSettings writerSettings = new XmlWriterSettings(); - writerSettings.Indent = true; + XmlWriterSettings writerSettings = new XmlWriterSettings(); + writerSettings.Indent = true; - XmlWriter xmlWriter = XmlWriter.Create(Response.OutputStream, writerSettings); - doc.Save(xmlWriter); + XmlWriter xmlWriter = XmlWriter.Create(Response.OutputStream, writerSettings); + doc.Save(xmlWriter); - //Response.Write(editDataType.ToXml(new XmlDocument()).OuterXml); - } - } - } + //Response.Write(editDataType.ToXml(new XmlDocument()).OuterXml); + } + } #region Web Form Designer generated code override protected void OnInit(EventArgs e) diff --git a/src/umbraco.cms/businesslogic/Packager/PackageInstance/CreatedPackage.cs b/src/umbraco.cms/businesslogic/Packager/PackageInstance/CreatedPackage.cs index 29eaaf25ea..b883f44e79 100644 --- a/src/umbraco.cms/businesslogic/Packager/PackageInstance/CreatedPackage.cs +++ b/src/umbraco.cms/businesslogic/Packager/PackageInstance/CreatedPackage.cs @@ -13,6 +13,7 @@ using umbraco.cms.businesslogic.web; using umbraco.cms.businesslogic.macro; using Umbraco.Core.IO; using Umbraco.Core.Models; +using Umbraco.Core.Services; using File = System.IO.File; using Template = umbraco.cms.businesslogic.template.Template; @@ -221,9 +222,29 @@ namespace umbraco.cms.businesslogic.packager } } + foreach (DocumentType d in dtl) { - docTypes.AppendChild(d.ToXml(_packageManifest)); + var folderNames = string.Empty; + if (d.Level != 1) + { + var folders = new List(); + + var current = d.Parent; + while (current.Level >= 1) + { + if (current.nodeObjectType == Constants.ObjectTypes.DocumentTypeContainerGuid) + folders.Add(HttpUtility.UrlEncode(current.Text)); + + if (current.Level == 1) + break; + current = current.Parent; + } + + folderNames = string.Join("/", folders.ToArray().Reverse()); + } + + docTypes.AppendChild(d.ToXml(_packageManifest, folderNames)); } AppendElement(docTypes); @@ -295,7 +316,28 @@ namespace umbraco.cms.businesslogic.packager if (int.TryParse(dtId, out outInt)) { datatype.DataTypeDefinition dtd = new datatype.DataTypeDefinition(outInt); - dataTypes.AppendChild(dtd.ToXml(_packageManifest)); + + var folderNames = string.Empty; + var dataTypeService = ApplicationContext.Current.Services.DataTypeService; + var dataTypeDefinition = dataTypeService.GetDataTypeDefinitionById(dtd.Id); + if (dataTypeDefinition.Level != 1) + { + var folders = new List(); + + var current = dataTypeService.GetContainer(dataTypeDefinition.ParentId); + while (current.Level >= 1) + { + folders.Add(HttpUtility.UrlEncode(current.Name)); + + if (current.Level == 1) + break; + current = dataTypeService.GetContainer(current.ParentId); + } + + folderNames = string.Join("/", folders.ToArray().Reverse()); + } + + dataTypes.AppendChild(dtd.ToXml(_packageManifest, folderNames)); } } AppendElement(dataTypes); @@ -371,16 +413,14 @@ namespace umbraco.cms.businesslogic.packager } } - + private void AddDocumentType(DocumentType dt, ref List dtl) { - if (dt.MasterContentType != 0) + if (dt.MasterContentType != 0 && dt.Parent.nodeObjectType == Constants.ObjectTypes.DocumentTypeGuid) { //first add masters var mDocT = new DocumentType(dt.MasterContentType); - AddDocumentType(mDocT, ref dtl); - } if (dtl.Contains(dt) == false) diff --git a/src/umbraco.cms/businesslogic/datatype/DataTypeDefinition.cs b/src/umbraco.cms/businesslogic/datatype/DataTypeDefinition.cs index 1e86544ab9..19acec8403 100644 --- a/src/umbraco.cms/businesslogic/datatype/DataTypeDefinition.cs +++ b/src/umbraco.cms/businesslogic/datatype/DataTypeDefinition.cs @@ -142,11 +142,16 @@ namespace umbraco.cms.businesslogic.datatype public XmlElement ToXml(XmlDocument xd) { - var serializer = new EntityXmlSerializer(); - var xml = serializer.Serialize(ApplicationContext.Current.Services.DataTypeService, DataTypeItem); - return (XmlElement)xml.GetXmlNode(xd); - + return ToXml(xd, string.Empty); } + + public XmlElement ToXml(XmlDocument xd, string folders) + { + var serializer = new EntityXmlSerializer(); + var xml = serializer.Serialize(ApplicationContext.Current.Services.DataTypeService, DataTypeItem, folders); + return (XmlElement)xml.GetXmlNode(xd); + } + #endregion #region Static methods diff --git a/src/umbraco.cms/businesslogic/web/DocumentType.cs b/src/umbraco.cms/businesslogic/web/DocumentType.cs index 27c2c4cb9f..2e8137d75c 100644 --- a/src/umbraco.cms/businesslogic/web/DocumentType.cs +++ b/src/umbraco.cms/businesslogic/web/DocumentType.cs @@ -473,14 +473,19 @@ namespace umbraco.cms.businesslogic.web } public XmlElement ToXml(XmlDocument xd) + { + return ToXml(xd, string.Empty); + } + + public XmlElement ToXml(XmlDocument xd, string folders) { var exporter = new EntityXmlSerializer(); - var xml = exporter.Serialize(ApplicationContext.Current.Services.DataTypeService, ContentType); + var xml = exporter.Serialize(ApplicationContext.Current.Services.DataTypeService, ContentType, folders); //convert the Linq to Xml structure to the old .net xml structure var xNode = xml.GetXmlNode(); var doc = (XmlElement)xd.ImportNode(xNode, true); - return doc; + return doc; } [Obsolete("Obsolete, Use SetDefaultTemplate(null) on Umbraco.Core.Models.ContentType", false)] @@ -538,7 +543,10 @@ namespace umbraco.cms.businesslogic.web protected override void setupNode() { var contentType = ApplicationContext.Current.Services.ContentTypeService.GetContentType(Id); - SetupNode(contentType); + + // If it's null, it's probably a folder + if (contentType != null) + SetupNode(contentType); } #endregion