summaryrefslogtreecommitdiff
path: root/internal/handlers/settings.go
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-04 11:12:44 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-03-04 11:12:44 -1000
commit0fd54eddc40f517cf491310d4f8a60b0d79dc937 (patch)
treeb026328a49b9583efb7c94b3777830c31c46fa33 /internal/handlers/settings.go
parent4853a4a917bb7942776ffd8b3e003ee03fc49160 (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/handlers/settings.go')
-rw-r--r--internal/handlers/settings.go50
1 files changed, 36 insertions, 14 deletions
diff --git a/internal/handlers/settings.go b/internal/handlers/settings.go
index 0ad362b..c0ba654 100644
--- a/internal/handlers/settings.go
+++ b/internal/handlers/settings.go
@@ -8,12 +8,14 @@ import (
"task-dashboard/internal/auth"
"task-dashboard/internal/models"
+ "task-dashboard/internal/store"
)
// HandleSettingsPage renders the settings page
func (h *Handler) HandleSettingsPage(w http.ResponseWriter, r *http.Request) {
configs, _ := h.store.GetSourceConfigs()
toggles, _ := h.store.GetFeatureToggles()
+ syncLog, _ := h.store.GetRecentSyncLog(20)
// Group configs by source
bySource := make(map[string][]models.SourceConfig)
@@ -25,12 +27,14 @@ func (h *Handler) HandleSettingsPage(w http.ResponseWriter, r *http.Request) {
Configs map[string][]models.SourceConfig
Sources []string
Toggles []models.FeatureToggle
+ SyncLog []store.SyncLogEntry
CSRFToken string
WebAuthnEnabled bool
}{
Configs: bySource,
Sources: []string{"trello", "todoist", "gcal", "gtasks"},
Toggles: toggles,
+ SyncLog: syncLog,
CSRFToken: auth.GetCSRFTokenFromContext(r.Context()),
WebAuthnEnabled: h.WebAuthnEnabled,
}
@@ -61,21 +65,18 @@ func (h *Handler) HandleSyncSources(w http.ResponseWriter, r *http.Request) {
}
}
- // Sync Todoist projects
- if h.todoistClient != nil {
- projects, err := h.todoistClient.GetProjects(ctx)
- if err == nil {
- var items []models.SourceConfig
- for _, p := range projects {
- items = append(items, models.SourceConfig{
- Source: "todoist",
- ItemType: "project",
- ItemID: p.ID,
- ItemName: p.Name,
- })
- }
- _ = h.store.SyncSourceConfigs("todoist", "project", items)
+ // Sync Todoist projects from cached tasks (avoids deprecated REST API)
+ if projects, err := h.store.GetProjectsFromTasks(); err == nil && len(projects) > 0 {
+ var items []models.SourceConfig
+ for _, p := range projects {
+ items = append(items, models.SourceConfig{
+ Source: "todoist",
+ ItemType: "project",
+ ItemID: p.ID,
+ ItemName: p.Name,
+ })
}
+ _ = h.store.SyncSourceConfigs("todoist", "project", items)
}
// Sync Google Calendar calendars
@@ -112,10 +113,31 @@ func (h *Handler) HandleSyncSources(w http.ResponseWriter, r *http.Request) {
}
}
+ _ = h.store.AddSyncLogEntry("sync", "Sources synced")
+
// Return updated configs
h.HandleSettingsPage(w, r)
}
+// HandleClearCache invalidates all caches and clears the Todoist sync token
+func (h *Handler) HandleClearCache(w http.ResponseWriter, r *http.Request) {
+ if err := h.store.InvalidateAllCaches(); err != nil {
+ JSONError(w, http.StatusInternalServerError, "Failed to clear cache", err)
+ return
+ }
+
+ if err := h.store.ClearSyncToken("todoist"); err != nil {
+ JSONError(w, http.StatusInternalServerError, "Failed to clear sync token", err)
+ return
+ }
+
+ _ = h.store.AddSyncLogEntry("cache_clear", "Cache cleared — next load fetches fresh data")
+
+ syncLog, _ := h.store.GetRecentSyncLog(20)
+ w.Header().Set("HX-Trigger", "refresh-tasks")
+ HTMLResponse(w, h.renderer, "sync-log", syncLog)
+}
+
// HandleToggleSourceConfig toggles a source config item
func (h *Handler) HandleToggleSourceConfig(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {