Skip to content

Commit 65723ea

Browse files
authored
Merge pull request #12087 from umbraco/v9/bugfix/history-cleanup-make-contenttype-dirty
V9: Fix history cleanup not making content type dirty
2 parents 50a239a + 5ef013c commit 65723ea

File tree

4 files changed

+188
-10
lines changed

4 files changed

+188
-10
lines changed
Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
using System.Runtime.Serialization;
2+
using Umbraco.Cms.Core.Models.Entities;
23

34
namespace Umbraco.Cms.Core.Models.ContentEditing
45
{
56
[DataContract(Name = "historyCleanup", Namespace = "")]
6-
public class HistoryCleanup
7+
public class HistoryCleanup : BeingDirtyBase
78
{
9+
private bool _preventCleanup;
10+
private int? _keepAllVersionsNewerThanDays;
11+
private int? _keepLatestVersionPerDayForDays;
12+
813
[DataMember(Name = "preventCleanup")]
9-
public bool PreventCleanup { get; set; }
14+
public bool PreventCleanup
15+
{
16+
get => _preventCleanup;
17+
set => SetPropertyValueAndDetectChanges(value, ref _preventCleanup, nameof(PreventCleanup));
18+
}
1019

1120
[DataMember(Name = "keepAllVersionsNewerThanDays")]
12-
public int? KeepAllVersionsNewerThanDays { get; set; }
21+
public int? KeepAllVersionsNewerThanDays
22+
{
23+
get => _keepAllVersionsNewerThanDays;
24+
set => SetPropertyValueAndDetectChanges(value, ref _keepAllVersionsNewerThanDays, nameof(KeepAllVersionsNewerThanDays));
25+
}
1326

1427
[DataMember(Name = "keepLatestVersionPerDayForDays")]
15-
public int? KeepLatestVersionPerDayForDays { get; set; }
28+
public int? KeepLatestVersionPerDayForDays
29+
{
30+
get => _keepLatestVersionPerDayForDays;
31+
set => SetPropertyValueAndDetectChanges(value, ref _keepLatestVersionPerDayForDays, nameof(KeepLatestVersionPerDayForDays));
32+
}
1633
}
1734
}

src/Umbraco.Core/Models/ContentType.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,13 @@ public IEnumerable<ITemplate> AllowedTemplates
9696
}
9797
}
9898

99-
public HistoryCleanup HistoryCleanup { get; set; }
99+
private HistoryCleanup _historyCleanup;
100+
101+
public HistoryCleanup HistoryCleanup
102+
{
103+
get => _historyCleanup;
104+
set => SetPropertyValueAndDetectChanges(value, ref _historyCleanup, nameof(HistoryCleanup));
105+
}
100106

101107
/// <summary>
102108
/// Determines if AllowedTemplates contains templateId
@@ -162,5 +168,8 @@ public bool RemoveTemplate(ITemplate template)
162168
/// <inheritdoc />
163169
IContentType IContentType.DeepCloneWithResetIdentities(string newAlias) =>
164170
(IContentType)DeepCloneWithResetIdentities(newAlias);
171+
172+
/// <inheritdoc/>
173+
public override bool IsDirty() => base.IsDirty() || HistoryCleanup.IsDirty();
165174
}
166175
}

src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ private void Map(DocumentTypeSave source, IContentType target, MapperContext con
133133

134134
if (target is IContentTypeWithHistoryCleanup targetWithHistoryCleanup)
135135
{
136-
targetWithHistoryCleanup.HistoryCleanup = source.HistoryCleanup;
136+
MapHistoryCleanup(source, targetWithHistoryCleanup);
137137
}
138138

139139
target.AllowedTemplates = source.AllowedTemplates
@@ -147,6 +147,34 @@ private void Map(DocumentTypeSave source, IContentType target, MapperContext con
147147
: _fileService.GetTemplate(source.DefaultTemplate));
148148
}
149149

150+
private static void MapHistoryCleanup(DocumentTypeSave source, IContentTypeWithHistoryCleanup target)
151+
{
152+
// If source history cleanup is null we don't have to map all properties
153+
if (source.HistoryCleanup is null)
154+
{
155+
target.HistoryCleanup = null;
156+
return;
157+
}
158+
159+
// We need to reset the dirty properties, because it is otherwise true, just because the json serializer has set properties
160+
target.HistoryCleanup.ResetDirtyProperties(false);
161+
if (target.HistoryCleanup.PreventCleanup != source.HistoryCleanup.PreventCleanup)
162+
{
163+
target.HistoryCleanup.PreventCleanup = source.HistoryCleanup.PreventCleanup;
164+
}
165+
166+
if (target.HistoryCleanup.KeepAllVersionsNewerThanDays != source.HistoryCleanup.KeepAllVersionsNewerThanDays)
167+
{
168+
target.HistoryCleanup.KeepAllVersionsNewerThanDays = source.HistoryCleanup.KeepAllVersionsNewerThanDays;
169+
}
170+
171+
if (target.HistoryCleanup.KeepLatestVersionPerDayForDays !=
172+
source.HistoryCleanup.KeepLatestVersionPerDayForDays)
173+
{
174+
target.HistoryCleanup.KeepLatestVersionPerDayForDays = source.HistoryCleanup.KeepLatestVersionPerDayForDays;
175+
}
176+
}
177+
150178
// no MapAll - take care
151179
private void Map(MediaTypeSave source, IMediaType target, MapperContext context)
152180
{
@@ -328,7 +356,10 @@ private static void Map(PropertyTypeBasic source, IPropertyType target, MapperCo
328356

329357
if (source.GroupId > 0)
330358
{
331-
target.PropertyGroupId = new Lazy<int>(() => source.GroupId, false);
359+
if (target.PropertyGroupId?.Value != source.GroupId)
360+
{
361+
target.PropertyGroupId = new Lazy<int>(() => source.GroupId, false);
362+
}
332363
}
333364

334365
target.Alias = source.Alias;
@@ -523,7 +554,15 @@ private static void MapSaveToTypeBase<TSource, TSourcePropertyType>(TSource sour
523554
target.Thumbnail = source.Thumbnail;
524555

525556
target.AllowedAsRoot = source.AllowAsRoot;
526-
target.AllowedContentTypes = source.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i));
557+
558+
bool allowedContentTypesUnchanged = target.AllowedContentTypes.Select(x => x.Id.Value)
559+
.SequenceEqual(source.AllowedContentTypes);
560+
561+
if (allowedContentTypesUnchanged is false)
562+
{
563+
target.AllowedContentTypes = source.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i));
564+
}
565+
527566

528567
if (!(target is IMemberType))
529568
{
@@ -574,13 +613,21 @@ private static void MapSaveToTypeBase<TSource, TSourcePropertyType>(TSource sour
574613

575614
// ensure no duplicate alias, then assign the group properties collection
576615
EnsureUniqueAliases(destProperties);
577-
destGroup.PropertyTypes = new PropertyTypeCollection(isPublishing, destProperties);
616+
if (destGroup.PropertyTypes.SupportsPublishing != isPublishing || destGroup.PropertyTypes.SequenceEqual(destProperties) is false)
617+
{
618+
destGroup.PropertyTypes = new PropertyTypeCollection(isPublishing, destProperties);
619+
}
620+
578621
destGroups.Add(destGroup);
579622
}
580623

581624
// ensure no duplicate name, then assign the groups collection
582625
EnsureUniqueAliases(destGroups);
583-
target.PropertyGroups = new PropertyGroupCollection(destGroups);
626+
627+
if (target.PropertyGroups.SequenceEqual(destGroups) is false)
628+
{
629+
target.PropertyGroups = new PropertyGroupCollection(destGroups);
630+
}
584631

585632
// because the property groups collection was rebuilt, there is no need to remove
586633
// the old groups - they are just gone and will be cleared by the repository
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
using Umbraco.Cms.Core.Models.ContentEditing;
4+
using Umbraco.Cms.Tests.Common.Builders;
5+
6+
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Models
7+
{
8+
[TestFixture]
9+
public class ContentTypeHistoryCleanupTests
10+
{
11+
[Test]
12+
public void Changing_Keep_all_Makes_ContentType_Dirty()
13+
{
14+
var contentType = ContentTypeBuilder.CreateBasicContentType();
15+
16+
Assert.IsFalse(contentType.IsDirty());
17+
18+
var newValue = 2;
19+
contentType.HistoryCleanup.KeepAllVersionsNewerThanDays = newValue;
20+
Assert.IsTrue(contentType.IsDirty());
21+
Assert.AreEqual(newValue, contentType.HistoryCleanup.KeepAllVersionsNewerThanDays);
22+
}
23+
24+
[Test]
25+
public void Changing_Keep_latest_Makes_ContentType_Dirty()
26+
{
27+
var contentType = ContentTypeBuilder.CreateBasicContentType();
28+
29+
Assert.IsFalse(contentType.IsDirty());
30+
31+
var newValue = 2;
32+
contentType.HistoryCleanup.KeepLatestVersionPerDayForDays = newValue;
33+
Assert.IsTrue(contentType.IsDirty());
34+
Assert.AreEqual(newValue, contentType.HistoryCleanup.KeepLatestVersionPerDayForDays);
35+
}
36+
37+
[Test]
38+
public void Changing_Prevent_Cleanup_Makes_ContentType_Dirty()
39+
{
40+
var contentType = ContentTypeBuilder.CreateBasicContentType();
41+
42+
Assert.IsFalse(contentType.IsDirty());
43+
44+
var newValue = true;
45+
contentType.HistoryCleanup.PreventCleanup = newValue;
46+
Assert.IsTrue(contentType.IsDirty());
47+
Assert.AreEqual(newValue, contentType.HistoryCleanup.PreventCleanup);
48+
}
49+
50+
[Test]
51+
public void Replacing_History_Cleanup_Registers_As_Dirty()
52+
{
53+
var contentType = ContentTypeBuilder.CreateBasicContentType();
54+
Assert.IsFalse(contentType.IsDirty());
55+
56+
contentType.HistoryCleanup = new HistoryCleanup();
57+
58+
Assert.IsTrue(contentType.IsDirty());
59+
Assert.IsTrue(contentType.IsPropertyDirty(nameof(contentType.HistoryCleanup)));
60+
}
61+
62+
[Test]
63+
public void Replacing_History_Cleanup_Removes_Old_Dirty_History_Properties()
64+
{
65+
var contentType = ContentTypeBuilder.CreateBasicContentType();
66+
67+
contentType.Alias = "NewValue";
68+
contentType.HistoryCleanup.KeepAllVersionsNewerThanDays = 2;
69+
70+
contentType.PropertyChanged += (sender, args) =>
71+
{
72+
// Ensure that property changed is only invoked for history cleanup
73+
Assert.AreEqual(nameof(contentType.HistoryCleanup), args.PropertyName);
74+
};
75+
76+
// Since we're replacing the entire HistoryCleanup the changed property is no longer dirty, the entire HistoryCleanup is
77+
contentType.HistoryCleanup = new HistoryCleanup();
78+
79+
Assert.Multiple(() =>
80+
{
81+
Assert.IsTrue(contentType.IsDirty());
82+
Assert.IsFalse(contentType.WasDirty());
83+
Assert.AreEqual(2, contentType.GetDirtyProperties().Count());
84+
Assert.IsTrue(contentType.IsPropertyDirty(nameof(contentType.HistoryCleanup)));
85+
Assert.IsTrue(contentType.IsPropertyDirty(nameof(contentType.Alias)));
86+
});
87+
}
88+
89+
[Test]
90+
public void Old_History_Cleanup_Reference_Doesnt_Make_Content_Type_Dirty()
91+
{
92+
var contentType = ContentTypeBuilder.CreateBasicContentType();
93+
var oldHistoryCleanup = contentType.HistoryCleanup;
94+
95+
contentType.HistoryCleanup = new HistoryCleanup();
96+
contentType.ResetDirtyProperties();
97+
contentType.ResetWereDirtyProperties();
98+
99+
oldHistoryCleanup.KeepAllVersionsNewerThanDays = 2;
100+
101+
Assert.IsFalse(contentType.IsDirty());
102+
Assert.IsFalse(contentType.WasDirty());
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)