From c088ab8292eef3ca0ff9bad29082efb8f78d9ebe Mon Sep 17 00:00:00 2001 From: Chris Kaczor Date: Wed, 1 Apr 2026 11:58:51 -0400 Subject: [PATCH] Add another national day source since DOTY is broken --- Calendar/Service/Calendar.http | 10 ++++ .../Controllers/NationalDaysController.cs | 59 ++++++++++++++++--- .../{NationalDays => DaysOfTheYear}/Entry.cs | 2 +- .../{NationalDays => DaysOfTheYear}/Meta.cs | 2 +- .../Response.cs | 4 +- .../Service/Models/HolidayCalendar/Data.cs | 13 ++++ .../Service/Models/HolidayCalendar/Item.cs | 13 ++++ .../Models/HolidayCalendar/Response.cs | 10 ++++ Calendar/Service/Models/NationalDay.cs | 31 ++++++++++ Calendar/Service/appsettings.json | 10 +++- Calendar/Service/deploy/manifest.yaml | 18 ++++-- 11 files changed, 155 insertions(+), 17 deletions(-) rename Calendar/Service/Models/{NationalDays => DaysOfTheYear}/Entry.cs (83%) rename Calendar/Service/Models/{NationalDays => DaysOfTheYear}/Meta.cs (83%) rename Calendar/Service/Models/{NationalDays => DaysOfTheYear}/Response.cs (50%) create mode 100644 Calendar/Service/Models/HolidayCalendar/Data.cs create mode 100644 Calendar/Service/Models/HolidayCalendar/Item.cs create mode 100644 Calendar/Service/Models/HolidayCalendar/Response.cs create mode 100644 Calendar/Service/Models/NationalDay.cs diff --git a/Calendar/Service/Calendar.http b/Calendar/Service/Calendar.http index d04312f..93cd76f 100644 --- a/Calendar/Service/Calendar.http +++ b/Calendar/Service/Calendar.http @@ -39,3 +39,13 @@ GET {{Calendar_HostAddress}}/national-days/today?timezone=America/New_York Accept: application/json ### + +GET {{Calendar_HostAddress}}/national-days/today?timezone=America/New_York&provider=DaysOfTheYear +Accept: application/json + +### + +GET {{Calendar_HostAddress}}/national-days/today?timezone=America/New_York&provider=HolidayCalendar +Accept: application/json + +### \ No newline at end of file diff --git a/Calendar/Service/Controllers/NationalDaysController.cs b/Calendar/Service/Controllers/NationalDaysController.cs index 52a51e4..4a85924 100644 --- a/Calendar/Service/Controllers/NationalDaysController.cs +++ b/Calendar/Service/Controllers/NationalDaysController.cs @@ -1,4 +1,6 @@ -using ChrisKaczor.HomeMonitor.Calendar.Service.Models.NationalDays; +using ChrisKaczor.HomeMonitor.Calendar.Service.Models; +using DaysOfTheYear = ChrisKaczor.HomeMonitor.Calendar.Service.Models.DaysOfTheYear; +using HolidayCalendar = ChrisKaczor.HomeMonitor.Calendar.Service.Models.HolidayCalendar; using Microsoft.AspNetCore.Mvc; using RestSharp; @@ -9,17 +11,58 @@ namespace ChrisKaczor.HomeMonitor.Calendar.Service.Controllers; public class NationalDaysController(IConfiguration configuration, RestClient restClient) : ControllerBase { [HttpGet("today")] - public async Task> GetToday([FromQuery] string timezone = "Etc/UTC") + public async Task>> GetToday([FromQuery] string timezone = "Etc/UTC", [FromQuery] string provider = "") { + if (string.IsNullOrEmpty(provider)) + { + provider = configuration["Calendar:NationalDays:Provider"] ?? string.Empty; + } + var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timezone); - var timeZoneOffset = timeZoneInfo.GetUtcOffset(DateTimeOffset.Now).TotalHours; + var timeZoneOffset = timeZoneInfo.GetUtcOffset(DateTimeOffset.Now); - var restRequest = new RestRequest(configuration["Calendar:NationalDays:Url"]); - restRequest.AddHeader("X-Api-Key", configuration["Calendar:NationalDays:Key"] ?? string.Empty); - restRequest.AddQueryParameter("timezone_offset", timeZoneOffset); + if (provider == "DaysOfTheYear") + { + return Ok(await GetFromDaysOfTheYear(timeZoneOffset)); + } - var response = await restClient.GetAsync(restRequest); + return Ok(await GetFromHolidayCalendar(timeZoneOffset)); + } - return Ok(response?.Data.Where(d => d.Type == "day")); + private async Task?> GetFromDaysOfTheYear(TimeSpan timeZoneOffset) + { + var timeZoneOffsetHours = timeZoneOffset.TotalHours; + + var restRequest = new RestRequest(configuration["Calendar:DaysOfTheYear:Url"]); + restRequest.AddHeader("X-Api-Key", configuration["Calendar:DaysOfTheYear:Key"] ?? string.Empty); + restRequest.AddQueryParameter("timezone_offset", timeZoneOffsetHours); + + var response = await restClient.GetAsync(restRequest); + + var items = response?.Data.Where(d => d.Type == "day"); + + var nationalDays = items?.Select(i => new NationalDay(i)); + + return nationalDays; + } + + private async Task?> GetFromHolidayCalendar(TimeSpan timeZoneOffset) + { + var now = DateTimeOffset.UtcNow.ToOffset(timeZoneOffset); + var dateString = now.ToString("yyyy-MM-dd"); + + var restRequest = new RestRequest(configuration["Calendar:HolidayCalendar:Url"]); + restRequest.AddHeader("Authorization", $"Bearer {configuration["Calendar:HolidayCalendar:Key"] ?? string.Empty}"); + restRequest.AddQueryParameter("limit", 100); + restRequest.AddQueryParameter("country", configuration["Calendar:HolidayCalendar:Country"]); + restRequest.AddQueryParameter("type", "Day"); + restRequest.AddQueryParameter("startDate", dateString); + restRequest.AddQueryParameter("endDate", dateString); + + var response = await restClient.GetAsync(restRequest); + + var nationalDays = response?.Data.Items.Select(i => new NationalDay(i)); + + return nationalDays; } } \ No newline at end of file diff --git a/Calendar/Service/Models/NationalDays/Entry.cs b/Calendar/Service/Models/DaysOfTheYear/Entry.cs similarity index 83% rename from Calendar/Service/Models/NationalDays/Entry.cs rename to Calendar/Service/Models/DaysOfTheYear/Entry.cs index 9b233f6..68e51cb 100644 --- a/Calendar/Service/Models/NationalDays/Entry.cs +++ b/Calendar/Service/Models/DaysOfTheYear/Entry.cs @@ -1,7 +1,7 @@ using JetBrains.Annotations; using System.Text.Json.Serialization; -namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.NationalDays; +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.DaysOfTheYear; [PublicAPI] public class Entry diff --git a/Calendar/Service/Models/NationalDays/Meta.cs b/Calendar/Service/Models/DaysOfTheYear/Meta.cs similarity index 83% rename from Calendar/Service/Models/NationalDays/Meta.cs rename to Calendar/Service/Models/DaysOfTheYear/Meta.cs index 5c4312f..9476cc6 100644 --- a/Calendar/Service/Models/NationalDays/Meta.cs +++ b/Calendar/Service/Models/DaysOfTheYear/Meta.cs @@ -1,7 +1,7 @@ using JetBrains.Annotations; using System.Text.Json.Serialization; -namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.NationalDays; +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.DaysOfTheYear; [PublicAPI] public class Meta diff --git a/Calendar/Service/Models/NationalDays/Response.cs b/Calendar/Service/Models/DaysOfTheYear/Response.cs similarity index 50% rename from Calendar/Service/Models/NationalDays/Response.cs rename to Calendar/Service/Models/DaysOfTheYear/Response.cs index e1db250..ad47f33 100644 --- a/Calendar/Service/Models/NationalDays/Response.cs +++ b/Calendar/Service/Models/DaysOfTheYear/Response.cs @@ -1,11 +1,11 @@ using JetBrains.Annotations; -namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.NationalDays; +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.DaysOfTheYear; [PublicAPI] public class Response { public int Code { get; set; } public Meta Meta { get; set; } = new(); - public IEnumerable Data { get; set; } = Array.Empty(); + public IEnumerable Data { get; set; } = []; } \ No newline at end of file diff --git a/Calendar/Service/Models/HolidayCalendar/Data.cs b/Calendar/Service/Models/HolidayCalendar/Data.cs new file mode 100644 index 0000000..ec9728b --- /dev/null +++ b/Calendar/Service/Models/HolidayCalendar/Data.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; + +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.HolidayCalendar; + +[PublicAPI] +public class Data +{ + public IEnumerable Items { get; set; } = []; + public int Total { get; set; } + public int Page { get; set; } + public int Limit { get; set; } + public int TotalPages { get; set; } +} \ No newline at end of file diff --git a/Calendar/Service/Models/HolidayCalendar/Item.cs b/Calendar/Service/Models/HolidayCalendar/Item.cs new file mode 100644 index 0000000..62b5ca7 --- /dev/null +++ b/Calendar/Service/Models/HolidayCalendar/Item.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; + +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.HolidayCalendar; + +[PublicAPI] +public class Item +{ + public required string Id { get; set; } + public required string Name { get; set; } + public required string Excerpt { get; set; } + public required string Url { get; set; } + public required string Type { get; set; } +} \ No newline at end of file diff --git a/Calendar/Service/Models/HolidayCalendar/Response.cs b/Calendar/Service/Models/HolidayCalendar/Response.cs new file mode 100644 index 0000000..2facdc9 --- /dev/null +++ b/Calendar/Service/Models/HolidayCalendar/Response.cs @@ -0,0 +1,10 @@ +using JetBrains.Annotations; + +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models.HolidayCalendar; + +[PublicAPI] +public class Response +{ + public bool Success { get; set; } + public Data Data { get; set; } = new(); +} \ No newline at end of file diff --git a/Calendar/Service/Models/NationalDay.cs b/Calendar/Service/Models/NationalDay.cs new file mode 100644 index 0000000..3d5f065 --- /dev/null +++ b/Calendar/Service/Models/NationalDay.cs @@ -0,0 +1,31 @@ +using JetBrains.Annotations; +using System.Diagnostics.CodeAnalysis; + +namespace ChrisKaczor.HomeMonitor.Calendar.Service.Models; + +[PublicAPI] +public class NationalDay +{ + public required string Name { get; set; } + public required string Url { get; set; } + public required string Excerpt { get; set; } + public required string Type { get; set; } + + [SetsRequiredMembers] + public NationalDay(HolidayCalendar.Item item) + { + Name = item.Name; + Url = item.Url; + Excerpt = item.Excerpt; + Type = item.Type; + } + + [SetsRequiredMembers] + public NationalDay(DaysOfTheYear.Entry entry) + { + Name = entry.Name; + Url = entry.Url; + Excerpt = entry.Excerpt; + Type = entry.Type; + } +} \ No newline at end of file diff --git a/Calendar/Service/appsettings.json b/Calendar/Service/appsettings.json index 0d35321..fec28cb 100644 --- a/Calendar/Service/appsettings.json +++ b/Calendar/Service/appsettings.json @@ -12,9 +12,17 @@ "Calendar": { "PersonalUrl": "", "HolidayUrl": "", - "NationalDays": { + "DaysOfTheYear": { "Url": "", "Key": "" + }, + "HolidayCalendar": { + "Url": "", + "Key": "", + "Country": "recYxvMVBeTBnsPrJ" + }, + "NationalDays": { + "Provider": "HolidayCalendar" } } } diff --git a/Calendar/Service/deploy/manifest.yaml b/Calendar/Service/deploy/manifest.yaml index c42259d..5e01925 100644 --- a/Calendar/Service/deploy/manifest.yaml +++ b/Calendar/Service/deploy/manifest.yaml @@ -35,16 +35,26 @@ spec: secretKeyRef: name: calendar-config key: HOLIDAYS_URL - - name: Calendar__NationalDays__Url + - name: Calendar__DaysOfTheYear__Url valueFrom: secretKeyRef: name: calendar-config - key: NATIONAL_DAYS_URL - - name: Calendar__NationalDays__Key + key: DAYS_OF_THE_YEAR_URL + - name: Calendar__DaysOfTheYear__Key valueFrom: secretKeyRef: name: calendar-config - key: NATIONAL_DAYS_KEY + key: DAYS_OF_THE_YEAR_KEY + - name: Calendar__HolidayCalendar__Url + valueFrom: + secretKeyRef: + name: calendar-config + key: HOLIDAY_CALENDAR_URL + - name: Calendar__HolidayCalendar__Key + valueFrom: + secretKeyRef: + name: calendar-config + key: HOLIDAY_CALENDAR_KEY restartPolicy: Always terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst