Browse Source

rework active date range; add tests (#1664)

pull/1666/head
Jason Dove 2 years ago committed by GitHub
parent
commit
e5f15df196
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 7
      ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplate.cs
  3. 14
      ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplateItemsHandler.cs
  4. 7
      ErsatzTV.Application/Scheduling/Mapper.cs
  5. 7
      ErsatzTV.Application/Scheduling/PlayoutTemplateViewModel.cs
  6. 411
      ErsatzTV.Core.Tests/Scheduling/PlayoutTemplateSelectorTests.cs
  7. 10
      ErsatzTV.Core/Domain/Scheduling/PlayoutTemplate.cs
  8. 48
      ErsatzTV.Core/Scheduling/PlayoutTemplateSelector.cs
  9. 5318
      ErsatzTV.Infrastructure.MySql/Migrations/20240403180938_Rework_PlayoutTemplate_ActiveDateRange.Designer.cs
  10. 94
      ErsatzTV.Infrastructure.MySql/Migrations/20240403180938_Rework_PlayoutTemplate_ActiveDateRange.cs
  11. 17
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  12. 5173
      ErsatzTV.Infrastructure.Sqlite/Migrations/20240403170331_Rework_PlayoutTemplate_ActiveDateRange.Designer.cs
  13. 94
      ErsatzTV.Infrastructure.Sqlite/Migrations/20240403170331_Rework_PlayoutTemplate_ActiveDateRange.cs
  14. 17
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  15. 52
      ErsatzTV/Pages/PlayoutTemplatesEditor.razor
  16. 5
      ErsatzTV/Services/SearchIndexService.cs
  17. 99
      ErsatzTV/ViewModels/PlayoutTemplateEditViewModel.cs

2
CHANGELOG.md

@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -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
ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplate.cs

@ -7,5 +7,8 @@ public record ReplacePlayoutTemplate( @@ -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);

14
ErsatzTV.Application/Scheduling/Commands/ReplacePlayoutTemplateItemsHandler.cs

@ -55,8 +55,11 @@ public class ReplacePlayoutTemplateItemsHandler( @@ -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( @@ -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;
}
}

7
ErsatzTV.Application/Scheduling/Mapper.cs

@ -54,8 +54,11 @@ internal static class Mapper @@ -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
ErsatzTV.Application/Scheduling/PlayoutTemplateViewModel.cs

@ -7,5 +7,8 @@ public record PlayoutTemplateViewModel( @@ -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);

411
ErsatzTV.Core.Tests/Scheduling/PlayoutTemplateSelectorTests.cs

@ -0,0 +1,411 @@ @@ -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();
}
}
}

10
ErsatzTV.Core/Domain/Scheduling/PlayoutTemplate.cs

@ -11,11 +11,13 @@ public class PlayoutTemplate @@ -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() =>
[

48
ErsatzTV.Core/Scheduling/PlayoutTemplateSelector.cs

@ -10,9 +10,53 @@ public static class PlayoutTemplateSelector @@ -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
ErsatzTV.Infrastructure.MySql/Migrations/20240403180938_Rework_PlayoutTemplate_ActiveDateRange.Designer.cs generated

File diff suppressed because it is too large Load Diff

94
ErsatzTV.Infrastructure.MySql/Migrations/20240403180938_Rework_PlayoutTemplate_ActiveDateRange.cs

@ -0,0 +1,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);
}
}
}

17
ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs

@ -2187,20 +2187,29 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -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
ErsatzTV.Infrastructure.Sqlite/Migrations/20240403170331_Rework_PlayoutTemplate_ActiveDateRange.Designer.cs generated

File diff suppressed because it is too large Load Diff

94
ErsatzTV.Infrastructure.Sqlite/Migrations/20240403170331_Rework_PlayoutTemplate_ActiveDateRange.cs

@ -0,0 +1,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);
}
}
}

17
ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs

@ -2076,20 +2076,29 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -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");

52
ErsatzTV/Pages/PlayoutTemplatesEditor.razor

@ -115,7 +115,42 @@ @@ -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 @@ @@ -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 @@ @@ -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);

5
ErsatzTV/Services/SearchIndexService.cs

@ -2,6 +2,7 @@ using System.Threading.Channels; @@ -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 @@ -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 @@ -26,6 +30,7 @@ public class SearchIndexService : BackgroundService
{
await Task.Yield();
await _systemStartup.WaitForDatabase(stoppingToken);
try
{
_logger.LogInformation("Search index worker service started");

99
ErsatzTV/ViewModels/PlayoutTemplateEditViewModel.cs

@ -1,10 +1,15 @@ @@ -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 @@ -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));
}
get => _startMonth == 0 ? 1 : _startMonth;
set => _startMonth = value;
}
return new DateRange(StartDate.Value.LocalDateTime, EndDate.Value.LocalDateTime);
}
public int StartDay
{
get => _startDay == 0 ? 1 : _startDay;
set => _startDay = value;
}
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);
}
}
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) =>
(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 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;
}
}

Loading…
Cancel
Save