rework active date range; add tests (#1664)
This commit is contained in:
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Add `Active Date Range` to block playout template editor to allow limiting templates to a specific date range
|
||||
- This is year-agnostic, meaning the Month/Day range will apply to every year
|
||||
- This also supports wrapping the end of the year (e.g., start 12/1 and end 1/15)
|
||||
|
||||
## [0.8.6-beta] - 2024-04-03
|
||||
### Added
|
||||
|
||||
@@ -7,5 +7,8 @@ public record ReplacePlayoutTemplate(
|
||||
List<DayOfWeek> DaysOfWeek,
|
||||
List<int> DaysOfMonth,
|
||||
List<int> MonthsOfYear,
|
||||
DateTimeOffset? StartDate,
|
||||
DateTimeOffset? EndDate);
|
||||
bool LimitToDateRange,
|
||||
int StartMonth,
|
||||
int StartDay,
|
||||
int EndMonth,
|
||||
int EndDay);
|
||||
|
||||
@@ -55,8 +55,11 @@ public class ReplacePlayoutTemplateItemsHandler(
|
||||
DaysOfWeek = add.DaysOfWeek,
|
||||
DaysOfMonth = add.DaysOfMonth,
|
||||
MonthsOfYear = add.MonthsOfYear,
|
||||
StartDate = add.StartDate,
|
||||
EndDate = add.EndDate,
|
||||
LimitToDateRange = add.LimitToDateRange,
|
||||
StartMonth = add.StartMonth,
|
||||
StartDay = add.StartDay,
|
||||
EndMonth = add.EndMonth,
|
||||
EndDay = add.EndDay,
|
||||
DateUpdated = now
|
||||
});
|
||||
}
|
||||
@@ -70,8 +73,11 @@ public class ReplacePlayoutTemplateItemsHandler(
|
||||
ex.DaysOfWeek = update.DaysOfWeek;
|
||||
ex.DaysOfMonth = update.DaysOfMonth;
|
||||
ex.MonthsOfYear = update.MonthsOfYear;
|
||||
ex.StartDate = update.StartDate;
|
||||
ex.EndDate = update.EndDate;
|
||||
ex.LimitToDateRange = update.LimitToDateRange;
|
||||
ex.StartMonth = update.StartMonth;
|
||||
ex.StartDay = update.StartDay;
|
||||
ex.EndMonth = update.EndMonth;
|
||||
ex.EndDay = update.EndDay;
|
||||
ex.DateUpdated = now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,11 @@ internal static class Mapper
|
||||
playoutTemplate.DaysOfWeek,
|
||||
playoutTemplate.DaysOfMonth,
|
||||
playoutTemplate.MonthsOfYear,
|
||||
playoutTemplate.StartDate,
|
||||
playoutTemplate.EndDate);
|
||||
playoutTemplate.LimitToDateRange,
|
||||
playoutTemplate.StartMonth,
|
||||
playoutTemplate.StartDay,
|
||||
playoutTemplate.EndMonth,
|
||||
playoutTemplate.EndDay);
|
||||
|
||||
internal static PlayoutItemPreviewViewModel ProjectToViewModel(PlayoutItem playoutItem) =>
|
||||
new(
|
||||
|
||||
@@ -7,5 +7,8 @@ public record PlayoutTemplateViewModel(
|
||||
ICollection<DayOfWeek> DaysOfWeek,
|
||||
ICollection<int> DaysOfMonth,
|
||||
ICollection<int> MonthsOfYear,
|
||||
DateTimeOffset? StartDate,
|
||||
DateTimeOffset? EndDate);
|
||||
bool LimitToDateRange,
|
||||
int StartMonth,
|
||||
int StartDay,
|
||||
int EndMonth,
|
||||
int EndDay);
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
using ErsatzTV.Core.Domain.Scheduling;
|
||||
using ErsatzTV.Core.Scheduling;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ErsatzTV.Core.Tests.Scheduling;
|
||||
|
||||
public static class PlayoutTemplateSelectorTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class GetPlayoutTemplateFor
|
||||
{
|
||||
private static readonly TimeSpan Offset = TimeSpan.FromHours(-5);
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Before_Start_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 4,
|
||||
StartDay = 1,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 3, 31, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_On_Start_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 4,
|
||||
StartDay = 1,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 4, 1, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_In_Range_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 4,
|
||||
StartDay = 1,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 4, 20, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_On_End_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 4,
|
||||
StartDay = 1,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 6, 15, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_After_End_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 4,
|
||||
StartDay = 1,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 6, 16, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Before_Invalid_Start_Date_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 2,
|
||||
StartDay = 29,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 2, 28, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_After_Invalid_Start_Date_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 2,
|
||||
StartDay = 29,
|
||||
EndMonth = 6,
|
||||
EndDay = 15
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 3, 1, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Before_Invalid_End_Date_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 1,
|
||||
StartDay = 1,
|
||||
EndMonth = 2,
|
||||
EndDay = 29
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 2, 28, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_After_Invalid_End_Date_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 1,
|
||||
StartDay = 1,
|
||||
EndMonth = 2,
|
||||
EndDay = 29
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 3, 1, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_Before_Start_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 6,
|
||||
StartDay = 15,
|
||||
EndMonth = 4,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 6, 14, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_On_Start_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 6,
|
||||
StartDay = 15,
|
||||
EndMonth = 4,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 6, 15, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_In_Range_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 6,
|
||||
StartDay = 15,
|
||||
EndMonth = 4,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 7, 20, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_On_End_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 6,
|
||||
StartDay = 15,
|
||||
EndMonth = 4,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 4, 1, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_After_End_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 6,
|
||||
StartDay = 15,
|
||||
EndMonth = 4,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2024, 4, 2, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_Before_Invalid_Start_Date_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 2,
|
||||
StartDay = 29,
|
||||
EndMonth = 1,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 2, 28, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_After_Invalid_Start_Date_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 2,
|
||||
StartDay = 29,
|
||||
EndMonth = 1,
|
||||
EndDay = 1
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 3, 1, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_Before_Invalid_End_Date_Should_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 5,
|
||||
StartDay = 1,
|
||||
EndMonth = 2,
|
||||
EndDay = 29
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 2, 28, 0, 0, 0, Offset));
|
||||
|
||||
result.IsSome.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LimitToDateRange_Wrap_Around_After_Invalid_End_Date_Should_Not_Return_Template()
|
||||
{
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = PlayoutTemplate.AllDaysOfWeek(),
|
||||
DaysOfMonth = PlayoutTemplate.AllDaysOfMonth(),
|
||||
MonthsOfYear = PlayoutTemplate.AllMonthsOfYear(),
|
||||
LimitToDateRange = true,
|
||||
StartMonth = 5,
|
||||
StartDay = 1,
|
||||
EndMonth = 2,
|
||||
EndDay = 29
|
||||
};
|
||||
|
||||
Option<PlayoutTemplate> result = PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new List<PlayoutTemplate> { template },
|
||||
new DateTimeOffset(2023, 3, 1, 0, 0, 0, Offset));
|
||||
|
||||
result.IsNone.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,13 @@ public class PlayoutTemplate
|
||||
public ICollection<DayOfWeek> DaysOfWeek { get; set; }
|
||||
public ICollection<int> DaysOfMonth { get; set; }
|
||||
public ICollection<int> MonthsOfYear { get; set; }
|
||||
public DateTimeOffset? StartDate { get; set; }
|
||||
public DateTimeOffset? EndDate { get; set; }
|
||||
public bool LimitToDateRange { get; set; }
|
||||
public int StartMonth { get; set; }
|
||||
public int StartDay { get; set; }
|
||||
public int EndMonth { get; set; }
|
||||
public int EndDay { get; set; }
|
||||
public DateTime DateUpdated { get; set; }
|
||||
|
||||
// TODO: ICollection<DateTimeOffset> AdditionalDays { get; set; }
|
||||
//public ICollection<DateTimeOffset> AdditionalDays { get; set; }
|
||||
|
||||
public static List<DayOfWeek> AllDaysOfWeek() =>
|
||||
[
|
||||
|
||||
@@ -10,9 +10,53 @@ public static class PlayoutTemplateSelector
|
||||
{
|
||||
foreach (PlayoutTemplate template in templates.OrderBy(x => x.Index))
|
||||
{
|
||||
if (template.StartDate.HasValue && template.EndDate.HasValue)
|
||||
if (template.LimitToDateRange)
|
||||
{
|
||||
if (date.Date < template.StartDate.Value.Date || date.Date > template.EndDate.Value.Date)
|
||||
bool reverse = template.StartMonth * 100 + template.StartDay >
|
||||
template.EndMonth * 100 + template.EndDay;
|
||||
|
||||
int year = date.LocalDateTime.Year;
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
|
||||
try
|
||||
{
|
||||
start = new DateTime(year, template.StartMonth, template.StartDay, 0, 0, 0, DateTimeKind.Local);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
// this should only happen with days that are greater than the actual days in the month,
|
||||
// so roll over to the 1st of the next month
|
||||
start = new DateTime(year, template.StartMonth + 1, 1, 0, 0, 0, DateTimeKind.Local);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
end = new DateTime(year, template.EndMonth, template.EndDay, 0, 0, 0, DateTimeKind.Local);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
// this should only happen with days that are greater than the actual days in the month,
|
||||
// so reduce to the max days in the month
|
||||
end = new DateTime(
|
||||
year,
|
||||
template.EndMonth,
|
||||
DateTime.DaysInMonth(year, template.EndMonth),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
DateTimeKind.Local);
|
||||
}
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
(start, end) = (end, start);
|
||||
if (date.Date > start.Date && date.Date < end.Date)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (date.Date < start.Date || date.Date > end.Date)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
+5318
File diff suppressed because it is too large
Load Diff
+94
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ErsatzTV.Infrastructure.MySql.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Rework_PlayoutTemplate_ActiveDateRange : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EndDate",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StartDate",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "EndDay",
|
||||
table: "PlayoutTemplate",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "EndMonth",
|
||||
table: "PlayoutTemplate",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "LimitToDateRange",
|
||||
table: "PlayoutTemplate",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "StartDay",
|
||||
table: "PlayoutTemplate",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "StartMonth",
|
||||
table: "PlayoutTemplate",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EndDay",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EndMonth",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LimitToDateRange",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StartDay",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StartMonth",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||
name: "EndDate",
|
||||
table: "PlayoutTemplate",
|
||||
type: "datetime(6)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||
name: "StartDate",
|
||||
table: "PlayoutTemplate",
|
||||
type: "datetime(6)",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2187,20 +2187,29 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
||||
b.Property<string>("DaysOfWeek")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTimeOffset?>("EndDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
b.Property<int>("EndDay")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("EndMonth")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Index")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("LimitToDateRange")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("MonthsOfYear")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("PlayoutId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTimeOffset?>("StartDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
b.Property<int>("StartDay")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StartMonth")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TemplateId")
|
||||
.HasColumnType("int");
|
||||
|
||||
+5173
File diff suppressed because it is too large
Load Diff
+94
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Rework_PlayoutTemplate_ActiveDateRange : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EndDate",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StartDate",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "EndDay",
|
||||
table: "PlayoutTemplate",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "EndMonth",
|
||||
table: "PlayoutTemplate",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "LimitToDateRange",
|
||||
table: "PlayoutTemplate",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "StartDay",
|
||||
table: "PlayoutTemplate",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "StartMonth",
|
||||
table: "PlayoutTemplate",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EndDay",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EndMonth",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LimitToDateRange",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StartDay",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StartMonth",
|
||||
table: "PlayoutTemplate");
|
||||
|
||||
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||
name: "EndDate",
|
||||
table: "PlayoutTemplate",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||
name: "StartDate",
|
||||
table: "PlayoutTemplate",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2076,20 +2076,29 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||
b.Property<string>("DaysOfWeek")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("EndDate")
|
||||
.HasColumnType("TEXT");
|
||||
b.Property<int>("EndDay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("EndMonth")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Index")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("LimitToDateRange")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("MonthsOfYear")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("PlayoutId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTimeOffset?>("StartDate")
|
||||
.HasColumnType("TEXT");
|
||||
b.Property<int>("StartDay")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("StartMonth")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("TemplateId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -115,7 +115,42 @@
|
||||
@bind-Value="_selectedItem.LimitToDateRange" />
|
||||
@if (_selectedItem.LimitToDateRange)
|
||||
{
|
||||
<MudDateRangePicker Class="mt-2" Label="Active Date Range" @bind-DateRange="_selectedItem.ActiveDateRange"/>
|
||||
<MudGrid Class="mt-2" Style="align-items: start" Justify="Justify.Center">
|
||||
<MudItem xs="6">
|
||||
<MudSelect T="int" @bind-Value="_selectedItem.StartMonth" Label="Start Month">
|
||||
@foreach (int month in Enumerable.Range(1, 12))
|
||||
{
|
||||
<MudSelectItem Value="@month">@_dtf.GetMonthName(month)</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudSelect T="int" @bind-Value="_selectedItem.StartDay" Label="Start Day">
|
||||
@foreach (int day in Enumerable.Range(1, 31))
|
||||
{
|
||||
<MudSelectItem Value="@day">@day.ToString()</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudGrid Class="mt-2" Style="align-items: start" Justify="Justify.Center">
|
||||
<MudItem xs="6">
|
||||
<MudSelect T="int" @bind-Value="_selectedItem.EndMonth" Label="End Month">
|
||||
@foreach (int month in Enumerable.Range(1, 12))
|
||||
{
|
||||
<MudSelectItem Value="@month">@_dtf.GetMonthName(month)</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudSelect T="int" @bind-Value="_selectedItem.EndDay" Label="End Day">
|
||||
@foreach (int day in Enumerable.Range(1, 31))
|
||||
{
|
||||
<MudSelectItem Value="@day">@day.ToString()</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
@@ -288,9 +323,11 @@
|
||||
DaysOfWeek = item.DaysOfWeek.ToList(),
|
||||
DaysOfMonth = item.DaysOfMonth.ToList(),
|
||||
MonthsOfYear = item.MonthsOfYear.ToList(),
|
||||
StartDate = item.StartDate,
|
||||
EndDate = item.EndDate,
|
||||
LimitToDateRange = item.StartDate.HasValue && item.EndDate.HasValue
|
||||
LimitToDateRange = item.LimitToDateRange,
|
||||
StartMonth = item.StartMonth,
|
||||
StartDay = item.StartDay,
|
||||
EndMonth = item.EndMonth,
|
||||
EndDay = item.EndDay
|
||||
};
|
||||
|
||||
private async Task UpdateTemplateGroupItems(TemplateGroupViewModel templateGroup)
|
||||
@@ -452,8 +489,11 @@
|
||||
item.DaysOfWeek,
|
||||
item.DaysOfMonth,
|
||||
item.MonthsOfYear,
|
||||
item.LimitToDateRange ? item.StartDate : null,
|
||||
item.LimitToDateRange ? item.EndDate : null)).ToList();
|
||||
item.LimitToDateRange,
|
||||
item.StartMonth,
|
||||
item.StartDay,
|
||||
item.EndMonth,
|
||||
item.EndDay)).ToList();
|
||||
|
||||
Option<BaseError> maybeError = await Mediator.Send(new ReplacePlayoutTemplateItems(Id, items), _cts.Token);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Threading.Channels;
|
||||
using Bugsnag;
|
||||
using ErsatzTV.Application;
|
||||
using ErsatzTV.Application.Search;
|
||||
using ErsatzTV.Core;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Services;
|
||||
@@ -11,14 +12,17 @@ public class SearchIndexService : BackgroundService
|
||||
private readonly ChannelReader<ISearchIndexBackgroundServiceRequest> _channel;
|
||||
private readonly ILogger<SearchIndexService> _logger;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly SystemStartup _systemStartup;
|
||||
|
||||
public SearchIndexService(
|
||||
ChannelReader<ISearchIndexBackgroundServiceRequest> channel,
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
SystemStartup systemStartup,
|
||||
ILogger<SearchIndexService> logger)
|
||||
{
|
||||
_channel = channel;
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_systemStartup = systemStartup;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -26,6 +30,7 @@ public class SearchIndexService : BackgroundService
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
await _systemStartup.WaitForDatabase(stoppingToken);
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Search index worker service started");
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
using ErsatzTV.Application.Scheduling;
|
||||
using MudBlazor;
|
||||
using ErsatzTV.Core.Domain.Scheduling;
|
||||
using ErsatzTV.Core.Scheduling;
|
||||
|
||||
namespace ErsatzTV.ViewModels;
|
||||
|
||||
public class PlayoutTemplateEditViewModel
|
||||
{
|
||||
private int _startMonth;
|
||||
private int _startDay;
|
||||
private int _endMonth;
|
||||
private int _endDay;
|
||||
public int Id { get; set; }
|
||||
public int Index { get; set; }
|
||||
public TemplateViewModel Template { get; set; }
|
||||
@@ -12,48 +17,62 @@ public class PlayoutTemplateEditViewModel
|
||||
public List<int> DaysOfMonth { get; set; }
|
||||
public List<int> MonthsOfYear { get; set; }
|
||||
public bool LimitToDateRange { get; set; }
|
||||
public DateTimeOffset? StartDate { get; set; }
|
||||
public DateTimeOffset? EndDate { get; set; }
|
||||
public DateRange ActiveDateRange
|
||||
|
||||
public int StartMonth
|
||||
{
|
||||
get
|
||||
{
|
||||
if (StartDate is null || EndDate is null || StartDate.Value.Year < 2000 || EndDate.Value.Year < 2000)
|
||||
{
|
||||
return new DateRange(
|
||||
DateTime.Today,
|
||||
new DateTime(3000, 1, 1, 0, 0, 0, DateTimeKind.Local));
|
||||
}
|
||||
|
||||
return new DateRange(StartDate.Value.LocalDateTime, EndDate.Value.LocalDateTime);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
StartDate = null;
|
||||
if (value?.Start is not null)
|
||||
{
|
||||
DateTime start = value.Start.Value;
|
||||
TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(
|
||||
new DateTime(start.Year, start.Month, start.Day, 0, 0, 0, DateTimeKind.Local));
|
||||
StartDate = new DateTimeOffset(start.Year, start.Month, start.Day, 0, 0, 0, offset);
|
||||
}
|
||||
|
||||
EndDate = null;
|
||||
if (value?.End is not null)
|
||||
{
|
||||
DateTime end = value.End.Value;
|
||||
TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(
|
||||
new DateTime(end.Year, end.Month, end.Day, 0, 0, 0, DateTimeKind.Local));
|
||||
EndDate = new DateTimeOffset(end.Year, end.Month, end.Day, 0, 0, 0, offset);
|
||||
}
|
||||
}
|
||||
get => _startMonth == 0 ? 1 : _startMonth;
|
||||
set => _startMonth = value;
|
||||
}
|
||||
|
||||
public bool AppliesToDate(DateTime date) =>
|
||||
(LimitToDateRange is false || StartDate is null || date.Date >= StartDate.Value.Date) &&
|
||||
(LimitToDateRange is false || EndDate is null || date.Date <= EndDate.Value.Date) &&
|
||||
DaysOfWeek.Contains(date.DayOfWeek) &&
|
||||
DaysOfMonth.Contains(date.Day) &&
|
||||
MonthsOfYear.Contains(date.Month);
|
||||
public int StartDay
|
||||
{
|
||||
get => _startDay == 0 ? 1 : _startDay;
|
||||
set => _startDay = value;
|
||||
}
|
||||
|
||||
public int EndMonth
|
||||
{
|
||||
get => _endMonth == 0 ? 12 : _endMonth;
|
||||
set => _endMonth = value;
|
||||
}
|
||||
|
||||
public int EndDay
|
||||
{
|
||||
get => _endDay == 0 ? 31 : _endDay;
|
||||
set => _endDay = value;
|
||||
}
|
||||
|
||||
public bool AppliesToDate(DateTime date)
|
||||
{
|
||||
// share the PlayoutTemplateSelector logic
|
||||
|
||||
var template = new PlayoutTemplate
|
||||
{
|
||||
DaysOfWeek = DaysOfWeek,
|
||||
DaysOfMonth = DaysOfMonth,
|
||||
MonthsOfYear = MonthsOfYear,
|
||||
LimitToDateRange = LimitToDateRange,
|
||||
StartMonth = StartMonth,
|
||||
StartDay = StartDay,
|
||||
EndMonth = EndMonth,
|
||||
EndDay = EndDay,
|
||||
};
|
||||
|
||||
TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(
|
||||
new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Local));
|
||||
|
||||
Option<PlayoutTemplate> result =
|
||||
PlayoutTemplateSelector.GetPlayoutTemplateFor(
|
||||
new[] { template },
|
||||
new DateTimeOffset(
|
||||
date.Year,
|
||||
date.Month,
|
||||
date.Day,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
offset));
|
||||
|
||||
return result.IsSome;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user