diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-03-04 11:12:44 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-03-04 11:12:44 -1000 |
| commit | 0fd54eddc40f517cf491310d4f8a60b0d79dc937 (patch) | |
| tree | b026328a49b9583efb7c94b3777830c31c46fa33 /internal/store | |
| parent | 4853a4a917bb7942776ffd8b3e003ee03fc49160 (diff) | |
feat: sync log, cache clear endpoint, Todoist projects from cached tasks
- migration 016: sync_log table
- store: AddSyncLogEntry, GetRecentSyncLog, InvalidateAllCaches, GetProjectsFromTasks
- settings: HandleClearCache (POST /settings/clear-cache), SyncLog in page data
- settings: use GetProjectsFromTasks instead of deprecated Todoist REST /projects
- handlers: populate atom projects from store
- agent: log warning on registration failure instead of silently swallowing
- google_tasks: simplify URL literal
- tests: sync log CRUD, clear cache handler, settings page includes sync log,
sync sources adds log entry, incremental sync paths, task completion
response/headers, calendar cache fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/store')
| -rw-r--r-- | internal/store/sqlite.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go index 158febc..366b24e 100644 --- a/internal/store/sqlite.go +++ b/internal/store/sqlite.go @@ -1397,6 +1397,37 @@ func (s *Store) SyncSourceConfigs(source, itemType string, items []models.Source return tx.Commit() } +// InvalidateAllCaches removes cache metadata for all known cache keys +func (s *Store) InvalidateAllCaches() error { + _, err := s.db.Exec(`DELETE FROM cache_metadata WHERE key IN (?, ?, ?, ?)`, + CacheKeyTodoistTasks, CacheKeyTrelloBoards, CacheKeyPlanToEatMeals, CacheKeyGoogleCalendar) + return err +} + +// GetProjectsFromTasks returns distinct projects from the tasks table +func (s *Store) GetProjectsFromTasks() ([]models.Project, error) { + rows, err := s.db.Query(` + SELECT DISTINCT project_id, project_name + FROM tasks + WHERE project_id != '' + ORDER BY project_name + `) + if err != nil { + return nil, err + } + defer func() { _ = rows.Close() }() + + var projects []models.Project + for rows.Next() { + var p models.Project + if err := rows.Scan(&p.ID, &p.Name); err != nil { + return nil, err + } + projects = append(projects, p) + } + return projects, rows.Err() +} + // Feature toggles // GetFeatureToggles returns all feature toggles @@ -1457,3 +1488,42 @@ func (s *Store) DeleteFeatureToggle(name string) error { _, err := s.db.Exec(`DELETE FROM feature_toggles WHERE name = ?`, name) return err } + +// SyncLogEntry represents a single entry in the sync activity log +type SyncLogEntry struct { + ID int64 + EventType string + Message string + CreatedAt time.Time +} + +// AddSyncLogEntry records a sync or cache event in the log +func (s *Store) AddSyncLogEntry(eventType, message string) error { + _, err := s.db.Exec( + `INSERT INTO sync_log (event_type, message) VALUES (?, ?)`, + eventType, message, + ) + return err +} + +// GetRecentSyncLog returns the most recent sync log entries, newest first +func (s *Store) GetRecentSyncLog(limit int) ([]SyncLogEntry, error) { + rows, err := s.db.Query( + `SELECT id, event_type, message, created_at FROM sync_log ORDER BY id DESC LIMIT ?`, + limit, + ) + if err != nil { + return nil, err + } + defer func() { _ = rows.Close() }() + + var entries []SyncLogEntry + for rows.Next() { + var e SyncLogEntry + if err := rows.Scan(&e.ID, &e.EventType, &e.Message, &e.CreatedAt); err != nil { + return nil, err + } + entries = append(entries, e) + } + return entries, rows.Err() +} |
