87 lines
3.1 KiB
C#
87 lines
3.1 KiB
C#
using System.Text;
|
|
using System.Globalization;
|
|
|
|
namespace Socialize.Api.Modules.CalendarIntegrations.Services;
|
|
|
|
internal sealed record CalendarExportFeedEvent(
|
|
string Uid,
|
|
string Title,
|
|
DateTimeOffset StartsAt,
|
|
DateTimeOffset EndsAt,
|
|
bool IsAllDay,
|
|
string? Description,
|
|
string? Url);
|
|
|
|
internal static class CalendarExportFeedBuilder
|
|
{
|
|
public static string Build(string calendarName, IReadOnlyCollection<CalendarExportFeedEvent> events)
|
|
{
|
|
StringBuilder builder = new();
|
|
builder.AppendLine("BEGIN:VCALENDAR");
|
|
builder.AppendLine("VERSION:2.0");
|
|
builder.AppendLine("PRODID:-//Socialize//User Work Calendar//EN");
|
|
builder.AppendLine("CALSCALE:GREGORIAN");
|
|
builder.AppendLine("METHOD:PUBLISH");
|
|
AppendLineInvariant(builder, $"X-WR-CALNAME:{EscapeText(calendarName)}");
|
|
|
|
foreach (CalendarExportFeedEvent feedEvent in events.OrderBy(calendarEvent => calendarEvent.StartsAt))
|
|
{
|
|
builder.AppendLine("BEGIN:VEVENT");
|
|
AppendLineInvariant(builder, $"UID:{EscapeText(feedEvent.Uid)}");
|
|
AppendLineInvariant(builder, $"DTSTAMP:{FormatUtc(DateTimeOffset.UtcNow)}");
|
|
AppendLineInvariant(builder, $"SUMMARY:{EscapeText(feedEvent.Title)}");
|
|
|
|
if (feedEvent.IsAllDay)
|
|
{
|
|
AppendLineInvariant(builder, $"DTSTART;VALUE=DATE:{FormatDate(feedEvent.StartsAt)}");
|
|
AppendLineInvariant(builder, $"DTEND;VALUE=DATE:{FormatDate(feedEvent.EndsAt)}");
|
|
}
|
|
else
|
|
{
|
|
AppendLineInvariant(builder, $"DTSTART:{FormatUtc(feedEvent.StartsAt)}");
|
|
AppendLineInvariant(builder, $"DTEND:{FormatUtc(feedEvent.EndsAt)}");
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(feedEvent.Description))
|
|
{
|
|
AppendLineInvariant(builder, $"DESCRIPTION:{EscapeText(feedEvent.Description)}");
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(feedEvent.Url))
|
|
{
|
|
AppendLineInvariant(builder, $"URL:{EscapeText(feedEvent.Url)}");
|
|
}
|
|
|
|
builder.AppendLine("END:VEVENT");
|
|
}
|
|
|
|
builder.AppendLine("END:VCALENDAR");
|
|
return builder.ToString();
|
|
}
|
|
|
|
private static string FormatDate(DateTimeOffset value)
|
|
{
|
|
return value.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
private static string FormatUtc(DateTimeOffset value)
|
|
{
|
|
return value.UtcDateTime.ToString("yyyyMMdd'T'HHmmss'Z'", System.Globalization.CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
private static string EscapeText(string value)
|
|
{
|
|
return value
|
|
.Replace("\\", "\\\\", StringComparison.Ordinal)
|
|
.Replace("\r\n", "\\n", StringComparison.Ordinal)
|
|
.Replace("\n", "\\n", StringComparison.Ordinal)
|
|
.Replace(";", "\\;", StringComparison.Ordinal)
|
|
.Replace(",", "\\,", StringComparison.Ordinal);
|
|
}
|
|
|
|
private static void AppendLineInvariant(StringBuilder builder, FormattableString value)
|
|
{
|
|
builder.AppendLine(value.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
}
|