diff --git a/pages/base.html b/pages/base.html
index 3fa0cc4..10b3755 100644
--- a/pages/base.html
+++ b/pages/base.html
@@ -51,7 +51,7 @@
}
// Check if auth info is indeed valid
- let response = await get_user(username, password);
+ let response = await getUser(username, password);
if (response.ok) {
let barAuth = document.getElementById("bar-auth");
barAuth.innerHTML = "" + username + "" + " | ";
diff --git a/pages/index.html b/pages/index.html
index d8777f8..7afd54b 100644
--- a/pages/index.html
+++ b/pages/index.html
@@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', async function() {
newTodoTextInput.value = "";
// Make a request
- let response = await post_new_todo(username, password, {text: newTodoText});
+ let response = await postNewTodo(username, password, {text: newTodoText});
if (response.ok) {
location.reload();
}
@@ -50,10 +50,12 @@ document.addEventListener('DOMContentLoaded', async function() {
// Fetch and display TODOs
- response = await get_todos(username, password);
+ response = await getTodos(username, password);
let todosJson = await response.json();
let todos = [];
let completeButtonIDs = [];
+ let deleteButtonIDs = [];
+
if (response.ok && todosJson != null) {
let todosDiv = document.getElementById("todos");
todosJson.forEach((item) => {
@@ -72,16 +74,30 @@ document.addEventListener('DOMContentLoaded', async function() {
todosDiv.innerHTML += "
" + item.text + " | " +
"" + " " + timeCreated.getDate() + "/" + timeCreated.getMonth() + "/" + timeCreated.getFullYear() + " | " +
" |
";
+ "";
completeButtonIDs.push(todoCompleteBtnID);
+ deleteButtonIDs.push(todoDeleteBtnID);
});
}
+ // Loop over all buttons (doesn't matter which ones because the amounts are equal)
for (let i = 0; i < completeButtonIDs.length; i++) {
+ // Done button
document.getElementById(completeButtonIDs[i]).addEventListener("click", async (event) => {
- response = await delete_todo(username, password, todos[i].id);
+ // Mark as done
+ todos[i].isDone = true;
+ // Update
+ response = await updateTodo(username, password, todos[i].id, todos[i]);
+ if (response.ok) {
+ location.reload();
+ }
+ });
+
+ // Delete button
+ document.getElementById(deleteButtonIDs[i]).addEventListener("click", async (event) => {
+ response = await deleteTodo(username, password, todos[i].id);
if (response.ok) {
location.reload();
}
diff --git a/scripts/api.js b/scripts/api.js
index d70eb5f..9b43b55 100644
--- a/scripts/api.js
+++ b/scripts/api.js
@@ -3,7 +3,7 @@
*/
-async function post_new_todo(username, password, new_todo) {
+async function postNewTodo(username, password, new_todo) {
return fetch("/api/todo", {
method: "POST",
headers: {
@@ -16,7 +16,7 @@ async function post_new_todo(username, password, new_todo) {
}
-async function get_todos(username, password) {
+async function getTodos(username, password) {
return fetch("/api/todo", {
method: "GET",
headers: {
@@ -27,7 +27,7 @@ async function get_todos(username, password) {
}
-async function get_todo_groups(username, password) {
+async function getTodoGroups(username, password) {
return fetch("/api/group", {
method: "GET",
headers: {
@@ -37,7 +37,7 @@ async function get_todo_groups(username, password) {
});
}
-async function delete_todo(username, password, id) {
+async function deleteTodo(username, password, id) {
return fetch("/api/todo/"+String(id), {
method: "DELETE",
headers: {
@@ -47,7 +47,18 @@ async function delete_todo(username, password, id) {
});
}
-async function get_user(username, password) {
+async function updateTodo(username, password, id, updatedTodo) {
+ return fetch("/api/todo/"+String(id), {
+ method: "POST",
+ headers: {
+ "EncryptedBase64": "false",
+ "Auth": username + "<-->" + password,
+ },
+ body: JSON.stringify(updatedTodo),
+ });
+}
+
+async function getUser(username, password) {
return fetch("/api/user", {
method: "GET",
headers: {
diff --git a/src/server/api.go b/src/server/api.go
index 725fc96..bc79b65 100644
--- a/src/server/api.go
+++ b/src/server/api.go
@@ -124,7 +124,7 @@ func (s *Server) UserEndpoint(w http.ResponseWriter, req *http.Request) {
}
}
-func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) {
+func (s *Server) SpecificTodoEndpoint(w http.ResponseWriter, req *http.Request) {
switch req.Method {
case http.MethodDelete:
// Delete an existing TODO
@@ -150,35 +150,92 @@ func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) {
return
}
- // Mark TODO as done and assign a completion time
- updatedTodo, err := s.db.GetTodo(todoID)
+ // // Mark TODO as done and assign a completion time
+ // updatedTodo, err := s.db.GetTodo(todoID)
+ // if err != nil {
+ // logger.Error("[Server] Failed to get todo with id %d for marking completion: %s", todoID, err)
+ // http.Error(w, "TODO retrieval error", http.StatusInternalServerError)
+ // return
+ // }
+ // updatedTodo.IsDone = true
+ // updatedTodo.CompletionTimeUnix = uint64(time.Now().Unix())
+
+ // err = s.db.UpdateTodo(todoID, *updatedTodo)
+ // if err != nil {
+ // logger.Error("[Server] Failed to update TODO with id %d: %s", todoID, err)
+ // http.Error(w, "Failed to update TODO information", http.StatusInternalServerError)
+ // return
+ // }
+
+ // Now delete
+ err = s.db.DeleteTodo(todoID)
if err != nil {
- logger.Error("[Server] Failed to get todo with id %d for marking completion: %s", todoID, err)
- http.Error(w, "TODO retrieval error", http.StatusInternalServerError)
+ logger.Error("[Server] Failed to delete %s's TODO: %s", GetUsernameFromAuth(req), err)
+ http.Error(w, "Failed to delete TODO", http.StatusInternalServerError)
return
}
- updatedTodo.IsDone = true
- updatedTodo.CompletionTimeUnix = uint64(time.Now().Unix())
- err = s.db.UpdateTodo(todoID, *updatedTodo)
+ // Success!
+ logger.Info("[Server] Deleted TODO with ID %d", todoID)
+ w.WriteHeader(http.StatusOK)
+
+ case http.MethodPost:
+ // Change TODO information
+
+ // Check authentication information
+ if !IsRequestAuthValid(req, s.db) {
+ http.Error(w, "Invalid user auth data", http.StatusForbidden)
+ return
+ }
+
+ // Obtain TODO ID
+ todoIDStr := path.Base(req.URL.Path)
+ todoID, err := strconv.ParseUint(todoIDStr, 10, 64)
if err != nil {
- logger.Error("[Server] Failed to update TODO with id %d: %s", todoID, err)
- http.Error(w, "Failed to update TODO information", http.StatusInternalServerError)
+ http.Error(w, "Invalid TODO ID", http.StatusBadRequest)
return
}
- // Now delete
- // err = s.db.DeleteTodo(todoID)
- // if err != nil {
- // logger.Error("[Server] Failed to delete %s's TODO: %s", GetUsernameFromAuth(req), err)
- // http.Error(w, "Failed to delete TODO", http.StatusInternalServerError)
- // return
- // }
+ // Check if the user owns this TODO
+ if !DoesUserOwnTodo(GetUsernameFromAuth(req), todoID, s.db) {
+ http.Error(w, "You don't own this TODO", http.StatusForbidden)
+ return
+ }
- // Success!
- logger.Info("[Server] updated (marked as done) TODO with ID %d", todoID)
+ // Read body
+ body, err := io.ReadAll(req.Body)
+ if err != nil {
+ logger.Warning("[Server] Failed to read request body to possibly update a TODO: %s", err)
+ http.Error(w, "Failed to read body", http.StatusInternalServerError)
+ return
+ }
+
+ // Unmarshal JSON
+ var updatedTodo db.Todo
+ err = json.Unmarshal(body, &updatedTodo)
+ if err != nil {
+ logger.Warning("[Server] Received invalid TODO JSON in order to update: %s", err)
+ http.Error(w, "Invalid TODO JSON", http.StatusBadRequest)
+ return
+ }
+
+ // Update. (Creation date, owner username and an ID do not change)
+ err = s.db.UpdateTodo(todoID, updatedTodo)
+ if err != nil {
+ logger.Warning("[Server] Failed to update TODO: %s", err)
+ http.Error(w, "Failed to update", http.StatusBadRequest)
+ return
+ }
w.WriteHeader(http.StatusOK)
+ logger.Info("[Server] Updated TODO with ID %d", todoID)
+ default:
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) {
+ switch req.Method {
case http.MethodPost:
// Create a new TODO
defer req.Body.Close()
@@ -218,6 +275,7 @@ func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) {
// Success!
w.WriteHeader(http.StatusOK)
logger.Info("[Server] Created a new TODO for %s", newTodo.OwnerUsername)
+
case http.MethodGet:
// Retrieve TODO information
// Check authentication information
@@ -226,7 +284,7 @@ func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) {
return
}
- // Get TODO
+ // Get all user TODOs
todos, err := s.db.GetAllUserTodos(GetUsernameFromAuth(req))
if err != nil {
http.Error(w, "Failed to get TODOs", http.StatusInternalServerError)
@@ -243,42 +301,6 @@ func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) {
// Send out
w.Header().Add("Content-Type", "application/json")
w.Write(todosBytes)
-
- // case http.MethodPatch:
- // // Change TODO due date and text
-
- // // Check authentication information
- // if !IsRequestAuthValid(req, s.db) {
- // http.Error(w, "Invalid user auth data", http.StatusForbidden)
- // return
- // }
-
- // // Read body
- // body, err := io.ReadAll(req.Body)
- // if err != nil {
- // logger.Warning("[Server] Failed to read request body to possibly update a TODO: %s", err)
- // http.Error(w, "Failed to read body", http.StatusInternalServerError)
- // return
- // }
-
- // // Unmarshal JSON
- // var todo db.Todo
- // err = json.Unmarshal(body, &todo)
- // if err != nil {
- // logger.Warning("[Server] Received invalid TODO JSON in order to update: %s", err)
- // http.Error(w, "Invalid TODO JSON", http.StatusBadRequest)
- // return
- // }
-
- // // TODO
- // err = s.db.UpdateTodo(todo.ID, todo)
- // if err != nil {
- // logger.Warning("[Server] Failed to update TODO: %s", err)
- // http.Error(w, "Failed to update", http.StatusBadRequest)
- // return
- // }
-
- // w.WriteHeader(http.StatusOK)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
diff --git a/src/server/server.go b/src/server/server.go
index b0759ac..bb53f27 100644
--- a/src/server/server.go
+++ b/src/server/server.go
@@ -133,7 +133,7 @@ func New(config conf.Conf) (*Server, error) {
})
mux.HandleFunc("/api/user", server.UserEndpoint)
mux.HandleFunc("/api/todo", server.TodoEndpoint)
- mux.HandleFunc("/api/todo/", server.TodoEndpoint)
+ mux.HandleFunc("/api/todo/", server.SpecificTodoEndpoint)
// mux.HandleFunc("/api/group", server.TodoGroupEndpoint)