// Copyright (c) Umbraco. // See LICENSE for more details. using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using System.Xml.XPath; using Moq; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.PublishedCache; using Umbraco.Cms.Infrastructure.PublishedCache.DataSource; using Umbraco.Cms.Infrastructure.PublishedCache.Persistence; using Umbraco.Cms.Infrastructure.Serialization; using Umbraco.Cms.Tests.Common.Builders; using Umbraco.Cms.Tests.Common.Builders.Extensions; using Umbraco.Extensions; namespace Umbraco.Cms.Tests.Common.Published; /// /// Converts legacy Umbraco XML structures to NuCache collections /// to populate a test implementation of /// /// /// This does not support variant data because the XML structure doesn't support variant data. /// public static class PublishedContentXmlAdapter { /// /// Generate a collection of based on legacy umbraco XML /// /// The legacy umbraco XML /// /// Dynamically generates a list of s based on the XML data /// Dynamically generates a list of for tests /// public static IEnumerable GetContentNodeKits( string xml, IShortStringHelper shortStringHelper, out ContentType[] contentTypes, out DataType[] dataTypes) { // use the label data type for all data for these tests except in the case // where a property is named 'content', in which case use the RTE. var serializer = new SystemTextConfigurationEditorJsonSerializer(); var labelDataType = new DataType(new VoidEditor("Label", Mock.Of()), serializer) { Id = 3 }; var rteDataType = new DataType(new VoidEditor("RTE", Mock.Of()), serializer) { Id = 4 }; dataTypes = new[] { labelDataType, rteDataType }; var kitsAndXml = new List<(ContentNodeKit kit, XElement node)>(); var xDoc = XDocument.Parse(xml); var nodes = xDoc.XPathSelectElements("//*[@isDoc]"); foreach (var node in nodes) { var id = node.AttributeValue("id"); var key = node.AttributeValue("key") ?? id.ToGuid(); var propertyElements = node.Elements().Where(x => x.Attribute("id") == null); var properties = new Dictionary(); foreach (var propertyElement in propertyElements) { properties[propertyElement.Name.LocalName] = new[] { // TODO: builder? new PropertyData {Culture = string.Empty, Segment = string.Empty, Value = propertyElement.Value} }; } var contentData = new ContentDataBuilder() .WithName(node.AttributeValue("nodeName")) .WithProperties(properties) .WithPublished(true) .WithTemplateId(node.AttributeValue("template")) .WithUrlSegment(node.AttributeValue("urlName")) .WithVersionDate(node.AttributeValue("updateDate")) .WithWriterId(node.AttributeValue("writerID")) .Build(); var kit = ContentNodeKitBuilder.CreateWithContent( node.AttributeValue("nodeType"), id, node.AttributeValue("path"), node.AttributeValue("sortOrder"), node.AttributeValue("level"), node.AttributeValue("parentID"), node.AttributeValue("creatorID"), key, node.AttributeValue("createDate"), contentData, contentData); kitsAndXml.Add((kit, node)); } // put together the unique content types var contentTypesIdToType = new Dictionary(); foreach ((var kit, var node) in kitsAndXml) { if (!contentTypesIdToType.TryGetValue(kit.ContentTypeId, out var contentType)) { contentType = new ContentType(shortStringHelper, -1) { Id = kit.ContentTypeId, Alias = node.Name.LocalName }; SetContentTypeProperties(shortStringHelper, labelDataType, rteDataType, kit, contentType); contentTypesIdToType[kit.ContentTypeId] = contentType; } else { // we've already created it but might need to add properties SetContentTypeProperties(shortStringHelper, labelDataType, rteDataType, kit, contentType); } } contentTypes = contentTypesIdToType.Values.ToArray(); return kitsAndXml.Select(x => x.kit); } private static void SetContentTypeProperties( IShortStringHelper shortStringHelper, DataType labelDataType, DataType rteDataType, ContentNodeKit kit, ContentType contentType) { foreach (var property in kit.DraftData.Properties) { var propertyType = new PropertyType(shortStringHelper, labelDataType, property.Key); if (!contentType.PropertyTypeExists(propertyType.Alias)) { if (propertyType.Alias == "content") { propertyType.DataTypeId = rteDataType.Id; } contentType.AddPropertyType(propertyType); } } } }