diff --git a/pages/category.html b/pages/category.html
index 9df0c2e..dae6eeb 100644
--- a/pages/category.html
+++ b/pages/category.html
@@ -18,7 +18,7 @@
{{ .Name }}
- {{ .TimeCreatedUnix }}
+ {{ .TimeCreated }}
Is removable: {{ .Removable }}
@@ -46,29 +46,76 @@
-
-
- ToDo |
- Created |
- Due |
- Group Id |
-
-
- {{ range .Todos }}
-
- {{ .Text }} |
- {{ .TimeCreatedUnix }} |
- {{ .DueUnix }} |
- {{ .GroupID }} |
-
- {{ end }}
-
-
+
+
+
+ ToDo |
+ Created |
+ Due |
+
+
+ {{ range .Todos }}
+ {{ if not .IsDone }}
+
+ {{ .Text }} |
+ {{ .TimeCreated }} |
+ {{ .Due }} |
+
+
+
+ |
+
+ {{ end }}
+ {{ end }}
+
+
+
+
+
+
+ ToDo |
+ Created |
+ Completed |
+
+
+ {{ range .Todos }}
+ {{ if .IsDone }}
+
+ {{ .Text }} |
+ {{ .TimeCreated }} |
+ {{ .CompletionTime }} |
+
+
+ |
+
+ {{ end }}
+ {{ end }}
+
+
{{ end }}
\ No newline at end of file
diff --git a/scripts/api.js b/scripts/api.js
index 7e93a60..65a805c 100644
--- a/scripts/api.js
+++ b/scripts/api.js
@@ -54,7 +54,7 @@ async function getAllGroups() {
async function del(url) {
return fetch(url, {
- method: "DELETE",
+ method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
@@ -74,6 +74,10 @@ async function updateTodo(id, updatedTodo) {
return update("/api/todo/update/"+id, updatedTodo);
}
+async function markAsDone(id) {
+ return update("/api/todo/markdone/"+id);
+}
+
async function updateGroup(id, updatedGroup) {
return update("/api/group/update/"+id, updatedGroup);
}
diff --git a/src/db/group.go b/src/db/group.go
index c42e8a5..b9b1630 100644
--- a/src/db/group.go
+++ b/src/db/group.go
@@ -18,7 +18,10 @@
package db
-import "database/sql"
+import (
+ "database/sql"
+ "time"
+)
// Todo group structure
type TodoGroup struct {
@@ -27,6 +30,7 @@ type TodoGroup struct {
TimeCreatedUnix uint64 `json:"timeCreatedUnix"`
OwnerLogin string `json:"ownerLogin"`
Removable bool `json:"removable"`
+ TimeCreated string
}
func NewTodoGroup(name string, timeCreatedUnix uint64, ownerLogin string, removable bool) TodoGroup {
@@ -64,6 +68,14 @@ func scanTodoGroup(rows *sql.Rows) (*TodoGroup, error) {
return nil, err
}
+ // Convert to Basic time
+ timeCreated := time.Unix(int64(newTodoGroup.TimeCreatedUnix), 0)
+ if timeCreated.Year() == 1970 {
+ newTodoGroup.TimeCreated = "None"
+ } else {
+ newTodoGroup.TimeCreated = timeCreated.Format(time.DateOnly)
+ }
+
return &newTodoGroup, nil
}
diff --git a/src/db/todo.go b/src/db/todo.go
index 3451a98..6c72421 100644
--- a/src/db/todo.go
+++ b/src/db/todo.go
@@ -18,7 +18,10 @@
package db
-import "database/sql"
+import (
+ "database/sql"
+ "time"
+)
// Todo structure
type Todo struct {
@@ -30,6 +33,9 @@ type Todo struct {
OwnerLogin string `json:"ownerLogin"`
IsDone bool `json:"isDone"`
CompletionTimeUnix uint64 `json:"completionTimeUnix"`
+ TimeCreated string
+ CompletionTime string
+ Due string
}
func scanTodo(rows *sql.Rows) (*Todo, error) {
@@ -48,6 +54,28 @@ func scanTodo(rows *sql.Rows) (*Todo, error) {
return nil, err
}
+ // Convert to Basic time
+ timeCreated := time.Unix(int64(newTodo.TimeCreatedUnix), 0)
+ if timeCreated.Year() == 1970 {
+ newTodo.TimeCreated = "None"
+ } else {
+ newTodo.TimeCreated = timeCreated.Format(time.DateOnly)
+ }
+
+ due := time.Unix(int64(newTodo.DueUnix), 0)
+ if due.Year() == 1970 {
+ newTodo.Due = "None"
+ } else {
+ newTodo.Due = due.Format(time.DateOnly)
+ }
+
+ completionTime := time.Unix(int64(newTodo.CompletionTimeUnix), 0)
+ if completionTime.Year() == 1970 {
+ newTodo.CompletionTime = "None"
+ } else {
+ newTodo.CompletionTime = completionTime.Format(time.DateOnly)
+ }
+
return &newTodo, nil
}
diff --git a/src/server/endpoints.go b/src/server/endpoints.go
index c19372b..fe8651f 100644
--- a/src/server/endpoints.go
+++ b/src/server/endpoints.go
@@ -265,6 +265,53 @@ func (s *Server) EndpointTodoUpdate(w http.ResponseWriter, req *http.Request) {
logger.Info("[Server] Updated TODO with ID %d", todoID)
}
+func (s *Server) EndpointTodoMarkDone(w http.ResponseWriter, req *http.Request) {
+ defer req.Body.Close()
+
+ if req.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ // Check authentication information
+ if !IsUserAuthorizedReq(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 {
+ http.Error(w, "Invalid TODO ID", http.StatusBadRequest)
+ return
+ }
+
+ // Check if the user owns this TODO
+ if !s.db.DoesUserOwnTodo(todoID, GetLoginFromReq(req)) {
+ http.Error(w, "You don't own this TODO", http.StatusForbidden)
+ return
+ }
+
+ todo, err := s.db.GetTodo(todoID)
+ if err != nil {
+ http.Error(w, "Can't access this TODO", http.StatusInternalServerError)
+ return
+ }
+
+ // Update
+ todo.IsDone = true
+ todo.CompletionTimeUnix = uint64(time.Now().Unix())
+ err = s.db.UpdateTodo(todoID, *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)
+ logger.Info("[Server] Marked TODO as done %d", todoID)
+}
+
func (s *Server) EndpointTodoDelete(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
diff --git a/src/server/server.go b/src/server/server.go
index 9994ec4..570e538 100644
--- a/src/server/server.go
+++ b/src/server/server.go
@@ -196,6 +196,7 @@ func New(config conf.Conf) (*Server, error) {
mux.HandleFunc("/api/todo/get", server.EndpointUserTodosGet) // Non specific
mux.HandleFunc("/api/todo/delete/", server.EndpointTodoDelete) // Specific
mux.HandleFunc("/api/todo/update/", server.EndpointTodoUpdate) // Specific
+ mux.HandleFunc("/api/todo/markdone/", server.EndpointTodoMarkDone) // Specific
mux.HandleFunc("/api/group/create", server.EndpointTodoGroupCreate) // Non specific
mux.HandleFunc("/api/group/get/", server.EndpointTodoGroupGet) // Specific
mux.HandleFunc("/api/group/update/", server.EndpointTodoGroupUpdate) // Specific