summaryrefslogtreecommitdiff
path: root/internal/handlers/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/handlers/handlers.go')
-rw-r--r--internal/handlers/handlers.go95
1 files changed, 88 insertions, 7 deletions
diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go
index 0af2bba..f53eced 100644
--- a/internal/handlers/handlers.go
+++ b/internal/handlers/handlers.go
@@ -350,9 +350,10 @@ func (h *Handler) aggregateData(ctx context.Context, forceRefresh bool) (*models
return data, nil
}
-// fetchTasks fetches tasks from cache or API
+// fetchTasks fetches tasks from cache or API using incremental sync
func (h *Handler) fetchTasks(ctx context.Context, forceRefresh bool) ([]models.Task, error) {
cacheKey := store.CacheKeyTodoistTasks
+ syncService := "todoist"
// Check cache validity
if !forceRefresh {
@@ -362,8 +363,20 @@ func (h *Handler) fetchTasks(ctx context.Context, forceRefresh bool) ([]models.T
}
}
- // Fetch from API
- tasks, err := h.todoistClient.GetTasks(ctx)
+ // Get stored sync token (empty string means full sync)
+ syncToken, err := h.store.GetSyncToken(syncService)
+ if err != nil {
+ log.Printf("Failed to get sync token, will do full sync: %v", err)
+ syncToken = ""
+ }
+
+ // Force full sync if requested
+ if forceRefresh {
+ syncToken = ""
+ }
+
+ // Fetch using Sync API
+ syncResp, err := h.todoistClient.Sync(ctx, syncToken)
if err != nil {
// Try to return cached data even if stale
cachedTasks, cacheErr := h.store.GetTasks()
@@ -373,9 +386,41 @@ func (h *Handler) fetchTasks(ctx context.Context, forceRefresh bool) ([]models.T
return nil, err
}
- // Save to cache
- if err := h.store.SaveTasks(tasks); err != nil {
- log.Printf("Failed to save tasks to cache: %v", err)
+ // Build project map from sync response
+ projectMap := api.BuildProjectMapFromSync(syncResp.Projects)
+
+ // Process sync response
+ if syncResp.FullSync {
+ // Full sync: replace all tasks
+ tasks := api.ConvertSyncItemsToTasks(syncResp.Items, projectMap)
+ if err := h.store.SaveTasks(tasks); err != nil {
+ log.Printf("Failed to save tasks to cache: %v", err)
+ }
+ } else {
+ // Incremental sync: merge changes
+ var deletedIDs []string
+ for _, item := range syncResp.Items {
+ if item.IsDeleted || item.IsCompleted {
+ deletedIDs = append(deletedIDs, item.ID)
+ } else {
+ // Upsert active task
+ task := h.convertSyncItemToTask(item, projectMap)
+ if err := h.store.UpsertTask(task); err != nil {
+ log.Printf("Failed to upsert task %s: %v", item.ID, err)
+ }
+ }
+ }
+ // Delete removed tasks
+ if len(deletedIDs) > 0 {
+ if err := h.store.DeleteTasksByIDs(deletedIDs); err != nil {
+ log.Printf("Failed to delete tasks: %v", err)
+ }
+ }
+ }
+
+ // Store the new sync token
+ if err := h.store.SetSyncToken(syncService, syncResp.SyncToken); err != nil {
+ log.Printf("Failed to save sync token: %v", err)
}
// Update cache metadata
@@ -383,7 +428,43 @@ func (h *Handler) fetchTasks(ctx context.Context, forceRefresh bool) ([]models.T
log.Printf("Failed to update cache metadata: %v", err)
}
- return tasks, nil
+ return h.store.GetTasks()
+}
+
+// convertSyncItemToTask converts a sync item to a Task model
+func (h *Handler) convertSyncItemToTask(item api.SyncItemResponse, projectMap map[string]string) models.Task {
+ task := models.Task{
+ ID: item.ID,
+ Content: item.Content,
+ Description: item.Description,
+ ProjectID: item.ProjectID,
+ ProjectName: projectMap[item.ProjectID],
+ Priority: item.Priority,
+ Completed: false,
+ Labels: item.Labels,
+ URL: fmt.Sprintf("https://todoist.com/showTask?id=%s", item.ID),
+ }
+
+ if item.AddedAt != "" {
+ if createdAt, err := time.Parse(time.RFC3339, item.AddedAt); err == nil {
+ task.CreatedAt = createdAt
+ }
+ }
+
+ if item.Due != nil {
+ var dueDate time.Time
+ var err error
+ if item.Due.Datetime != "" {
+ dueDate, err = time.Parse(time.RFC3339, item.Due.Datetime)
+ } else if item.Due.Date != "" {
+ dueDate, err = time.Parse("2006-01-02", item.Due.Date)
+ }
+ if err == nil {
+ task.DueDate = &dueDate
+ }
+ }
+
+ return task
}
// fetchNotes fetches notes from cache or filesystem