Adds change tracking to the schedule collection, updates the DocumentRepository to add logic to fetch the schedule, adds/updates tests, all green

This commit is contained in:
Shannon
2018-11-05 17:20:26 +11:00
parent 0d35a6a140
commit 24360a762c
10 changed files with 333 additions and 92 deletions

View File

@@ -92,10 +92,36 @@ namespace Umbraco.Core.Models
}
/// <inheritdoc />
[DoNotClone]
public ContentScheduleCollection ContentSchedule
{
get => _schedule ?? (_schedule = new ContentScheduleCollection());
set => SetPropertyValueAndDetectChanges(value, ref _schedule, Ps.Value.ContentScheduleSelector);
get
{
if (_schedule == null)
{
_schedule = new ContentScheduleCollection();
_schedule.CollectionChanged += ScheduleCollectionChanged;
}
return _schedule ?? (_schedule = new ContentScheduleCollection());
}
set
{
if(_schedule != null)
_schedule.CollectionChanged -= ScheduleCollectionChanged;
SetPropertyValueAndDetectChanges(value, ref _schedule, Ps.Value.ContentScheduleSelector);
if (_schedule != null)
_schedule.CollectionChanged += ScheduleCollectionChanged;
}
}
/// <summary>
/// Collection changed event handler to ensure the schedule field is set to dirty when the schedule changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScheduleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(Ps.Value.ContentScheduleSelector);
}
/// <summary>
@@ -125,13 +151,13 @@ namespace Umbraco.Core.Models
return ContentStatus.Trashed;
//fixme - deal with variants
var expires = ContentSchedule.GetSchedule(ContentScheduleChange.End).FirstOrDefault();
if (expires != null && expires.Date > DateTime.MinValue && DateTime.Now > expires.Date)
var expires = ContentSchedule.GetSchedule(ContentScheduleChange.End);
if (expires != null && expires.Any(x => x.Date > DateTime.MinValue && DateTime.Now > x.Date))
return ContentStatus.Expired;
//fixme - deal with variants
var release = ContentSchedule.GetSchedule(ContentScheduleChange.Start).FirstOrDefault();
if (release != null && release.Date > DateTime.MinValue && release.Date > DateTime.Now)
var release = ContentSchedule.GetSchedule(ContentScheduleChange.Start);
if (release != null && release.Any(x => x.Date > DateTime.MinValue && x.Date > DateTime.Now))
return ContentStatus.AwaitingRelease;
if(Published)
@@ -508,6 +534,14 @@ namespace Umbraco.Core.Models
clone._publishInfos.CollectionChanged += clone.PublishNamesCollectionChanged; //re-assign correct event handler
}
//if properties exist then deal with event bindings
if (clone._schedule != null)
{
clone._schedule.CollectionChanged -= ScheduleCollectionChanged; //clear this event handler if any
clone._schedule = (ContentScheduleCollection)_schedule.DeepClone(); //manually deep clone
clone._schedule.CollectionChanged += clone.ScheduleCollectionChanged; //re-assign correct event handler
}
//re-enable tracking
clone.EnableChangeTracking();

View File

@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public class ContentSchedule
public class ContentSchedule : IDeepCloneable
{
public ContentSchedule(int id, string culture, DateTime date, ContentScheduleChange change)
{
@@ -45,5 +45,10 @@ namespace Umbraco.Core.Models
/// </summary>
[DataMember]
public ContentScheduleChange Change { get; }
public object DeepClone()
{
return new ContentSchedule(Id, Culture, Date, Change);
}
}
}

View File

@@ -2,14 +2,22 @@
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace Umbraco.Core.Models
{
public class ContentScheduleCollection
public class ContentScheduleCollection : INotifyCollectionChanged, IDeepCloneable
{
//underlying storage for the collection backed by a sorted list so that the schedule is always in order of date
private readonly Dictionary<string, SortedList<DateTime, ContentSchedule>> _schedule = new Dictionary<string, SortedList<DateTime, ContentSchedule>>();
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
CollectionChanged?.Invoke(this, args);
}
/// <summary>
/// Add an existing schedule
/// </summary>
@@ -24,6 +32,8 @@ namespace Umbraco.Core.Models
//TODO: Below will throw if there are duplicate dates added, validate/return bool?
changes.Add(schedule.Date, schedule);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, schedule));
}
/// <summary>
@@ -62,9 +72,20 @@ namespace Umbraco.Core.Models
// but the bool won't indicate which date was in error, maybe have 2 diff methods to schedule start/end?
if (releaseDate.HasValue)
changes.Add(releaseDate.Value, new ContentSchedule(0, culture, releaseDate.Value, ContentScheduleChange.Start));
{
var entry = new ContentSchedule(0, culture, releaseDate.Value, ContentScheduleChange.Start);
changes.Add(releaseDate.Value, entry);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, entry));
}
if (expireDate.HasValue)
changes.Add(expireDate.Value, new ContentSchedule(0, culture, expireDate.Value, ContentScheduleChange.End));
{
var entry = new ContentSchedule(0, culture, expireDate.Value, ContentScheduleChange.End);
changes.Add(expireDate.Value, entry);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, entry));
}
}
@@ -76,7 +97,14 @@ namespace Umbraco.Core.Models
{
if (_schedule.TryGetValue(change.Culture, out var s))
{
s.Remove(change.Date);
var removed = s.Remove(change.Date);
if (removed)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, change));
if (s.Count == 0)
_schedule.Remove(change.Culture);
}
}
}
@@ -99,7 +127,16 @@ namespace Umbraco.Core.Models
if (_schedule.TryGetValue(culture, out var s))
{
foreach (var ofChange in s.Where(x => x.Value.Change == changeType).ToList())
s.Remove(ofChange.Value.Date);
{
var removed = s.Remove(ofChange.Value.Date);
if (removed)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, ofChange.Value));
if (s.Count == 0)
_schedule.Remove(culture);
}
}
}
}
@@ -132,5 +169,18 @@ namespace Umbraco.Core.Models
{
return _schedule.ToDictionary(x => x.Key, x => (IEnumerable<ContentSchedule>)x.Value.Values);
}
public object DeepClone()
{
var clone = new ContentScheduleCollection();
foreach(var cultureSched in _schedule)
{
var list = new SortedList<DateTime, ContentSchedule>();
foreach (var schedEntry in cultureSched.Value)
list.Add(schedEntry.Key, (ContentSchedule)schedEntry.Value.DeepClone());
clone._schedule[cultureSched.Key] = list;
}
return clone;
}
}
}