Fixed sync logic + code cleanup
All checks were successful
build and deploy kleinTodo / build (push) Successful in 17s
All checks were successful
build and deploy kleinTodo / build (push) Successful in 17s
This commit is contained in:
parent
deb43b98aa
commit
58bde59342
@ -80,6 +80,10 @@ func syncAction(context context.Context, c *cli.Command) error {
|
|||||||
response.SyncedTodos = append(response.SyncedTodos, todo.ServerTodo)
|
response.SyncedTodos = append(response.SyncedTodos, todo.ServerTodo)
|
||||||
} else {
|
} else {
|
||||||
response.SyncedTodos = append(response.SyncedTodos, todo.LocalTodo)
|
response.SyncedTodos = append(response.SyncedTodos, todo.LocalTodo)
|
||||||
|
if common.AskUserBool("Do you wish to push this to the server?") {
|
||||||
|
println("TODO not yet implemented")
|
||||||
|
// TODO push to server
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,7 +108,8 @@ func (todo Todo) PrintIndexed(index int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t Todo) IsEqual(other Todo) bool {
|
func (t Todo) IsEqual(other Todo) bool {
|
||||||
return t.Name == other.Name &&
|
return t.Id == other.Id &&
|
||||||
|
t.Name == other.Name &&
|
||||||
t.Description == other.Description &&
|
t.Description == other.Description &&
|
||||||
t.Status == other.Status &&
|
t.Status == other.Status &&
|
||||||
t.Owner == other.Owner &&
|
t.Owner == other.Owner &&
|
||||||
@ -116,7 +117,8 @@ func (t Todo) IsEqual(other Todo) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t Todo) IsEqualIgnoringStatus(other Todo) bool {
|
func (t Todo) IsEqualIgnoringStatus(other Todo) bool {
|
||||||
return t.Name == other.Name &&
|
return t.Id == other.Id &&
|
||||||
|
t.Name == other.Name &&
|
||||||
t.Description == other.Description &&
|
t.Description == other.Description &&
|
||||||
t.Owner == other.Owner &&
|
t.Owner == other.Owner &&
|
||||||
t.Deleted == other.Deleted
|
t.Deleted == other.Deleted
|
||||||
|
|||||||
@ -21,6 +21,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if handleError(w, http.StatusInternalServerError, err) {
|
if handleError(w, http.StatusInternalServerError, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Check password
|
||||||
password := db.GetFromBucketByKey(common.UserBucket, user.Username)
|
password := db.GetFromBucketByKey(common.UserBucket, user.Username)
|
||||||
if user.ComparePasswords(password) {
|
if user.ComparePasswords(password) {
|
||||||
w.Header().Set(common.AuthHeader, jwt.CreateUserJWT(user.Username))
|
w.Header().Set(common.AuthHeader, jwt.CreateUserJWT(user.Username))
|
||||||
|
|||||||
@ -10,14 +10,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func SyncHandler(w http.ResponseWriter, r *http.Request) {
|
func SyncHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 1. Setup: Auth, Decode, Database Connection
|
||||||
user, err := jwt.GetVerifiedUser(r)
|
user, err := jwt.GetVerifiedUser(r)
|
||||||
if handleError(w, http.StatusUnauthorized, err) {
|
if handleError(w, http.StatusUnauthorized, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var todoList common.TodoList
|
var todoList common.TodoList
|
||||||
err = json.NewDecoder(r.Body).Decode(&todoList)
|
if handleError(w, http.StatusBadRequest, json.NewDecoder(r.Body).Decode(&todoList)) {
|
||||||
if handleError(w, http.StatusBadRequest, err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,62 +26,76 @@ func SyncHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Load Server State
|
||||||
serverTodos := store.GetTodoMap(user)
|
serverTodos := store.GetTodoMap(user)
|
||||||
|
response := common.SyncResponse{
|
||||||
var response = common.SyncResponse{
|
|
||||||
SyncedTodos: []common.Todo{},
|
SyncedTodos: []common.Todo{},
|
||||||
MisMatchingTodos: []common.MisMatchingTodo{},
|
MisMatchingTodos: []common.MisMatchingTodo{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Process Client Updates
|
||||||
for _, clientTodo := range todoList.Todos {
|
for _, clientTodo := range todoList.Todos {
|
||||||
|
|
||||||
|
// Default to "Now"
|
||||||
if clientTodo.LastModified.IsZero() {
|
if clientTodo.LastModified.IsZero() {
|
||||||
clientTodo.LastModified = time.Now().UTC()
|
clientTodo.LastModified = time.Now().UTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
serverTodo, exists := serverTodos[clientTodo.Id]
|
serverTodo, exists := serverTodos[clientTodo.Id]
|
||||||
|
|
||||||
|
// New Item (Does not exist on server)
|
||||||
if !exists {
|
if !exists {
|
||||||
if clientTodo.Deleted {
|
if clientTodo.Deleted {
|
||||||
continue
|
continue // Ignore deleted items that don't exist
|
||||||
}
|
}
|
||||||
err = clientTodo.Store(store, user)
|
|
||||||
if handleError(w, http.StatusInternalServerError, err) {
|
if handleError(w, http.StatusInternalServerError, clientTodo.Store(store, user)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Add to map so it gets returned in the "Synced" list
|
||||||
serverTodos[clientTodo.Id] = clientTodo
|
serverTodos[clientTodo.Id] = clientTodo
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Item is deleted (Client wants to delete)
|
||||||
if clientTodo.Deleted {
|
if clientTodo.Deleted {
|
||||||
|
// Only delete if client is newer than server
|
||||||
if clientTodo.LastModified.After(serverTodo.LastModified) {
|
if clientTodo.LastModified.After(serverTodo.LastModified) {
|
||||||
err = store.RemoveValueFromBucket(user, clientTodo.Id)
|
if handleError(w, http.StatusInternalServerError, store.RemoveValueFromBucket(user, clientTodo.Id)) {
|
||||||
if handleError(w, http.StatusInternalServerError, err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Remove from map so it is NOT returned in the "Synced" list
|
||||||
delete(serverTodos, clientTodo.Id)
|
delete(serverTodos, clientTodo.Id)
|
||||||
}
|
}
|
||||||
} else if !serverTodo.IsEqual(clientTodo) {
|
continue
|
||||||
if serverTodo.IsEqualIgnoringStatus(clientTodo) && clientTodo.LastModified.After(serverTodo.LastModified) {
|
}
|
||||||
err = clientTodo.Store(store, user)
|
|
||||||
if handleError(w, http.StatusInternalServerError, err) {
|
// Item is updated (Item exists and is not deleted) ---
|
||||||
return
|
if serverTodo.IsEqual(clientTodo) {
|
||||||
}
|
continue
|
||||||
serverTodos[clientTodo.Id] = clientTodo
|
}
|
||||||
} else {
|
|
||||||
response.MisMatchingTodos = append(response.MisMatchingTodos, common.MisMatchingTodo{
|
isMergeable := serverTodo.IsEqualIgnoringStatus(clientTodo) && clientTodo.LastModified.After(serverTodo.LastModified)
|
||||||
ServerTodo: serverTodo,
|
|
||||||
LocalTodo: clientTodo,
|
if isMergeable {
|
||||||
})
|
if handleError(w, http.StatusInternalServerError, clientTodo.Store(store, user)) {
|
||||||
delete(serverTodos, clientTodo.Id)
|
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 {
|
for _, todo := range serverTodos {
|
||||||
response.SyncedTodos = append(response.SyncedTodos, todo)
|
response.SyncedTodos = append(response.SyncedTodos, todo)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
err = json.NewEncoder(w).Encode(response)
|
handleError(w, http.StatusInternalServerError, json.NewEncoder(w).Encode(response))
|
||||||
if handleError(w, http.StatusInternalServerError, err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user