diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 24b9de43fb..3e5eb6483b 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -311,9 +311,17 @@ namespace Umbraco.Core.Services new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()), new XElement("IsListView", contentType.IsContainer.ToString())); - var masterContentType = contentType.CompositionAliases().FirstOrDefault(); - if (masterContentType != null) - info.Add(new XElement("Master", masterContentType)); + var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId); + if(masterContentType != null) + info.Add(new XElement("Master", masterContentType.Alias)); + + var compositionsElement = new XElement("Compositions"); + var compositions = contentType.ContentTypeComposition; + foreach (var composition in compositions) + { + compositionsElement.Add(new XElement("Composition", composition.Alias)); + } + info.Add(compositionsElement); var allowedTemplates = new XElement("AllowedTemplates"); foreach (var template in contentType.AllowedTemplates) @@ -321,6 +329,7 @@ namespace Umbraco.Core.Services allowedTemplates.Add(new XElement("Template", template.Alias)); } info.Add(allowedTemplates); + if (contentType.DefaultTemplate != null && contentType.DefaultTemplate.Id != 0) info.Add(new XElement("DefaultTemplate", contentType.DefaultTemplate.Alias)); else diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 145af171a1..249efb8ec5 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -405,6 +405,23 @@ namespace Umbraco.Core.Services if (parent != null) contentType.AddContentType(parent); + var compositionsElement = infoElement.Element("Compositions"); + if (compositionsElement != null && compositionsElement.HasElements) + { + var compositions = compositionsElement.Elements("Composition"); + if (compositions.Any()) + { + foreach (var composition in compositions) + { + var compositionAlias = composition.Value; + var compositionContentType = _importedContentTypes.ContainsKey(compositionAlias) + ? _importedContentTypes[compositionAlias] + : _contentTypeService.GetContentType(compositionAlias); + var added = contentType.AddContentType(compositionContentType); + } + } + } + return UpdateContentTypeFromXml(documentType, contentType); } @@ -417,15 +434,47 @@ namespace Umbraco.Core.Services contentType.Icon = infoElement.Element("Icon").Value; contentType.Thumbnail = infoElement.Element("Thumbnail").Value; contentType.Description = infoElement.Element("Description").Value; + //NOTE AllowAtRoot is a new property in the package xml so we need to verify it exists before using it. var allowAtRoot = infoElement.Element("AllowAtRoot"); if (allowAtRoot != null) contentType.AllowedAsRoot = allowAtRoot.Value.InvariantEquals("true"); + //NOTE IsListView is a new property in the package xml so we need to verify it exists before using it. var isListView = infoElement.Element("IsListView"); if (isListView != null) contentType.IsContainer = isListView.Value.InvariantEquals("true"); + //Name of the master corresponds to the parent and we need to ensure that the Parent Id is set + var masterElement = infoElement.Element("Master"); + if (masterElement != null) + { + var masterAlias = masterElement.Value; + IContentType parent = _importedContentTypes.ContainsKey(masterAlias) + ? _importedContentTypes[masterAlias] + : _contentTypeService.GetContentType(masterAlias); + + contentType.SetLazyParentId(new Lazy(() => parent.Id)); + } + + //Update Compositions on the ContentType to ensure that they are as is defined in the package xml + var compositionsElement = infoElement.Element("Compositions"); + if (compositionsElement != null && compositionsElement.HasElements) + { + var compositions = compositionsElement.Elements("Composition"); + if (compositions.Any()) + { + foreach (var composition in compositions) + { + var compositionAlias = composition.Value; + var compositionContentType = _importedContentTypes.ContainsKey(compositionAlias) + ? _importedContentTypes[compositionAlias] + : _contentTypeService.GetContentType(compositionAlias); + var added = contentType.AddContentType(compositionContentType); + } + } + } + UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement); UpdateContentTypesTabs(contentType, documentType.Element("Tabs")); UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties")); diff --git a/src/Umbraco.Tests/Services/Importing/CompositionsTestPackage.xml b/src/Umbraco.Tests/Services/Importing/CompositionsTestPackage.xml new file mode 100644 index 0000000000..f6b4e2c160 --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/CompositionsTestPackage.xml @@ -0,0 +1,924 @@ + + + + + + Compositions Packaged + 1.0 + MIT License + http://blog.sitereactor.dk + + 3 + 0 + 0 + + + + Morten Christensen + http://blog.sitereactor.dk + + + + + + + 0 + <![CDATA[Txt: A responsive starter kit for Umbraco]]> + + + + + 0 + + + + 1054 + + + This is TXT, a free site template designed by n33 for HTML5 UP. It's built on the skelJS framework, uses well-thought out HTML5 and CSS3, and is fully responsive making it a great starting point for your own projects. And, like everything else we make, it's also free to use for pretty much any personal or commercial work under the Creative Commons Attribution license, so go ahead and use it – just don't forget to credit us!

]]>
+ + + + + 0 + 1 + + + You've installed Umbraco and the "Txt" Starter Kit.

+

Edit the text on the homepage and create a site structure by adding new texpages to your site. This is all done in the Content section.

+

If you find the editing options provided by the Txt site too limited for you needs, simply add more properties to the page by going to the Settings section, expanding the Document Types item and adding new properties on the Generic Properties tab. You can find more information about document types and properties at the Umbraco website.

+

You'll probably want to personalize your site by changing the current design. This is also done in the Settings section, by editing the CSS styles and HTML templates. Umbraco uses master templates, so the main, common markup is placed in the Starterkit Master template, while the Homeage and Textpage have separate templates for their unique layouts. You can find more information about templates and css in umbraco at the umbraco website.

+

Once you're happy with your site's design, you might want to add more functionality, such as maps, image galleries or forms. This is done by installing Umbraco modules.

]]> +
+
+ + 0 + 1 + + + The Txt Starter Kit only scratches the surface of what's possible with Umbraco. Below the Txt Starter Kit and its modules lies a great architecture that lets you implement whatever you need.

+

With Umbraco you've finally got a solid, open and reliable platform for websites as basic as the Txt site, and Umbraco can be rapidly expanded to support multi-language websites, collaboration platforms and intra/extranets, to name just a few.

+

Advanced functionality is created with Umbraco macros, built with Umbraco's award-winning .NET integration, including full support for any .NET User or Custom control and ASP.NET MVC. Create and integrate your own .NET macros in mere minutes with point and click simplicity. Simply copy your controls to the Umbraco website, go to the Developer section and create a new macro, selecting your control from the list.

+

You can also use Microsoft's Razor syntax to quickly add dynamic functionality to your site.

+

We've also gathered the best community macros into a repository that's also accessed from the Developer section, in the Packages area. You can find more information about creating macros, on the Umbraco website.

+

The sky is the limit with Umbraco, and you have the benefit a friendly community, training, and guaranteed support. Find out how to get help.

]]> +
+
+ + 0 + 1 + + + Umbraco modules encapsulate specific bits of advanced functionality that are easily added to your website.

+

Once installed, Umbraco modules are open source and easy to customize if you want to modify the behavior for your specific needs.

+

Because Umbraco modules are provided under the MIT license you are free to use and modify them any way you want, with no strings attached.

+

To add Umbraco modules to your website, go to the Settings section, expand the Templates item, select the Starterkit Master template, then click the Customize Skin button on the toolbar.

+

Umbraco modules are available for various kinds of navigation, a sitemap, social media feeds, and a contact form. The list of available Umbraco modules is growing rapidly and is automatically updated from a central source, always fresh and current.

+

Get more information about the umbraco way.

]]> +
+
+ + 0 + 1 + + + The Txt Starter Kit gives you a small website that introduces you to a set of well-defined conventions for building an Umbraco website.

+

Now that you know what the Txt Starter Kit is, it is time to get started using Umbraco.

]]> +
+
+ + 0 + <![CDATA[Adventure log]]> + + 0 + + Ita prorsus, inquam; Hanc ergo intuens debet institutum illud quasi signum absolvere. Ergo adhuc, quantum equidem intellego, causa non videtur fuisse mutandi nominis. Quia dolori non voluptas contraria est, sed doloris privatio. Nos autem non solum beatae vitae istam esse oblectationem videmus, sed etiam levamentum miseriarum. Quodsi ipsam honestatem undique pertectam atque absolutam. Nos cum te, M. Quod vestri non item.

+

Cum id quoque, ut cupiebat, audivisset, evelli iussit eam, qua erat transfixus, hastam. Quarum ambarum rerum cum medicinam pollicetur, luxuriae licentiam pollicetur. Quid iudicant sensus? Quo tandem modo?

]]> +
+
+ + 0 + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Commoda autem et incommoda in eo genere sunt, quae praeposita et reiecta diximus; Bestiarum vero nullum iudicium puto. Est enim effectrix multarum et magnarum voluptatum. Duo Reges: constructio interrete. Claudii libidini, qui tum erat summo ne imperio, dederetur. Quarum ambarum rerum cum medicinam pollicetur, luxuriae licentiam pollicetur. Sed virtutem ipsam inchoavit, nihil amplius.

+

Ita redarguitur ipse a sese, convincunturque scripta eius probitate ipsius ac moribus. Istam voluptatem, inquit, Epicurus ignorat? Sed venio ad inconstantiae crimen, ne saepius dicas me aberrare; Sic, et quidem diligentius saepiusque ista loquemur inter nos agemusque communiter. Primum in nostrane potestate est, quid meminerimus? Consequens enim est et post oritur, ut dixi. Hoc mihi cum tuo fratre convenit. Immo videri fortasse. Itaque in rebus minime obscuris non multus est apud eos disserendi labor. Aliud igitur esse censet gaudere, aliud non dolere.

]]> +
+
+ + 0 + + Ut aliquid scire se gaudeant? Hanc ergo intuens debet institutum illud quasi signum absolvere. Vestri haec verecundius, illi fortasse constantius. Itaque sensibus rationem adiunxit et ratione effecta sensus non reliquit. Sed ea mala virtuti magnitudine obruebantur. Quasi ego id curem, quid ille aiat aut neget. Verum tamen cum de rebus grandioribus dicas, ipsae res verba rapiunt; Apparet statim, quae sint officia, quae actiones.

+

Virtutibus igitur rectissime mihi videris et ad consuetudinem nostrae orationis vitia posuisse contraria. Nonne videmus quanta perturbatio rerum omnium consequatur, quanta confusio? Sed eum qui audiebant, quoad poterant, defendebant sententiam suam. Ut necesse sit omnium rerum, quae natura vigeant, similem esse finem, non eundem.

]]> +
+
+ + 0 + 2021-09-20T00:00:00 + + + + Sed ad haec, nisi molestum est, habeo quae velim. Neque enim disputari sine reprehensione nec cum iracundia aut pertinacia recte disputari potest. Nec vero alia sunt quaerenda contra Carneadeam illam sententiam. Deinde disputat, quod cuiusque generis animantium statui deceat extremum. Facit igitur Lucius noster prudenter, qui audire de summo bono potissimum velit; Quis non odit sordidos, vanos, leves, futtiles?

+

Negat enim summo bono afferre incrementum diem. Haec mihi videtur delicatior, ut ita dicam, molliorque ratio, quam virtutis vis gravitasque postulat. Haec quo modo conveniant, non sane intellego. Quis enim confidit semper sibi illud stabile et firmum permansurum, quod fragile et caducum sit? Multoque hoc melius nos veriusque quam Stoici. Igitur neque stultorum quisquam beatus neque sapientium non beatus. De hominibus dici non necesse est. Non enim iam stirpis bonum quaeret, sed animalis. Nobis Heracleotes ille Dionysius flagitiose descivisse videtur a Stoicis propter oculorum dolorem. At, illa, ut vobis placet, partem quandam tuetur, reliquam deserit.

]]> +
+
+
+
+
+
+ + + + Master + umbMaster + folder.gif + folder.png + + False + False + + + + + + + + Hide in navigation? + umbracoNaviHide + Umbraco.TrueFalse + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + + False + + + + + Page title + title + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Content + False + + + + + + + 12 + Content + 0 + + + + + + Home + umbHomePage + .sprTreeSettingDomain + docWithImage.png + + False + False + umbMaster + + umbMaster + + + + + umbHomePage + + + umbTextPage + + + + Facebook link + facebookLink + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Social + False + + + + + Twitter link + twitterLink + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Social + False + + + + + Rss link + rssLink + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Social + False + + + + + Dribbble link + dribbbleLink + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Social + False + + + + + LinkedIn link + linkedInLink + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Social + False + + + + + Google+ link + googleLink + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Social + False + + + + + Hide banner? + hideBanner + Umbraco.TrueFalse + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + Banner + False + + + + + Banner Header + bannerHeader + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Banner + False + + + + + Banner Subheader + bannerSubheader + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Banner + False + + + + + Banner link text + bannerLinkText + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Banner + False + + + + + Banner link + bannerLink + Umbraco.ContentPickerAlias + a6857c73-d6e9-480c-b6e6-f15f6ad11125 + Banner + False + + + + + Banner background image + bannerBackgroundImage + Umbraco.UploadField + 84c6b441-31df-4ffe-b67e-67d5bc3ae65a + Banner + False + + + + + About Title + aboutTitle + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + About + False + + + + + AboutText + aboutText + Umbraco.TinyMCEv3 + ca90c950-0aff-4e72-b976-a30b1ac57dad + About + False + + + + + Site Name + siteName + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Content + False + + + + + Byline + byline + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Content + False + + + + + Copyright + copyright + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Content + False + + + + + + + 13 + Social + 0 + + + 14 + Banner + 1 + + + 15 + About + 2 + + + 16 + Content + 3 + + + + + + Meta + Meta + icon-truck + folder.png + + False + False + + + + + + + + Meta Keywords + metaKeywords + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Meta + False + + + + + + + 19 + Meta + 9 + + + + + + News Item + umbNewsItem + .sprTreeDocPic + docWithImage.png + + False + False + umbMaster + + umbMaster + + + + + umbNewsItem + + + + + Publish date + publishDate + Umbraco.DateTime + e4d66c0f-b935-4200-81f0-025f7256b89a + + False + + + + + Image + image + Umbraco.UploadField + 84c6b441-31df-4ffe-b67e-67d5bc3ae65a + Content + False + + + + + Subheader + subheader + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Content + False + + + + + Content + bodyText + Umbraco.TinyMCEv3 + ca90c950-0aff-4e72-b976-a30b1ac57dad + Content + False + + + + + + + 17 + Content + 0 + + + + + + News Overview + umbNewsOverview + package.png + folder_media.png + + False + False + umbMaster + + umbMaster + + + + + umbNewsOverview + + + umbNewsItem + + + + + + + Seo + Seo + icon-wifi + folder.png + + False + False + + + + + + + + Seo Pimp Title + seoPimpTitle + Umbraco.Textbox + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Seo + False + + + + + + + 20 + Seo + 10 + + + + + + Text Page + umbTextyPage + .sprTreeDoc + doc.png + + False + False + umbMaster + + umbMaster + Meta + Seo + + + + + umbTextyPage + + + umbTextyPage + + + + Featured Page? + featuredPage + Umbraco.TrueFalse + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + Content + False + + + + + Image + image + Umbraco.UploadField + 84c6b441-31df-4ffe-b67e-67d5bc3ae65a + Content + False + + + + + Content + bodyText + Umbraco.TinyMCEv3 + ca90c950-0aff-4e72-b976-a30b1ac57dad + Content + False + + + + + + + 18 + Content + 0 + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs index c840f08842..5726753037 100644 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18051 +// Runtime Version:4.0.30319.34209 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -88,32 +88,6 @@ namespace Umbraco.Tests.Services.Importing { } } - /// - /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> - ///<umbPackage> - /// <files /> - /// <info> - /// <package> - /// <name>Dictionary-Package</name> - /// <version>1.0</version> - /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> - /// <url>http://not.available</url> - /// <requirements> - /// <major>3</major> - /// <minor>0</minor> - /// <patch>0</patch> - /// </requirements> - /// </package> - /// <author> - /// <name>Test</name> - /// <website>http://not.available</w [rest of string was truncated]";. - /// - internal static string Dictionary_Package { - get { - return ResourceManager.GetString("Dictionary_Package", resourceCulture); - } - } - /// /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> ///<umbPackage> @@ -142,6 +116,58 @@ namespace Umbraco.Tests.Services.Importing { } } + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Compositions Packaged</name> + /// <version>1.0</version> + /// <license url="http://opensource.org/licenses/MIT">MIT License</license> + /// <url>http://blog.sitereactor.dk</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Morten Christensen</name> + /// <website>h [rest of string was truncated]";. + /// + internal static string CompositionsTestPackage { + get { + return ResourceManager.GetString("CompositionsTestPackage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Dictionary-Package</name> + /// <version>1.0</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> + /// <url>http://not.available</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Test</name> + /// <website>http://not.available</w [rest of string was truncated]";. + /// + internal static string Dictionary_Package { + get { + return ResourceManager.GetString("Dictionary_Package", resourceCulture); + } + } + /// /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> ///<umbPackage> diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.resx b/src/Umbraco.Tests/Services/Importing/ImportResources.resx index dd47151b73..1c1c02a4f5 100644 --- a/src/Umbraco.Tests/Services/Importing/ImportResources.resx +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.resx @@ -148,4 +148,7 @@ dictionary-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + compositionstestpackage.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs index bec18c23c3..376c89b755 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using NUnit.Framework; @@ -554,6 +555,35 @@ namespace Umbraco.Tests.Services.Importing } } + [Test] + public void PackagingService_Can_Import_Package_With_Compositions() + { + // Arrange + string strXml = ImportResources.CompositionsTestPackage; + var xml = XElement.Parse(strXml); + var templateElement = xml.Descendants("Templates").First(); + var docTypeElement = xml.Descendants("DocumentTypes").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var templates = packagingService.ImportTemplates(templateElement); + var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); + + // Assert + Assert.That(contentTypes, Is.Not.Null); + Assert.That(contentTypes.Any(), Is.True); + Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); + Assert.That(contentTypes.Count(x => x.ParentId == -1), Is.EqualTo(3)); + + var textpage = contentTypes.First(x => x.Alias.Equals("umbTextyPage")); + Assert.That(textpage.ParentId, Is.Not.EqualTo(-1)); + Assert.That(textpage.ContentTypeComposition.Count(), Is.EqualTo(3)); + Assert.That(textpage.ContentTypeCompositionExists("umbMaster"), Is.True); + Assert.That(textpage.ContentTypeCompositionExists("Meta"), Is.True); + Assert.That(textpage.ContentTypeCompositionExists("Seo"), Is.True); + } + private void AddLanguages() { var norwegian = new Core.Models.Language("nb-NO"); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 3c94bced66..300baebc98 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -694,6 +694,7 @@ Designer +