summaryrefslogtreecommitdiff
path: root/internal/api
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-25 20:04:03 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-25 20:04:03 -1000
commitfa95c71494458070b78270e3d9170076028fc974 (patch)
tree5cb06c5e6962c9d46ee0e0dad106ff6cbf097730 /internal/api
parent15ac2c98b554e43d287c136b3223d30b0af72b06 (diff)
Refactor: extract helpers and clean up hardcoded HTML
- Extract parseEventTime() and deduplicateEvents() in google_calendar.go - Add scanTask() and scanTasks() SQL helpers in sqlite.go - Move completed-atom HTML to partial template - Add loadTestTemplates() test helper for template-dependent tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/api')
-rw-r--r--internal/api/google_calendar.go101
1 files changed, 38 insertions, 63 deletions
diff --git a/internal/api/google_calendar.go b/internal/api/google_calendar.go
index 8217b49..dc61f3d 100644
--- a/internal/api/google_calendar.go
+++ b/internal/api/google_calendar.go
@@ -19,6 +19,39 @@ type GoogleCalendarClient struct {
calendarIDs []string
}
+// parseEventTime extracts start/end times from a Google Calendar event, converting to local timezone
+func parseEventTime(item *calendar.Event) (start, end time.Time) {
+ if item.Start.DateTime == "" {
+ // All-day event - parse in local timezone
+ start, _ = time.ParseInLocation("2006-01-02", item.Start.Date, time.Local)
+ end, _ = time.ParseInLocation("2006-01-02", item.End.Date, time.Local)
+ } else {
+ // Timed event - parse RFC3339 then convert to local
+ start, _ = time.Parse(time.RFC3339, item.Start.DateTime)
+ end, _ = time.Parse(time.RFC3339, item.End.DateTime)
+ start = start.Local()
+ end = end.Local()
+ }
+ return
+}
+
+// deduplicateEvents removes duplicate events (same summary + start time)
+func deduplicateEvents(events []models.CalendarEvent) []models.CalendarEvent {
+ seen := make(map[string]bool)
+ var unique []models.CalendarEvent
+ for _, event := range events {
+ key := fmt.Sprintf("%s|%d", event.Summary, event.Start.Unix())
+ if !seen[key] {
+ seen[key] = true
+ unique = append(unique, event)
+ }
+ }
+ sort.Slice(unique, func(i, j int) bool {
+ return unique[i].Start.Before(unique[j].Start)
+ })
+ return unique
+}
+
// NewGoogleCalendarClient creates a client that fetches from multiple calendars.
// calendarIDs can be comma-separated (e.g., "cal1@group.calendar.google.com,cal2@group.calendar.google.com")
func NewGoogleCalendarClient(ctx context.Context, credentialsFile, calendarIDs string) (*GoogleCalendarClient, error) {
@@ -51,23 +84,11 @@ func (c *GoogleCalendarClient) GetUpcomingEvents(ctx context.Context, maxResults
SingleEvents(true).TimeMin(t).MaxResults(int64(maxResults)).OrderBy("startTime").Do()
if err != nil {
log.Printf("Warning: failed to fetch events from calendar %s: %v", calendarID, err)
- continue // Don't fail entirely, just skip this calendar
+ continue
}
for _, item := range events.Items {
- var start, end time.Time
- if item.Start.DateTime == "" {
- // All-day event - parse in local timezone
- start, _ = time.ParseInLocation("2006-01-02", item.Start.Date, time.Local)
- end, _ = time.ParseInLocation("2006-01-02", item.End.Date, time.Local)
- } else {
- // Timed event - parse RFC3339 then convert to local
- start, _ = time.Parse(time.RFC3339, item.Start.DateTime)
- end, _ = time.Parse(time.RFC3339, item.End.DateTime)
- start = start.Local()
- end = end.Local()
- }
-
+ start, end := parseEventTime(item)
allEvents = append(allEvents, models.CalendarEvent{
ID: item.Id,
Summary: item.Summary,
@@ -79,29 +100,10 @@ func (c *GoogleCalendarClient) GetUpcomingEvents(ctx context.Context, maxResults
}
}
- // Deduplicate events (same event may appear in multiple calendars)
- // Use Unix timestamp to handle timezone differences
- seen := make(map[string]bool)
- var uniqueEvents []models.CalendarEvent
- for _, event := range allEvents {
- // Use summary + unix timestamp as dedup key (handles timezone differences)
- key := fmt.Sprintf("%s|%d", event.Summary, event.Start.Unix())
- if !seen[key] {
- seen[key] = true
- uniqueEvents = append(uniqueEvents, event)
- }
- }
-
- // Sort all events by start time
- sort.Slice(uniqueEvents, func(i, j int) bool {
- return uniqueEvents[i].Start.Before(uniqueEvents[j].Start)
- })
-
- // Limit to maxResults
+ uniqueEvents := deduplicateEvents(allEvents)
if len(uniqueEvents) > maxResults {
uniqueEvents = uniqueEvents[:maxResults]
}
-
return uniqueEvents, nil
}
@@ -119,19 +121,7 @@ func (c *GoogleCalendarClient) GetEventsByDateRange(ctx context.Context, start,
}
for _, item := range events.Items {
- var evtStart, evtEnd time.Time
- if item.Start.DateTime == "" {
- // All-day event - parse in local timezone
- evtStart, _ = time.ParseInLocation("2006-01-02", item.Start.Date, time.Local)
- evtEnd, _ = time.ParseInLocation("2006-01-02", item.End.Date, time.Local)
- } else {
- // Timed event - parse RFC3339 then convert to local
- evtStart, _ = time.Parse(time.RFC3339, item.Start.DateTime)
- evtEnd, _ = time.Parse(time.RFC3339, item.End.DateTime)
- evtStart = evtStart.Local()
- evtEnd = evtEnd.Local()
- }
-
+ evtStart, evtEnd := parseEventTime(item)
allEvents = append(allEvents, models.CalendarEvent{
ID: item.Id,
Summary: item.Summary,
@@ -143,20 +133,5 @@ func (c *GoogleCalendarClient) GetEventsByDateRange(ctx context.Context, start,
}
}
- // Deduplicate
- seen := make(map[string]bool)
- var uniqueEvents []models.CalendarEvent
- for _, event := range allEvents {
- key := fmt.Sprintf("%s|%d", event.Summary, event.Start.Unix())
- if !seen[key] {
- seen[key] = true
- uniqueEvents = append(uniqueEvents, event)
- }
- }
-
- sort.Slice(uniqueEvents, func(i, j int) bool {
- return uniqueEvents[i].Start.Before(uniqueEvents[j].Start)
- })
-
- return uniqueEvents, nil
+ return deduplicateEvents(allEvents), nil
}