119 lines
3.4 KiB
C#
119 lines
3.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
|
|
using FluentValidation;
|
|
|
|
using Ical.Net.CalendarComponents;
|
|
using Ical.Net.DataTypes;
|
|
using Ical.Net.Serialization;
|
|
|
|
using MfGames.Gallium;
|
|
using MfGames.Nitride.Contents;
|
|
using MfGames.Nitride.Generators;
|
|
using MfGames.Nitride.Temporal;
|
|
|
|
using NodaTime;
|
|
|
|
using Zio;
|
|
|
|
namespace MfGames.Nitride.Calendar;
|
|
|
|
/// <summary>
|
|
/// Creates an iCalendar file from all the entities passed into the method
|
|
/// that have a NodaTime.Instant component. This will write both past and
|
|
/// future events.
|
|
/// </summary>
|
|
[WithProperties]
|
|
public partial class CreateCalender : OperationBase
|
|
{
|
|
private readonly TimeService clock;
|
|
|
|
private readonly IValidator<CreateCalender> validator;
|
|
|
|
public CreateCalender(
|
|
IValidator<CreateCalender> validator,
|
|
TimeService clock)
|
|
{
|
|
this.validator = validator;
|
|
this.clock = clock;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a callback to get the summary of the event representing
|
|
/// the entity.
|
|
/// </summary>
|
|
public Func<Entity, string>? GetEventSummary { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a callback to get the optional URL of an event for
|
|
/// the entity.
|
|
/// </summary>
|
|
public Func<Entity, Uri?>? GetEventUrl { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the file system path for the resulting calendar.
|
|
/// </summary>
|
|
public UPath? Path { get; set; }
|
|
|
|
/// <inheritdoc />
|
|
public override IEnumerable<Entity> Run(
|
|
IEnumerable<Entity> input,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
this.validator.ValidateAndThrow(this);
|
|
|
|
SplitEntityEnumerations split = input.SplitEntity<Instant>();
|
|
IEnumerable<Entity> datedAndCalendars =
|
|
this.CreateCalendarEntity(split.HasAll);
|
|
|
|
return datedAndCalendars.Union(split.NotHasAll);
|
|
}
|
|
|
|
private IEnumerable<Entity> CreateCalendarEntity(
|
|
IEnumerable<Entity> entities)
|
|
{
|
|
// Create the calendar in the same time zone as the rest of the system.
|
|
var calendar = new Ical.Net.Calendar();
|
|
|
|
calendar.TimeZones.Add(new VTimeZone(this.clock.DateTimeZone.Id));
|
|
|
|
// Go through the events and add all of them.
|
|
var input = entities.ToList();
|
|
IEnumerable<CalendarEvent> events =
|
|
input.Select(this.CreateCalendarEvent);
|
|
|
|
calendar.Events.AddRange(events);
|
|
|
|
// Create the iCalendar file.
|
|
var serializer = new CalendarSerializer();
|
|
string serializedCalendar = serializer.SerializeToString(calendar);
|
|
|
|
// Create the calendar entity and populate everything.
|
|
Entity calendarEntity = new Entity().Set(IsCalendar.Instance)
|
|
.Set(this.Path!.Value)
|
|
.SetTextContent(serializedCalendar);
|
|
|
|
// Return the results along with the new calendar.
|
|
return input.Union(new[] { calendarEntity });
|
|
}
|
|
|
|
private CalendarEvent CreateCalendarEvent(Entity entity)
|
|
{
|
|
Instant instant = entity.Get<Instant>();
|
|
var when = this.clock.ToDateTime(instant);
|
|
string summary = this.GetEventSummary!(entity);
|
|
Uri? url = this.GetEventUrl?.Invoke(entity);
|
|
|
|
var calendarEvent = new CalendarEvent
|
|
{
|
|
Summary = summary,
|
|
Start = new CalDateTime(when),
|
|
Url = url,
|
|
};
|
|
|
|
return calendarEvent;
|
|
}
|
|
}
|