package handler import ( "encoding/json" "net/http" "time" "gitea.kleinsense.nl/DariusKlein/kleinTodo/common" "gitea.kleinsense.nl/DariusKlein/kleinTodo/common/jwt" ) func SyncHandler(w http.ResponseWriter, r *http.Request) { // 1. Setup: Auth, Decode, Database Connection user, err := jwt.GetVerifiedUser(r) if handleError(w, http.StatusUnauthorized, err) { return } var todoList common.TodoList if handleError(w, http.StatusBadRequest, json.NewDecoder(r.Body).Decode(&todoList)) { return } store, err := common.GetTodoDataStore() if handleError(w, http.StatusInternalServerError, err) { return } // 2. Load Server State serverTodos := store.GetTodoMap(user) response := common.SyncResponse{ SyncedTodos: []common.Todo{}, MisMatchingTodos: []common.MisMatchingTodo{}, } // 3. Process Client Updates for _, clientTodo := range todoList.Todos { // Default to "Now" if clientTodo.LastModified.IsZero() { clientTodo.LastModified = time.Now().UTC() } serverTodo, exists := serverTodos[clientTodo.Id] // New Item (Does not exist on server) if !exists { if clientTodo.Deleted { continue // Ignore deleted items that don't exist } if handleError(w, http.StatusInternalServerError, clientTodo.Store(store, user)) { return } // Add to map so it gets returned in the "Synced" list serverTodos[clientTodo.Id] = clientTodo continue } // Item is deleted (Client wants to delete) if clientTodo.Deleted { // Only delete if client is newer than server if clientTodo.LastModified.After(serverTodo.LastModified) { if handleError(w, http.StatusInternalServerError, store.RemoveValueFromBucket(user, clientTodo.Id)) { return } // Remove from map so it is NOT returned in the "Synced" list delete(serverTodos, clientTodo.Id) } continue } // Item is updated (Item exists and is not deleted) --- if serverTodo.IsEqual(clientTodo) { continue } isMergeable := serverTodo.IsEqualIgnoringStatus(clientTodo) && clientTodo.LastModified.After(serverTodo.LastModified) if isMergeable { if handleError(w, http.StatusInternalServerError, clientTodo.Store(store, user)) { return } serverTodos[clientTodo.Id] = clientTodo } else { response.MisMatchingTodos = append(response.MisMatchingTodos, common.MisMatchingTodo{ ServerTodo: serverTodo, LocalTodo: clientTodo, }) delete(serverTodos, clientTodo.Id) } } // Build Final Response for _, todo := range serverTodos { response.SyncedTodos = append(response.SyncedTodos, todo) } w.Header().Set("Content-Type", "application/json") handleError(w, http.StatusInternalServerError, json.NewEncoder(w).Encode(response)) }