From af0d59d78524127f6cc76e43a7e397da01788d97 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Sun, 12 Jul 2026 07:18:01 +0000 Subject: fix(calendar): split comma-joined GOOGLE_CALENDAR_ID before use fetchCalendarEvents falls back to config.GoogleCalendarID whenever no source_configs rows exist yet for the gcal source -- which is the current live state (0 rows). GoogleCalendarID is a single env var that itself holds a comma-separated list of calendar IDs, but the whole joined string was being wrapped in a single-element []string{...} and passed straight to SetCalendarIDs. Google's API takes one calendarId per call, so every fetch failed with '404 Not Found' on the literal comma-joined string -- confirmed live in production logs. This broke all calendar events, in both the web dashboard and the widget, silently. Now splits on commas and trims whitespace before use. --- internal/handlers/handlers.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'internal/handlers/handlers.go') diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index d1a7512..0d8b2da 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -314,9 +314,20 @@ func (h *Handler) fetchCalendarEvents(ctx context.Context, forceRefresh bool) ([ } if len(enabledIDs) == 0 { - // No source_configs synced yet — fall back to the configured calendar ID + // No source_configs synced yet — fall back to the configured calendar + // ID(s). GoogleCalendarID is a single env var that itself holds a + // comma-separated list (see GOOGLE_CALENDAR_ID in .env) -- it must be + // split before use. Passing the raw joined string straight through + // as a single calendar ID (the previous behavior) sends Google's API + // a calendarId that matches nothing, failing every fetch with a 404 — + // this is a real production incident, not a hypothetical: it silently + // broke all calendar events (web and widget both) until fixed. if len(configs) == 0 && h.config.GoogleCalendarID != "" { - enabledIDs = []string{h.config.GoogleCalendarID} + for _, id := range strings.Split(h.config.GoogleCalendarID, ",") { + if trimmed := strings.TrimSpace(id); trimmed != "" { + enabledIDs = append(enabledIDs, trimmed) + } + } } else { // Configs exist but all disabled — respect that return nil, nil @@ -326,10 +337,12 @@ func (h *Handler) fetchCalendarEvents(ctx context.Context, forceRefresh bool) ([ h.googleCalendarClient.SetCalendarIDs(enabledIDs) fetcher := &CacheFetcher[models.CalendarEvent]{ - Store: h.store, - CacheKey: store.CacheKeyGoogleCalendar, - TTLMinutes: h.config.CacheTTLMinutes, - Fetch: func(ctx context.Context) ([]models.CalendarEvent, error) { return h.googleCalendarClient.GetUpcomingEvents(ctx, 50) }, + Store: h.store, + CacheKey: store.CacheKeyGoogleCalendar, + TTLMinutes: h.config.CacheTTLMinutes, + Fetch: func(ctx context.Context) ([]models.CalendarEvent, error) { + return h.googleCalendarClient.GetUpcomingEvents(ctx, 50) + }, GetFromCache: h.store.GetCalendarEvents, SaveToCache: h.store.SaveCalendarEvents, } -- cgit v1.2.3