using System.Text; namespace Socialize.Api.Modules.CalendarIntegrations.Services; public sealed record CalendarExportFeedEvent( string Uid, string Title, DateTimeOffset StartsAt, DateTimeOffset EndsAt, bool IsAllDay, string? Description, string? Url); public class CalendarExportFeedBuilder { public string Build(string calendarName, IReadOnlyCollection 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"); builder.AppendLine($"X-WR-CALNAME:{EscapeText(calendarName)}"); foreach (CalendarExportFeedEvent feedEvent in events.OrderBy(calendarEvent => calendarEvent.StartsAt)) { builder.AppendLine("BEGIN:VEVENT"); builder.AppendLine($"UID:{EscapeText(feedEvent.Uid)}"); builder.AppendLine($"DTSTAMP:{FormatUtc(DateTimeOffset.UtcNow)}"); builder.AppendLine($"SUMMARY:{EscapeText(feedEvent.Title)}"); if (feedEvent.IsAllDay) { builder.AppendLine($"DTSTART;VALUE=DATE:{FormatDate(feedEvent.StartsAt)}"); builder.AppendLine($"DTEND;VALUE=DATE:{FormatDate(feedEvent.EndsAt)}"); } else { builder.AppendLine($"DTSTART:{FormatUtc(feedEvent.StartsAt)}"); builder.AppendLine($"DTEND:{FormatUtc(feedEvent.EndsAt)}"); } if (!string.IsNullOrWhiteSpace(feedEvent.Description)) { builder.AppendLine($"DESCRIPTION:{EscapeText(feedEvent.Description)}"); } if (!string.IsNullOrWhiteSpace(feedEvent.Url)) { builder.AppendLine($"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("\\", "\\\\") .Replace("\r\n", "\\n") .Replace("\n", "\\n") .Replace(";", "\\;") .Replace(",", "\\,"); } }