Handle tags when variations change

This commit is contained in:
Stephan
2018-12-04 08:23:18 +01:00
parent 18c382d888
commit 5c140762c4
7 changed files with 393 additions and 23 deletions

View File

@@ -595,7 +595,6 @@ namespace Umbraco.Core
return null;
}
/// <summary>
/// Attempts to serialize the value to an XmlString using ToXmlString
/// </summary>
@@ -788,5 +787,20 @@ namespace Umbraco.Core
return BoolConvertCache[type] = false;
}
/// <summary>
/// Indicates whether two nullable values are equal, substituting a fallback value for nulls.
/// </summary>
/// <typeparam name="T">The nullable type.</typeparam>
/// <param name="value">The value to compare.</param>
/// <param name="other">The value to compare to.</param>
/// <param name="fallbackValue">The value to use when any value is null.</param>
/// <remarks>Do not use outside of Sql expressions.</remarks>
// see usage in ExpressionVisitorBase
public static bool NEquals<T>(this T? value, T? other, T fallbackValue)
where T : struct
{
return (value ?? fallbackValue).Equals(other ?? fallbackValue);
}
}
}

View File

@@ -3,11 +3,13 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Persistence.Dtos
{
[TableName(Constants.DatabaseSchema.Tables.TagRelationship)]
[TableName(TableName)]
[PrimaryKey("nodeId", AutoIncrement = false)]
[ExplicitColumns]
internal class TagRelationshipDto
{
public const string TableName = Constants.DatabaseSchema.Tables.TagRelationship;
[Column("nodeId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsTagRelationship", OnColumns = "nodeId, propertyTypeId, tagId")]
[ForeignKey(typeof(ContentDto), Name = "FK_cmsTagRelationship_cmsContent", Column = "nodeId")]

View File

@@ -653,6 +653,23 @@ namespace Umbraco.Core.Persistence.Querying
else
throw new NotSupportedException("Expression is not a proper lambda.");
// c# 'x == null' becomes sql 'x IS NULL' which is fine
// c# 'x == y' becomes sql 'x = @0' which is fine - unless they are nullable types,
// because sql 'x = NULL' is always false and the 'IS NULL' syntax is required,
// so for comparing nullable types, we use x.NEquals(y, fb) where fb is a fallback
// value which will be used when values are null - turning the comparison into
// sql 'COALESCE(x,fb) = COALESCE(y,fb)' - of course, fb must be a value outside
// of x and y range - and if that is not possible, then a manual comparison need
// to be written
//TODO support NEquals with 0 parameters, using the full syntax below
case "NEquals":
var compareTo = Visit(m.Arguments[1]);
var fallback = Visit(m.Arguments[2]);
// that would work without a fallback value but is more cumbersome
//return Visited ? string.Empty : $"((({compareTo} is null) AND ({visitedMethodObject} is null)) OR (({compareTo} is not null) AND ({visitedMethodObject} = {compareTo})))";
// use a fallback value
return Visited ? string.Empty : $"(COALESCE({visitedMethodObject},{fallback}) = COALESCE({compareTo},{fallback}))";
default:
throw new ArgumentOutOfRangeException("No logic supported for " + m.Method.Name);

View File

@@ -190,8 +190,8 @@ AND umbracoNode.nodeObjectType = @objectType",
SortOrder = allowedContentType.SortOrder
});
}
//Insert Tabs
foreach (var propertyGroup in entity.PropertyGroups)
{
@@ -620,7 +620,7 @@ AND umbracoNode.id <> @id",
var sqlDelete = Sql()
.Delete<RedirectUrlDto>()
.WhereIn((System.Linq.Expressions.Expression<Func<RedirectUrlDto, object>>)(x => x.ContentKey), sqlSelect);
Database.Execute(sqlDelete);
}
@@ -663,9 +663,11 @@ AND umbracoNode.id <> @id",
{
case ContentVariation.Culture:
CopyPropertyData(null, defaultLanguageId, propertyTypeIds, impactedL);
CopyTagData(null, defaultLanguageId, propertyTypeIds, impactedL);
break;
case ContentVariation.Nothing:
CopyPropertyData(defaultLanguageId, null, propertyTypeIds, impactedL);
CopyTagData(defaultLanguageId, null, propertyTypeIds, impactedL);
break;
case ContentVariation.CultureAndSegment:
case ContentVariation.Segment:
@@ -690,7 +692,7 @@ AND umbracoNode.id <> @id",
//first clear out any existing names that might already exists under the default lang
//there's 2x tables to update
//clear out the versionCultureVariation table
//clear out the versionCultureVariation table
var sqlSelect = Sql().Select<ContentVersionCultureVariationDto>(x => x.Id)
.From<ContentVersionCultureVariationDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, ContentVersionCultureVariationDto>(x => x.Id, x => x.VersionId)
@@ -757,6 +759,129 @@ AND umbracoNode.id <> @id",
}
}
///
private void CopyTagData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection<int> propertyTypeIds, IReadOnlyCollection<int> contentTypeIds = null)
{
// note: important to use NEquals for nullable types, cannot directly compare language identifiers
// fixme - should we batch then?
var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0);
if (whereInArgsCount > 2000)
throw new NotSupportedException("Too many property/content types.");
// delete existing relations (for target language)
// do *not* delete existing tags
var sqlTagToDelete = Sql()
.Select<TagDto>(x => x.Id)
.From<TagDto>()
.InnerJoin<TagRelationshipDto>().On<TagDto, TagRelationshipDto>((tag, rel) => tag.Id == rel.TagId);
if (contentTypeIds != null)
sqlTagToDelete
.InnerJoin<ContentDto>().On<TagRelationshipDto, ContentDto>((rel, content) => rel.NodeId == content.NodeId)
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIds);
sqlTagToDelete
.WhereIn<TagRelationshipDto>(x => x.PropertyTypeId, propertyTypeIds)
.Where<TagDto>(x => x.LanguageId.NEquals(targetLanguageId, -1));
var sqlDeleteRel = Sql()
.Delete<TagRelationshipDto>()
.WhereIn<TagRelationshipDto>(x => x.TagId, sqlTagToDelete);
sqlDeleteRel.WriteToConsole();
Database.Execute(sqlDeleteRel);
// do *not* delete the tags - they could be used by other content types / property types
/*
var sqlDeleteTag = Sql()
.Delete<TagDto>()
.WhereIn<TagDto>(x => x.Id, sqlTagToDelete);
Database.Execute(sqlDeleteTag);
*/
// copy tags from source language to target language
var targetLanguageIdS = targetLanguageId.HasValue ? targetLanguageId.ToString() : "NULL";
var sqlSelect = Sql()
.Select<TagDto>(x => x.Text, x => x.Group)
.Append(", " + targetLanguageIdS)
.From<TagDto>();
sqlSelect
.InnerJoin<TagRelationshipDto>().On<TagDto, TagRelationshipDto>((tag, rel) => tag.Id == rel.TagId)
.LeftJoin<TagDto>("xtags").On<TagDto, TagDto>((tag, xtag) => tag.Text == xtag.Text && tag.Group == xtag.Group && tag.LanguageId.NEquals(targetLanguageId, -1), aliasRight: "xtags");
if (contentTypeIds != null)
sqlSelect
.InnerJoin<ContentDto>().On<TagRelationshipDto, ContentDto>((rel, content) => rel.NodeId == content.NodeId);
sqlSelect
.WhereIn<TagRelationshipDto>(x => x.PropertyTypeId, propertyTypeIds)
.WhereNull<TagDto>(x => x.Id, "xtags"); // ie, not exists
if (contentTypeIds != null)
sqlSelect
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIds);
sqlSelect.Where<TagDto>(x => x.LanguageId.NEquals(sourceLanguageId, -1));
var cols = Sql().Columns<TagDto>(x => x.Text, x => x.Group, x => x.LanguageId);
var sqlInsertTag = Sql($"INSERT INTO {TagDto.TableName} ({cols})").Append(sqlSelect);
sqlInsertTag.WriteToConsole();
Database.Execute(sqlInsertTag);
// create relations to new tags
var sqlFoo = Sql()
.Select<TagRelationshipDto>(x => x.NodeId, x => x.PropertyTypeId)
.AndSelect<TagDto>("otag", x => x.Id)
.From<TagRelationshipDto>()
.InnerJoin<TagDto>().On<TagRelationshipDto, TagDto>((rel, tag) => rel.TagId == tag.Id)
.InnerJoin<TagDto>("otag").On<TagDto, TagDto>((tag, otag) => tag.Text == otag.Text && tag.Group == otag.Group && otag.LanguageId.NEquals(targetLanguageId, -1), aliasRight: "otag")
.Where<TagDto>(x => x.LanguageId.NEquals(sourceLanguageId, -1));
var cols2 = Sql().Columns<TagRelationshipDto>(x => x.NodeId, x => x.PropertyTypeId, x => x.TagId);
var sqlInsertRel = Sql($"INSERT INTO {TagRelationshipDto.TableName} ({cols2})").Append(sqlFoo);
sqlInsertRel.WriteToConsole();
Database.Execute(sqlInsertRel);
// delete original relations - *not* the tags - all of them
// cannot really "go back" with relations, would have to do it with property values
sqlTagToDelete = Sql()
.Select<TagDto>(x => x.Id)
.From<TagDto>()
.InnerJoin<TagRelationshipDto>().On<TagDto, TagRelationshipDto>((tag, rel) => tag.Id == rel.TagId);
if (contentTypeIds != null)
sqlTagToDelete
.InnerJoin<ContentDto>().On<TagRelationshipDto, ContentDto>((rel, content) => rel.NodeId == content.NodeId)
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIds);
sqlTagToDelete
.WhereIn<TagRelationshipDto>(x => x.PropertyTypeId, propertyTypeIds)
.Where<TagDto>(x => !x.LanguageId.NEquals(targetLanguageId, -1));
sqlDeleteRel = Sql()
.Delete<TagRelationshipDto>()
.WhereIn<TagRelationshipDto>(x => x.TagId, sqlTagToDelete);
sqlDeleteRel.WriteToConsole();
Database.Execute(sqlDeleteRel);
// no
/*
var sqlDeleteTag = Sql()
.Delete<TagDto>()
.WhereIn<TagDto>(x => x.Id, sqlTagToDelete);
Database.Execute(sqlDeleteTag);
*/
}
/// <summary>
/// Copies property data from one language to another.
/// </summary>
@@ -766,6 +891,8 @@ AND umbracoNode.id <> @id",
/// <param name="contentTypeIds">The content type identifiers.</param>
private void CopyPropertyData(int? sourceLanguageId, int? targetLanguageId, IReadOnlyCollection<int> propertyTypeIds, IReadOnlyCollection<int> contentTypeIds = null)
{
// note: important to use NEquals for nullable types, cannot directly compare language identifiers
//
// fixme - should we batch then?
var whereInArgsCount = propertyTypeIds.Count + (contentTypeIds?.Count ?? 0);
if (whereInArgsCount > 2000)
@@ -793,11 +920,7 @@ AND umbracoNode.id <> @id",
sqlDelete.WhereIn<PropertyDataDto>(x => x.VersionId, inSql);
}
// NPoco cannot turn the clause into IS NULL with a nullable parameter - deal with it
if (targetLanguageId == null)
sqlDelete.Where<PropertyDataDto>(x => x.LanguageId == null);
else
sqlDelete.Where<PropertyDataDto>(x => x.LanguageId == targetLanguageId);
sqlDelete.Where<PropertyDataDto>(x => x.LanguageId.NEquals(targetLanguageId, -1));
sqlDelete
.WhereIn<PropertyDataDto>(x => x.PropertyTypeId, propertyTypeIds);
@@ -821,11 +944,7 @@ AND umbracoNode.id <> @id",
.InnerJoin<ContentVersionDto>().On<PropertyDataDto, ContentVersionDto>((pdata, cversion) => pdata.VersionId == cversion.Id)
.InnerJoin<ContentDto>().On<ContentVersionDto, ContentDto>((cversion, c) => cversion.NodeId == c.NodeId);
// NPoco cannot turn the clause into IS NULL with a nullable parameter - deal with it
if (sourceLanguageId == null)
sqlSelectData.Where<PropertyDataDto>(x => x.LanguageId == null);
else
sqlSelectData.Where<PropertyDataDto>(x => x.LanguageId == sourceLanguageId);
sqlSelectData.Where<PropertyDataDto>(x => x.LanguageId.NEquals(sourceLanguageId, -1));
sqlSelectData
.WhereIn<PropertyDataDto>(x => x.PropertyTypeId, propertyTypeIds);

View File

@@ -67,6 +67,24 @@ namespace Umbraco.Core.Persistence
/// <inheritdoc />
public ISqlContext SqlContext { get; }
#region Temp
// work around NPoco issue https://github.com/schotime/NPoco/issues/517 while we wait for the fix
public override DbCommand CreateCommand(DbConnection connection, CommandType commandType, string sql, params object[] args)
{
var command = base.CreateCommand(connection, commandType, sql, args);
if (!DatabaseType.IsSqlCe()) return command;
foreach (DbParameter parameter in command.Parameters)
if (parameter.Value == DBNull.Value)
parameter.DbType = DbType.String;
return command;
}
#endregion
#region Testing, Debugging and Troubleshooting
private bool _enableCount;
@@ -242,7 +260,9 @@ namespace Umbraco.Core.Persistence
sb.Append(" @");
sb.Append(i++);
sb.Append(":");
sb.Append(arg);
if (arg == DBNull.Value) sb.Append("<dbNull>");
else if (arg == null) sb.Append("<null>");
else sb.Append(arg);
}
return sb.ToString();

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using NPoco;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Tests.TestHelpers;
@@ -11,6 +12,80 @@ namespace Umbraco.Tests.Persistence.NPocoTests
[TestFixture]
public class NPocoSqlExtensionsTests : BaseUsingSqlCeSyntax
{
[Test]
public void WhereTest()
{
var sql = new Sql<ISqlContext>(SqlContext)
.Select("*")
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => x.LanguageId == null);
Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] is null))", sql.SQL, sql.SQL);
sql = new Sql<ISqlContext>(SqlContext)
.Select("*")
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => x.LanguageId == 123);
Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] = @0))", sql.SQL, sql.SQL);
var id = 123;
sql = new Sql<ISqlContext>(SqlContext)
.Select("*")
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => x.LanguageId == id);
Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] = @0))", sql.SQL, sql.SQL);
int? nid = 123;
sql = new Sql<ISqlContext>(SqlContext)
.Select("*")
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => x.LanguageId == nid);
Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE (([umbracoPropertyData].[languageId] = @0))", sql.SQL, sql.SQL);
// but the above comparison fails if @0 is null
// what we want is something similar to:
sql = new Sql<ISqlContext>(SqlContext)
.Select("*")
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => (nid == null && x.LanguageId == null) || (nid != null && x.LanguageId == nid));
Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@1 is not null) AND ([umbracoPropertyData].[languageId] = @2))))", sql.SQL, sql.SQL);
// new NEquals method does it automatically
// 'course it would be nicer if '==' could do it
// see note in ExpressionVisitorBase for NEquals
//sql = new Sql<ISqlContext>(SqlContext)
// .Select("*")
// .From<PropertyDataDto>()
// .Where<PropertyDataDto>(x => x.LanguageId.NEquals(nid));
//Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((((@0 is null) AND ([umbracoPropertyData].[languageId] is null)) OR ((@0 is not null) AND ([umbracoPropertyData].[languageId] = @0))))", sql.SQL, sql.SQL);
// but, the expression above fails with SQL CE, 'specified argument for the function is not valid' in 'isnull' function
// so... compare with fallback values
sql = new Sql<ISqlContext>(SqlContext)
.Select("*")
.From<PropertyDataDto>()
.Where<PropertyDataDto>(x => x.LanguageId.NEquals(nid, -1));
Assert.AreEqual("SELECT *\nFROM [umbracoPropertyData]\nWHERE ((COALESCE([umbracoPropertyData].[languageId],@0) = COALESCE(@1,@0)))", sql.SQL, sql.SQL);
}
[Test]
public void NEqualsTest()
{
int? a, b;
a = b = null;
Assert.IsTrue(a.NEquals(b, -1));
b = 2;
Assert.IsFalse(a.NEquals(b, -1));
a = 2;
Assert.IsTrue(a.NEquals(b, -1));
b = null;
Assert.IsFalse(a.NEquals(b, -1));
}
[Test]
public void WhereInValueFieldTest()
{

View File

@@ -129,6 +129,133 @@ namespace Umbraco.Tests.Services
Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus"));
}
[Test]
public void TagsCanBecomeVariant()
{
var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value;
var contentService = ServiceContext.ContentService;
var contentTypeService = ServiceContext.ContentTypeService;
var tagService = ServiceContext.TagService;
var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true);
PropertyType propertyType;
contentType.PropertyGroups.First().PropertyTypes.Add(
propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags")
{
DataTypeId = 1041
});
contentTypeService.Save(contentType);
IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
content1.AssignTags("tags", new[] { "hello", "world", "another", "one" });
contentService.SaveAndPublish(content1);
contentType.Variations = ContentVariation.Culture;
contentTypeService.Save(contentType);
// no changes
content1 = contentService.GetById(content1.Id);
var tags = content1.Properties["tags"].GetTagsValue().ToArray();
Assert.AreEqual(4, tags.Length);
Assert.Contains("one", tags);
Assert.AreEqual(-1, tags.IndexOf("plus"));
var tagGroups = tagService.GetAllTags().GroupBy(x => x.LanguageId);
foreach (var tag in tagService.GetAllTags())
Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}");
Assert.AreEqual(1, tagGroups.Count());
var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null);
Assert.IsNotNull(enTagGroup);
Assert.AreEqual(4, enTagGroup.Count());
Assert.IsTrue(enTagGroup.Any(x => x.Text == "one"));
Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus"));
propertyType.Variations = ContentVariation.Culture;
contentTypeService.Save(contentType);
// changes
content1 = contentService.GetById(content1.Id);
// property value has been moved from invariant to en-US
tags = content1.Properties["tags"].GetTagsValue().ToArray();
Assert.IsEmpty(tags);
tags = content1.Properties["tags"].GetTagsValue("en-US").ToArray();
Assert.AreEqual(4, tags.Length);
Assert.Contains("one", tags);
Assert.AreEqual(-1, tags.IndexOf("plus"));
// tags have been copied from invariant to en-US
tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId);
foreach (var tag in tagService.GetAllTags("*"))
Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}");
Assert.AreEqual(1, tagGroups.Count());
enTagGroup = tagGroups.FirstOrDefault(x => x.Key == enId);
Assert.IsNotNull(enTagGroup);
Assert.AreEqual(4, enTagGroup.Count());
Assert.IsTrue(enTagGroup.Any(x => x.Text == "one"));
Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus"));
}
[Test]
public void TagsCanBecomeInvariant()
{
var languageService = ServiceContext.LocalizationService;
languageService.Save(new Language("fr-FR")); // en-US is already there
var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value;
var contentService = ServiceContext.ContentService;
var contentTypeService = ServiceContext.ContentTypeService;
var tagService = ServiceContext.TagService;
var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true);
PropertyType propertyType;
contentType.PropertyGroups.First().PropertyTypes.Add(
propertyType = new PropertyType("test", ValueStorageType.Ntext, "tags")
{
DataTypeId = 1041,
Variations = ContentVariation.Culture
});
contentType.Variations = ContentVariation.Culture;
contentTypeService.Save(contentType);
IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
content1.SetCultureName("name-fr", "fr-FR");
content1.SetCultureName("name-en", "en-US");
content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR");
content1.AssignTags("tags", new[] { "hello", "world", "another", "one" }, culture: "en-US");
contentService.SaveAndPublish(content1);
contentType.Variations = ContentVariation.Nothing;
contentTypeService.Save(contentType);
// changes
content1 = contentService.GetById(content1.Id);
// property value has been moved from en-US to invariant, fr-FR tags are gone
Assert.IsEmpty(content1.Properties["tags"].GetTagsValue("fr-FR"));
Assert.IsEmpty(content1.Properties["tags"].GetTagsValue("en-US"));
var tags = content1.Properties["tags"].GetTagsValue().ToArray();
Assert.AreEqual(4, tags.Length);
Assert.Contains("one", tags);
Assert.AreEqual(-1, tags.IndexOf("plus"));
// tags have been copied from en-US to invariant, fr-FR tags are gone
var tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId);
foreach (var tag in tagService.GetAllTags("*"))
Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}");
Assert.AreEqual(1, tagGroups.Count());
var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null);
Assert.IsNotNull(enTagGroup);
Assert.AreEqual(4, enTagGroup.Count());
Assert.IsTrue(enTagGroup.Any(x => x.Text == "one"));
Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus"));
}
[Test]
public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_One()
{
@@ -193,7 +320,7 @@ namespace Umbraco.Tests.Services
}
[Test]
[Ignore("U4-8442, will need to be fixed eventually.")]
//[Ignore("U4-8442, will need to be fixed eventually.")]
public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_Tree()
{
var contentService = ServiceContext.ContentService;
@@ -209,12 +336,10 @@ namespace Umbraco.Tests.Services
var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "plus" });
content1.PublishCulture();
contentService.SaveAndPublish(content1);
var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1.Id);
content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" });
content2.PublishCulture();
contentService.SaveAndPublish(content2);
// verify
@@ -298,7 +423,7 @@ namespace Umbraco.Tests.Services
}
[Test]
[Ignore("U4-8442, will need to be fixed eventually.")]
//[Ignore("U4-8442, will need to be fixed eventually.")]
public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished_Tree()
{
var contentService = ServiceContext.ContentService;
@@ -314,12 +439,10 @@ namespace Umbraco.Tests.Services
var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
content1.AssignTags("tags", new[] { "hello", "world", "some", "tags", "bam" });
content1.PublishCulture();
contentService.SaveAndPublish(content1);
var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1);
content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" });
content2.PublishCulture();
contentService.SaveAndPublish(content2);
contentService.Unpublish(content1);