/// <summary> /// Construct from an Umbraco 8 ContentNodeKit. /// </summary> internal UmbracoNode(UmbracoXmlParser parser, int id, ContentNodeKit treeNode, string url, List <int> pathIds, List <string> pathNames) { _parser = parser; if (treeNode.PublishedData != null) { _propertyData = treeNode.PublishedData.Properties; } Id = id; Uid = treeNode.Node.Uid.ToString().Replace("-", string.Empty).ToLower(); ParentId = pathIds.Skip(pathIds.Count - 2).FirstOrDefault(); if (ParentId == -1) { ParentId = null; } Name = pathNames.Last(); Url = url; PathIds = pathIds.Skip(1).ToList(); // skip -1 root PathNames = pathNames; Doctype = _parser.Options.DoctypeMapping != null && _parser.Options.DoctypeMapping.ContainsKey(treeNode.ContentTypeId) ? _parser.Options.DoctypeMapping[treeNode.ContentTypeId] : treeNode.ContentTypeId.ToString(); Level = pathIds.Count - 1; CreateDate = new DateTime(treeNode.Node.CreateDate.Ticks - (treeNode.Node.CreateDate.Ticks % TimeSpan.TicksPerSecond), treeNode.Node.CreateDate.Kind); UpdateDate = treeNode.PublishedData != null ? new DateTime(treeNode.PublishedData.VersionDate.Ticks - (treeNode.PublishedData.VersionDate.Ticks % TimeSpan.TicksPerSecond), treeNode.PublishedData.VersionDate.Kind) : CreateDate; CreatorName = _parser.Options.UserMapping != null && _parser.Options.UserMapping.ContainsKey(treeNode.Node.CreatorId) ? _parser.Options.UserMapping[treeNode.Node.CreatorId] : treeNode.Node.CreatorId.ToString(); WriterName = _parser.Options.UserMapping != null && treeNode.PublishedData != null && _parser.Options.UserMapping.ContainsKey(treeNode.PublishedData.WriterId) ? _parser.Options.UserMapping[treeNode.PublishedData.WriterId] : treeNode.PublishedData != null?treeNode.PublishedData.WriterId.ToString() : null; TemplateId = treeNode.PublishedData != null && treeNode.PublishedData.TemplateId.HasValue ? treeNode.PublishedData.TemplateId.Value : default(int); }
private ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto, IContentCacheDataSerializer serializer) { if (dto.EditData == null && dto.EditDataRaw == null) { throw new InvalidOperationException("No data for media " + dto.Id); } bool published = true; var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published); var p = new ContentData { Name = dto.EditName, Published = published, TemplateId = -1, VersionId = dto.VersionId, VersionDate = dto.EditVersionDate, WriterId = dto.CreatorId, // what-else? Properties = deserializedMedia.PropertyData, // TODO: We don't want to allocate empty arrays CultureInfos = deserializedMedia.CultureData }; var n = new ContentNode(dto.Id, dto.Key, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit { Node = n, ContentTypeId = dto.ContentTypeId, PublishedData = p }; return(s); }
private static ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto) { if (dto.EditData == null) { throw new Exception("No data for media " + dto.Id); } var nested = DeserializeNestedData(dto.EditData); var p = new ContentData { Name = dto.EditName, Published = true, TemplateId = -1, VersionId = dto.VersionId, VersionDate = dto.EditVersionDate, WriterId = dto.CreatorId, // what-else? Properties = nested.PropertyData, CultureInfos = nested.CultureData }; var n = new ContentNode(dto.Id, dto.Uid, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit { Node = n, ContentTypeId = dto.ContentTypeId, PublishedData = p }; return(s); }
private ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto, IContentCacheDataSerializer serializer) { if (dto.EditData == null && dto.EditDataRaw == null) { throw new InvalidOperationException("No data for media " + dto.Id); } bool published = true; var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published); var p = new ContentData( dto.EditName, null, dto.VersionId, dto.EditVersionDate, dto.CreatorId, -1, published, deserializedMedia?.PropertyData, deserializedMedia?.CultureData); var n = new ContentNode(dto.Id, dto.Key, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit(n, dto.ContentTypeId, null, p); return(s); }
private IEnumerable <ContentNodeKit> CreateChildren( int startId, ContentNodeKit parent, IMediaType mediaType, int count) { for (var i = 0; i < count; i++) { var id = startId + i + 1; var item1Data = new ContentDataBuilder() .WithName("Child " + id) .WithProperties(new PropertyDataBuilder() .WithPropertyData("content", "<div>This is some content</div>") .Build()) .Build(); var parentPath = parent.Node.Path; var item1 = ContentNodeKitBuilder.CreateWithContent( mediaType.Id, id, $"{parentPath},{id}", draftData: item1Data, publishedData: item1Data); yield return(item1); } }
private List <int> GetNodeIdPath(ContentNodeKit treeNode) { var paths = new List <int>(); if (treeNode.Node != null && !string.IsNullOrEmpty(treeNode.Node.Path)) { paths.AddRange(treeNode.Node.Path.Split(',').AsEnumerable().Select(i => Convert.ToInt32(i))); } return(paths); }
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); } } }
private static ContentNodeKit CreateContentNodeKit(ContentSourceDto dto) { ContentData d = null; ContentData p = null; if (dto.Edited) { if (dto.EditData == null) { if (Debugger.IsAttached) { throw new Exception("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); } Current.Logger.Warn <DatabaseDataSource>("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); } else { var nested = DeserializeNestedData(dto.EditData); d = new ContentData { Name = dto.EditName, Published = false, TemplateId = dto.EditTemplateId, VersionId = dto.VersionId, VersionDate = dto.EditVersionDate, WriterId = dto.EditWriterId, Properties = nested.PropertyData, CultureInfos = nested.CultureData }; } } if (dto.Published) { if (dto.PubData == null) { if (Debugger.IsAttached) { throw new Exception("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding."); } Current.Logger.Warn <DatabaseDataSource>("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); } else { var nested = DeserializeNestedData(dto.PubData); p = new ContentData { Name = dto.PubName, UrlSegment = nested.UrlSegment, Published = true, TemplateId = dto.PubTemplateId, VersionId = dto.VersionId, VersionDate = dto.PubVersionDate, WriterId = dto.PubWriterId, Properties = nested.PropertyData, CultureInfos = nested.CultureData }; } } var n = new ContentNode(dto.Id, dto.Uid, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit { Node = n, ContentTypeId = dto.ContentTypeId, DraftData = d, PublishedData = p }; return(s); }
private void Init() { Current.Reset(); var factory = Mock.Of <IFactory>(); Current.Factory = factory; var configs = new Configs(); Mock.Get(factory).Setup(x => x.GetInstance(typeof(Configs))).Returns(configs); var globalSettings = new GlobalSettings(); configs.Add(SettingsForTests.GenerateMockUmbracoSettings); configs.Add <IGlobalSettings>(() => globalSettings); var publishedModelFactory = new NoopPublishedModelFactory(); Mock.Get(factory).Setup(x => x.GetInstance(typeof(IPublishedModelFactory))).Returns(publishedModelFactory); // create a content node kit var kit = new ContentNodeKit { ContentTypeId = 2, Node = new ContentNode(1, Guid.NewGuid(), 0, "-1,1", 0, -1, DateTime.Now, 0), DraftData = new ContentData { Name = "It Works2!", Published = false, TemplateId = 0, VersionId = 2, VersionDate = DateTime.Now, WriterId = 0, Properties = new Dictionary <string, PropertyData[]> { { "prop", new[] { new PropertyData { Culture = "", Segment = "", Value = "val2" }, new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr2" }, new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk2" }, new PropertyData { Culture = "dk-DA", Segment = "", Value = "val-da2" }, new PropertyData { Culture = "de-DE", Segment = "", Value = "val-de2" } } } }, CultureInfos = new Dictionary <string, CultureVariation> { // draft data = everything, and IsDraft indicates what's edited { "fr-FR", new CultureVariation { Name = "name-fr2", IsDraft = true, Date = new DateTime(2018, 01, 03, 01, 00, 00) } }, { "en-UK", new CultureVariation { Name = "name-uk2", IsDraft = true, Date = new DateTime(2018, 01, 04, 01, 00, 00) } }, { "dk-DA", new CultureVariation { Name = "name-da2", IsDraft = true, Date = new DateTime(2018, 01, 05, 01, 00, 00) } }, { "de-DE", new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } } } }, PublishedData = new ContentData { Name = "It Works1!", Published = true, TemplateId = 0, VersionId = 1, VersionDate = DateTime.Now, WriterId = 0, Properties = new Dictionary <string, PropertyData[]> { { "prop", new[] { new PropertyData { Culture = "", Segment = "", Value = "val1" }, new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr1" }, new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk1" } } } }, CultureInfos = new Dictionary <string, CultureVariation> { // published data = only what's actually published, and IsDraft has to be false { "fr-FR", new CultureVariation { Name = "name-fr1", IsDraft = false, Date = new DateTime(2018, 01, 01, 01, 00, 00) } }, { "en-UK", new CultureVariation { Name = "name-uk1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } }, { "de-DE", new CultureVariation { Name = "name-de1", IsDraft = false, Date = new DateTime(2018, 01, 02, 01, 00, 00) } } } } }; // create a data source for NuCache var dataSource = new TestDataSource(kit); var runtime = Mock.Of <IRuntimeState>(); Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); // create data types, property types and content types var dataType = new DataType(new VoidEditor("Editor", Mock.Of <ILogger>())) { Id = 3 }; var dataTypes = new[] { dataType }; _propertyType = new PropertyType("Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.Culture }; _contentType = new ContentType(-1) { Id = 2, Alias = "alias-ct", Variations = ContentVariation.Culture }; _contentType.AddPropertyType(_propertyType); var contentTypes = new[] { _contentType }; var contentTypeService = new Mock <IContentTypeService>(); contentTypeService.Setup(x => x.GetAll()).Returns(contentTypes); contentTypeService.Setup(x => x.GetAll(It.IsAny <int[]>())).Returns(contentTypes); var mediaTypeService = new Mock <IMediaTypeService>(); mediaTypeService.Setup(x => x.GetAll()).Returns(Enumerable.Empty <IMediaType>()); mediaTypeService.Setup(x => x.GetAll(It.IsAny <int[]>())).Returns(Enumerable.Empty <IMediaType>()); var contentTypeServiceBaseFactory = new Mock <IContentTypeBaseServiceProvider>(); contentTypeServiceBaseFactory.Setup(x => x.For(It.IsAny <IContentBase>())).Returns(contentTypeService.Object); var dataTypeService = Mock.Of <IDataTypeService>(); Mock.Get(dataTypeService).Setup(x => x.GetAll()).Returns(dataTypes); // create a service context var serviceContext = ServiceContext.CreatePartial( dataTypeService: dataTypeService, memberTypeService: Mock.Of <IMemberTypeService>(), memberService: Mock.Of <IMemberService>(), contentTypeService: contentTypeService.Object, mediaTypeService: mediaTypeService.Object, localizationService: Mock.Of <ILocalizationService>(), domainService: Mock.Of <IDomainService>() ); // create a scope provider var scopeProvider = Mock.Of <IScopeProvider>(); Mock.Get(scopeProvider) .Setup(x => x.CreateScope( It.IsAny <IsolationLevel>(), It.IsAny <RepositoryCacheMode>(), It.IsAny <IEventDispatcher>(), It.IsAny <bool?>(), It.IsAny <bool>(), It.IsAny <bool>())) .Returns(Mock.Of <IScope>); // create a published content type factory var contentTypeFactory = new PublishedContentTypeFactory( Mock.Of <IPublishedModelFactory>(), new PropertyValueConverterCollection(Array.Empty <IPropertyValueConverter>()), dataTypeService); // create a variation accessor _variationAccesor = new TestVariationContextAccessor(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; _snapshotService = new PublishedSnapshotService(options, null, runtime, serviceContext, contentTypeFactory, null, new TestPublishedSnapshotAccessor(), _variationAccesor, Mock.Of <IProfilingLogger>(), scopeProvider, Mock.Of <IDocumentRepository>(), Mock.Of <IMediaRepository>(), Mock.Of <IMemberRepository>(), new TestDefaultCultureAccessor(), dataSource, globalSettings, Mock.Of <IEntityXmlSerializer>(), Mock.Of <IPublishedModelFactory>(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() })); // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); Mock.Get(factory).Setup(x => x.GetInstance(typeof(IVariationContextAccessor))).Returns(_variationAccesor); }
/// <summary> /// Creates a content cache /// </summary> /// <param name="dataTypes"></param> /// <param name="contentTypes"></param> /// <returns></returns> /// <remarks> /// Builds a content hierarchy of 3 nodes, each has a different set of cultural properties. /// The first 2 share the same content type, the last one is a different content type. /// NOTE: The content items themselves are 'Invariant' but their properties are 'Variant' by culture. /// Normally in Umbraco this is prohibited but our APIs and database do actually support that behavior. /// It is simpler to have these tests run this way, else we would need to use WithCultureInfos /// for each item and pass in name values for all cultures we are supporting and then specify the /// default VariationContextAccessor.VariationContext value to be a default culture instead of "". /// </remarks> private IEnumerable <ContentNodeKit> CreateCache(IDataType[] dataTypes, out ContentType[] contentTypes) { var result = new List <ContentNodeKit>(); var propertyDataTypes = new Dictionary <string, IDataType> { // we only have one data type for this test which will be resolved with string empty. [string.Empty] = dataTypes[0] }; var contentType1 = new ContentType(ShortStringHelper, -1); ContentData item1Data = new ContentDataBuilder() .WithName("Content 1") .WithProperties(new PropertyDataBuilder() .WithPropertyData("welcomeText", "Welcome") .WithPropertyData("welcomeText", "Welcome", "en-US") .WithPropertyData("welcomeText", "Willkommen", "de") .WithPropertyData("welcomeText", "Welkom", "nl") .WithPropertyData("welcomeText2", "Welcome") .WithPropertyData("welcomeText2", "Welcome", "en-US") .WithPropertyData("noprop", "xxx") .Build()) // build with a dynamically created content type .Build(ShortStringHelper, propertyDataTypes, contentType1, "ContentType1"); ContentNodeKit item1 = ContentNodeKitBuilder.CreateWithContent( contentType1.Id, 1, "-1,1", draftData: item1Data, publishedData: item1Data); result.Add(item1); ContentData item2Data = new ContentDataBuilder() .WithName("Content 2") .WithProperties(new PropertyDataBuilder() .WithPropertyData("welcomeText", "Welcome") .WithPropertyData("welcomeText", "Welcome", "en-US") .WithPropertyData("noprop", "xxx") .Build()) // build while dynamically updating the same content type .Build(ShortStringHelper, propertyDataTypes, contentType1); ContentNodeKit item2 = ContentNodeKitBuilder.CreateWithContent( contentType1.Id, 2, "-1,1,2", parentContentId: 1, draftData: item2Data, publishedData: item2Data); result.Add(item2); var contentType2 = new ContentType(ShortStringHelper, -1); ContentData item3Data = new ContentDataBuilder() .WithName("Content 3") .WithProperties(new PropertyDataBuilder() .WithPropertyData("prop3", "Oxxo") .WithPropertyData("prop3", "Oxxo", "en-US") .Build()) // build with a dynamically created content type .Build(ShortStringHelper, propertyDataTypes, contentType2, "ContentType2"); ContentNodeKit item3 = ContentNodeKitBuilder.CreateWithContent( contentType2.Id, 3, "-1,1,2,3", parentContentId: 2, draftData: item3Data, publishedData: item3Data); result.Add(item3); contentTypes = new[] { contentType1, contentType2 }; return(result); }
private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto, IContentCacheDataSerializer serializer) { ContentData d = null; ContentData p = null; if (dto.Edited) { if (dto.EditData == null && dto.EditDataRaw == null) { if (Debugger.IsAttached) { throw new InvalidOperationException("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); } _logger.LogWarning("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); } else { bool published = false; var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published); d = new ContentData { Name = dto.EditName, Published = published, TemplateId = dto.EditTemplateId, VersionId = dto.VersionId, VersionDate = dto.EditVersionDate, WriterId = dto.EditWriterId, Properties = deserializedContent.PropertyData, // TODO: We don't want to allocate empty arrays CultureInfos = deserializedContent.CultureData, UrlSegment = deserializedContent.UrlSegment }; } } if (dto.Published) { if (dto.PubData == null && dto.PubDataRaw == null) { if (Debugger.IsAttached) { throw new InvalidOperationException("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding."); } _logger.LogWarning("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); } else { bool published = true; var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw, published); p = new ContentData { Name = dto.PubName, UrlSegment = deserializedContent.UrlSegment, Published = published, TemplateId = dto.PubTemplateId, VersionId = dto.VersionId, VersionDate = dto.PubVersionDate, WriterId = dto.PubWriterId, Properties = deserializedContent.PropertyData, // TODO: We don't want to allocate empty arrays CultureInfos = deserializedContent.CultureData }; } } var n = new ContentNode(dto.Id, dto.Key, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit { Node = n, ContentTypeId = dto.ContentTypeId, DraftData = d, PublishedData = p }; return(s); }
/// <summary> /// Generate a collection of <see cref="ContentNodeKit"/> based on legacy umbraco XML /// </summary> /// <param name="xml">The legacy umbraco XML</param> /// <param name="shortStringHelper"></param> /// <param name="contentTypes">Dynamically generates a list of <see cref="ContentType"/>s based on the XML data</param> /// <param name="dataTypes">Dynamically generates a list of <see cref="DataType"/> for tests</param> /// <returns></returns> public static IEnumerable <ContentNodeKit> 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 ConfigurationEditorJsonSerializer(); var labelDataType = new DataType(new VoidEditor("Label", Mock.Of <IDataValueEditorFactory>()), serializer) { Id = 3 }; var rteDataType = new DataType(new VoidEditor("RTE", Mock.Of <IDataValueEditorFactory>()), serializer) { Id = 4 }; dataTypes = new[] { labelDataType, rteDataType }; var kitsAndXml = new List <(ContentNodeKit kit, XElement node)>(); var xDoc = XDocument.Parse(xml); IEnumerable <XElement> nodes = xDoc.XPathSelectElements("//*[@isDoc]"); foreach (XElement node in nodes) { var id = node.AttributeValue <int>("id"); Guid key = node.AttributeValue <Guid?>("key") ?? id.ToGuid(); var propertyElements = node.Elements().Where(x => x.Attribute("id") == null); var properties = new Dictionary <string, PropertyData[]>(); foreach (XElement 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 <string>("nodeName")) .WithProperties(properties) .WithPublished(true) .WithTemplateId(node.AttributeValue <int>("template")) .WithUrlSegment(node.AttributeValue <string>("urlName")) .WithVersionDate(node.AttributeValue <DateTime>("updateDate")) .WithWriterId(node.AttributeValue <int>("writerID")) .Build(); ContentNodeKit kit = ContentNodeKitBuilder.CreateWithContent( node.AttributeValue <int>("nodeType"), id, node.AttributeValue <string>("path"), node.AttributeValue <int>("sortOrder"), node.AttributeValue <int>("level"), node.AttributeValue <int>("parentID"), node.AttributeValue <int>("creatorID"), key, node.AttributeValue <DateTime>("createDate"), contentData, contentData); kitsAndXml.Add((kit, node)); } // put together the unique content types var contentTypesIdToType = new Dictionary <int, ContentType>(); foreach ((ContentNodeKit kit, XElement node) in kitsAndXml) { if (!contentTypesIdToType.TryGetValue(kit.ContentTypeId, out ContentType 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)); }
public void StandaloneVariations() { // this test implements a full standalone NuCache (based upon a test IDataSource, does not // use any local db files, does not rely on any database) - and tests variations Current.Reset(); Current.UnlockConfigs(); Current.Configs.Add(SettingsForTests.GenerateMockUmbracoSettings); Current.Configs.Add <IGlobalSettings>(() => new GlobalSettings()); var globalSettings = Current.Configs.Global(); // create a content node kit var kit = new ContentNodeKit { ContentTypeId = 2, Node = new ContentNode(1, Guid.NewGuid(), 0, "-1,1", 0, -1, DateTime.Now, 0), DraftData = new ContentData { Name = "It Works2!", Published = false, TemplateId = 0, VersionId = 2, VersionDate = DateTime.Now, WriterId = 0, Properties = new Dictionary <string, PropertyData[]> { { "prop", new[] { new PropertyData { Culture = "", Segment = "", Value = "val2" }, new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr2" }, new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk2" } } } }, CultureInfos = new Dictionary <string, CultureVariation> { { "fr-FR", new CultureVariation { Name = "name-fr2", Date = new DateTime(2018, 01, 03, 01, 00, 00) } }, { "en-UK", new CultureVariation { Name = "name-uk2", Date = new DateTime(2018, 01, 04, 01, 00, 00) } } } }, PublishedData = new ContentData { Name = "It Works1!", Published = true, TemplateId = 0, VersionId = 1, VersionDate = DateTime.Now, WriterId = 0, Properties = new Dictionary <string, PropertyData[]> { { "prop", new[] { new PropertyData { Culture = "", Segment = "", Value = "val1" }, new PropertyData { Culture = "fr-FR", Segment = "", Value = "val-fr1" }, new PropertyData { Culture = "en-UK", Segment = "", Value = "val-uk1" } } } }, CultureInfos = new Dictionary <string, CultureVariation> { { "fr-FR", new CultureVariation { Name = "name-fr1", Date = new DateTime(2018, 01, 01, 01, 00, 00) } }, { "en-UK", new CultureVariation { Name = "name-uk1", Date = new DateTime(2018, 01, 02, 01, 00, 00) } } } } }; // create a data source for NuCache var dataSource = new TestDataSource(kit); var runtime = Mock.Of <IRuntimeState>(); Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); // create data types, property types and content types var dataType = new DataType(new VoidEditor("Editor", Mock.Of <ILogger>())) { Id = 3 }; var dataTypes = new[] { dataType }; var propertyType = new PropertyType("Umbraco.Void.Editor", ValueStorageType.Nvarchar) { Alias = "prop", DataTypeId = 3, Variations = ContentVariation.Culture }; var contentType = new ContentType(-1) { Id = 2, Alias = "alias-ct", Variations = ContentVariation.Culture }; contentType.AddPropertyType(propertyType); var contentTypes = new[] { contentType }; var contentTypeService = Mock.Of <IContentTypeService>(); Mock.Get(contentTypeService).Setup(x => x.GetAll()).Returns(contentTypes); Mock.Get(contentTypeService).Setup(x => x.GetAll(It.IsAny <int[]>())).Returns(contentTypes); var dataTypeService = Mock.Of <IDataTypeService>(); Mock.Get(dataTypeService).Setup(x => x.GetAll()).Returns(dataTypes); // create a service context var serviceContext = ServiceContext.CreatePartial( dataTypeService: dataTypeService, memberTypeService: Mock.Of <IMemberTypeService>(), memberService: Mock.Of <IMemberService>(), contentTypeService: contentTypeService, localizationService: Mock.Of <ILocalizationService>() ); // create a scope provider var scopeProvider = Mock.Of <IScopeProvider>(); Mock.Get(scopeProvider) .Setup(x => x.CreateScope( It.IsAny <IsolationLevel>(), It.IsAny <RepositoryCacheMode>(), It.IsAny <IEventDispatcher>(), It.IsAny <bool?>(), It.IsAny <bool>(), It.IsAny <bool>())) .Returns(Mock.Of <IScope>); // create a published content type factory var contentTypeFactory = new PublishedContentTypeFactory( Mock.Of <IPublishedModelFactory>(), new PropertyValueConverterCollection(Array.Empty <IPropertyValueConverter>()), dataTypeService); // create a variation accessor var variationAccessor = new TestVariationContextAccessor(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true }; var snapshotService = new PublishedSnapshotService(options, null, runtime, serviceContext, contentTypeFactory, null, new TestPublishedSnapshotAccessor(), variationAccessor, Mock.Of <ILogger>(), scopeProvider, Mock.Of <IDocumentRepository>(), Mock.Of <IMediaRepository>(), Mock.Of <IMemberRepository>(), new TestDefaultCultureAccessor(), dataSource, globalSettings, new SiteDomainHelper()); // get a snapshot, get a published content var snapshot = snapshotService.CreatePublishedSnapshot(previewToken: null); var publishedContent = snapshot.Content.GetById(1); // invariant is the current default variationAccessor.VariationContext = new VariationContext(); Assert.IsNotNull(publishedContent); Assert.AreEqual("It Works1!", publishedContent.Name); Assert.AreEqual("val1", publishedContent.Value <string>("prop")); Assert.AreEqual("val-fr1", publishedContent.Value <string>("prop", "fr-FR")); Assert.AreEqual("val-uk1", publishedContent.Value <string>("prop", "en-UK")); Assert.AreEqual("name-fr1", publishedContent.GetCulture("fr-FR").Name); Assert.AreEqual("name-uk1", publishedContent.GetCulture("en-UK").Name); var draftContent = snapshot.Content.GetById(true, 1); Assert.AreEqual("It Works2!", draftContent.Name); Assert.AreEqual("val2", draftContent.Value <string>("prop")); Assert.AreEqual("val-fr2", draftContent.Value <string>("prop", "fr-FR")); Assert.AreEqual("val-uk2", draftContent.Value <string>("prop", "en-UK")); Assert.AreEqual("name-fr2", draftContent.GetCulture("fr-FR").Name); Assert.AreEqual("name-uk2", draftContent.GetCulture("en-UK").Name); // now french is default variationAccessor.VariationContext = new VariationContext("fr-FR"); Assert.AreEqual("val-fr1", publishedContent.Value <string>("prop")); Assert.AreEqual("name-fr1", publishedContent.GetCulture().Name); Assert.AreEqual("name-fr1", publishedContent.Name); Assert.AreEqual(new DateTime(2018, 01, 01, 01, 00, 00), publishedContent.GetCulture().Date); // now uk is default variationAccessor.VariationContext = new VariationContext("en-UK"); Assert.AreEqual("val-uk1", publishedContent.Value <string>("prop")); Assert.AreEqual("name-uk1", publishedContent.GetCulture().Name); Assert.AreEqual("name-uk1", publishedContent.Name); Assert.AreEqual(new DateTime(2018, 01, 02, 01, 00, 00), publishedContent.GetCulture().Date); // invariant needs to be retrieved explicitely, when it's not default Assert.AreEqual("val1", publishedContent.Value <string>("prop", culture: "")); // but, // if the content type / property type does not vary, then it's all invariant again // modify the content type and property type, notify the snapshot service contentType.Variations = ContentVariation.Nothing; propertyType.Variations = ContentVariation.Nothing; snapshotService.Notify(new[] { new ContentTypeCacheRefresher.JsonPayload("IContentType", publishedContent.ContentType.Id, ContentTypeChangeTypes.RefreshMain) }); // get a new snapshot (nothing changed in the old one), get the published content again var anotherSnapshot = snapshotService.CreatePublishedSnapshot(previewToken: null); var againContent = anotherSnapshot.Content.GetById(1); Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.Variations); Assert.AreEqual(ContentVariation.Nothing, againContent.ContentType.GetPropertyType("prop").Variations); // now, "no culture" means "invariant" Assert.AreEqual("It Works1!", againContent.Name); Assert.AreEqual("val1", againContent.Value <string>("prop")); }
private ContentNodeKit CreateContentNodeKit(ContentSourceDto dto, IContentCacheDataSerializer serializer) { ContentData?d = null; ContentData?p = null; if (dto.Edited) { if (dto.EditData == null && dto.EditDataRaw == null) { if (Debugger.IsAttached) { throw new InvalidOperationException("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); } _logger.LogWarning("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); } else { bool published = false; var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw, published); d = new ContentData( dto.EditName, deserializedContent?.UrlSegment, dto.VersionId, dto.EditVersionDate, dto.EditWriterId, dto.EditTemplateId, published, deserializedContent?.PropertyData, deserializedContent?.CultureData); } } if (dto.Published) { if (dto.PubData == null && dto.PubDataRaw == null) { if (Debugger.IsAttached) { throw new InvalidOperationException("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding."); } _logger.LogWarning("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); } else { bool published = true; var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw, published); p = new ContentData( dto.PubName, deserializedContent?.UrlSegment, dto.VersionId, dto.PubVersionDate, dto.PubWriterId, dto.PubTemplateId, published, deserializedContent?.PropertyData, deserializedContent?.CultureData); } } var n = new ContentNode(dto.Id, dto.Key, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit(n, dto.ContentTypeId, d, p); return(s); }
private IEnumerable <ContentNodeKit> CreateCache( bool createChildren, IDataType dataType, out ContentType[] contentTypes) { var result = new List <ContentNodeKit>(); var valueCounter = 1; var parentId = 3; var properties = new Dictionary <string, string> { ["property1"] = "Property 1", ["property2"] = "Property 2", }; ContentType parentContentType = CreateContentType("Parent", dataType, new Dictionary <string, string>(properties) { ["property3"] = "Property 3" }); ContentType childContentType = CreateContentType("Child", dataType, new Dictionary <string, string>(properties) { ["property4"] = "Property 4" }); ContentType child2ContentType = CreateContentType("Child2", dataType, new Dictionary <string, string>(properties) { ["property4"] = "Property 4" }); contentTypes = new[] { parentContentType, childContentType, child2ContentType }; ContentData parentData = new ContentDataBuilder() .WithName("Page" + Guid.NewGuid()) .WithProperties(new PropertyDataBuilder() .WithPropertyData("property1", "value" + valueCounter) .WithPropertyData("property2", "value" + (valueCounter + 1)) .WithPropertyData("property3", "value" + (valueCounter + 2)) .Build()) .Build(); ContentNodeKit parent = ContentNodeKitBuilder.CreateWithContent( parentContentType.Id, parentId, $"-1,{parentId}", draftData: parentData, publishedData: parentData); result.Add(parent); if (createChildren) { for (int i = 0; i < 3; i++) { valueCounter += 3; var childId = parentId + i + 1; ContentData childData = new ContentDataBuilder() .WithName("Page" + Guid.NewGuid()) .WithProperties(new PropertyDataBuilder() .WithPropertyData("property1", "value" + valueCounter) .WithPropertyData("property2", "value" + (valueCounter + 1)) .WithPropertyData("property4", "value" + (valueCounter + 2)) .Build()) .Build(); ContentNodeKit child = ContentNodeKitBuilder.CreateWithContent( i > 0 ? childContentType.Id : child2ContentType.Id, childId, $"-1,{parentId},{childId}", i, draftData: childData, publishedData: childData); result.Add(child); } } return(result); }
private void PopulateCache(string culture = "fr-FR") { var dataTypes = GetDefaultDataTypes(); var propertyDataTypes = new Dictionary <string, IDataType> { // we only have one data type for this test which will be resolved with string empty. [string.Empty] = dataTypes[0] }; var contentType1 = new ContentType(ShortStringHelper, -1); ContentData rootData = new ContentDataBuilder() .WithName("Page" + Guid.NewGuid()) .WithCultureInfos(new Dictionary <string, CultureVariation> { [culture] = new CultureVariation { Name = "root", IsDraft = true, Date = DateTime.Now, UrlSegment = "root" }, }) .Build(ShortStringHelper, propertyDataTypes, contentType1, "alias"); ContentNodeKit root = ContentNodeKitBuilder.CreateWithContent( contentType1.Id, 9876, $"-1,9876", draftData: rootData, publishedData: rootData); ContentData parentData = new ContentDataBuilder() .WithName("Page" + Guid.NewGuid()) .WithCultureInfos(new Dictionary <string, CultureVariation> { [culture] = new CultureVariation { Name = "home", IsDraft = true, Date = DateTime.Now, UrlSegment = "home" }, }) .Build(); ContentNodeKit parent = ContentNodeKitBuilder.CreateWithContent( contentType1.Id, 5432, $"-1,9876,5432", parentContentId: 9876, draftData: parentData, publishedData: parentData); ContentData contentData = new ContentDataBuilder() .WithName("Page" + Guid.NewGuid()) .WithCultureInfos(new Dictionary <string, CultureVariation> { [culture] = new CultureVariation { Name = "name-fr2", IsDraft = true, Date = DateTime.Now, UrlSegment = "test-fr" }, }) .Build(); ContentNodeKit content = ContentNodeKitBuilder.CreateWithContent( contentType1.Id, 1234, $"-1,9876,5432,1234", parentContentId: 5432, draftData: contentData, publishedData: contentData); InitializedCache(new[] { root, parent, content }, new[] { contentType1 }, dataTypes: dataTypes); }