From 6414cd423352563d399012c8b6974453d4c77ae0 Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Mon, 19 Jun 2023 15:18:00 +0300 Subject: [PATCH] Fixed a disastrous misconfiguration in the API; progress towards displaying TODOs --- pages/about.html | 15 +++ pages/base.html | 15 ++- pages/index.html | 234 +++++++++++++++++++++++++++++++++++++++++-- pages/list.html | 9 -- src/db/todo.go | 62 ++++++++++-- src/db/user.go | 6 +- src/server/api.go | 61 +++++------ src/server/server.go | 2 +- 8 files changed, 332 insertions(+), 72 deletions(-) create mode 100644 pages/about.html delete mode 100644 pages/list.html diff --git a/pages/about.html b/pages/about.html new file mode 100644 index 0000000..9cf69cb --- /dev/null +++ b/pages/about.html @@ -0,0 +1,15 @@ +{{ template "base" . }} + +{{ define "content" }} +
+
+

Dela.

+

A free and open-source web TODO list

+

+ Login + Register +

+
+
+ +{{ end }} \ No newline at end of file diff --git a/pages/base.html b/pages/base.html index 8f3eb54..77a3b62 100644 --- a/pages/base.html +++ b/pages/base.html @@ -45,11 +45,14 @@ {{ end }} \ No newline at end of file diff --git a/pages/index.html b/pages/index.html index 9cf69cb..8c6f07d 100644 --- a/pages/index.html +++ b/pages/index.html @@ -1,15 +1,229 @@ {{ template "base" . }} {{ define "content" }} -
-
-

Dela.

-

A free and open-source web TODO list

-

- Login - Register -

-
-
+ + + + + +
+
+ + +
+
+ + +
+ +
+ +
+ +
+ +
+ +
+ + {{ end }} \ No newline at end of file diff --git a/pages/list.html b/pages/list.html deleted file mode 100644 index c20365c..0000000 --- a/pages/list.html +++ /dev/null @@ -1,9 +0,0 @@ -{{ template "base" . }} - -{{ define "content" }} - - - -{{ end }} \ No newline at end of file diff --git a/src/db/todo.go b/src/db/todo.go index 22902ee..4b43d40 100644 --- a/src/db/todo.go +++ b/src/db/todo.go @@ -4,20 +4,20 @@ import "database/sql" // Todo group structure type TodoGroup struct { - ID uint64 - Name string - TimeCreatedUnix uint64 - OwnerUsername string + ID uint64 `json: "id"` + Name string `json: "name"` + TimeCreatedUnix uint64 `json: "timeCreatedUnix` + OwnerUsername string `json: "ownerUsername` } // Todo structure type Todo struct { - ID uint64 - GroupID uint64 - Text string - TimeCreatedUnix uint64 - DueUnix uint64 - OwnerUsername string + ID uint64 `json: "id"` + GroupID uint64 `json: "groupId"` + Text string `json: "text"` + TimeCreatedUnix uint64 `json: "timeCreatedUnix"` + DueUnix uint64 `json: "dueUnix"` + OwnerUsername string `json: "ownerUsername"` } // Creates a new TODO group in the database @@ -67,6 +67,27 @@ func (db *DB) GetTodoGroup(id uint64) (*TodoGroup, error) { return todoGroup, nil } +// Retrieves information on ALL TODO groups +func (db *DB) GetTodoGroups() ([]*TodoGroup, error) { + var groups []*TodoGroup + + rows, err := db.Query("SELECT * FROM todo_groups") + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + todoGroup, err := scanTodoGroup(rows) + if err != nil { + return groups, err + } + groups = append(groups, todoGroup) + } + + return groups, nil +} + // Deletes information about a TODO group of given ID from the database func (db *DB) DeleteTodoGroup(id uint64) error { _, err := db.Exec( @@ -124,6 +145,27 @@ func (db *DB) GetTodo(id uint64) (*Todo, error) { return todo, nil } +// Retrieves information on ALL TODOs +func (db *DB) GetTodos() ([]*Todo, error) { + var todos []*Todo + + rows, err := db.Query("SELECT * FROM todos") + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + todo, err := scanTodo(rows) + if err != nil { + return todos, err + } + todos = append(todos, todo) + } + + return todos, nil +} + // Creates a new TODO in the database func (db *DB) CreateTodo(todo Todo) error { _, err := db.Exec( diff --git a/src/db/user.go b/src/db/user.go index 94bfe5c..95ae1c0 100644 --- a/src/db/user.go +++ b/src/db/user.go @@ -4,9 +4,9 @@ import "database/sql" // User structure type User struct { - Username string - Password string - TimeCreatedUnix uint64 + Username string `json: "username"` + Password string `json: "password"` + TimeCreatedUnix uint64 `json: "timeCreatedUnix"` } func scanUser(rows *sql.Rows) (*User, error) { diff --git a/src/server/api.go b/src/server/api.go index 9d359d8..eaa5193 100644 --- a/src/server/api.go +++ b/src/server/api.go @@ -89,6 +89,22 @@ func (s *Server) UserEndpoint(w http.ResponseWriter, req *http.Request) { return } + // Create an initial TODO group + err = s.db.CreateTodoGroup( + db.TodoGroup{ + Name: "Todos", + TimeCreatedUnix: uint64(time.Now().Unix()), + OwnerUsername: newUser.Username, + }, + ) + if err != nil { + // Oops, that's VERY bad. Delete newly created user + s.db.DeleteUser(newUser.Username) + logger.Error("[SERVER] Failed to create an initial TODO group for a newly created \"%s\": %s. Deleted.", newUser.Username, err) + http.Error(w, "Failed to create initial TODO group", http.StatusInternalServerError) + return + } + // Success! w.WriteHeader(http.StatusOK) logger.Info("[Server] Created a new user \"%s\"", newUser.Username) @@ -190,41 +206,29 @@ func (s *Server) TodoEndpoint(w http.ResponseWriter, req *http.Request) { logger.Info("[Server] Created a new TODO for %s", newTodo.OwnerUsername) case http.MethodGet: // Retrieve TODO information - // Check authentication information if !IsRequestAuthValid(req, s.db) { http.Error(w, "Invalid user auth data", http.StatusForbidden) return } - todoID, err := GetTodoIDFromReq(req) - if err != nil { - http.Error(w, "Invalid TODO ID", http.StatusBadRequest) - return - } - - if !DoesUserOwnTodo(GetUsernameFromAuth(req), todoID, s.db) { - http.Error(w, "You don't own this TODO", http.StatusForbidden) - return - } - // Get TODO - todo, err := s.db.GetTodo(todoID) + todos, err := s.db.GetAllUserTodos(GetUsernameFromAuth(req)) if err != nil { - http.Error(w, "Failed to get TODO", http.StatusInternalServerError) + http.Error(w, "Failed to get TODOs", http.StatusInternalServerError) return } // Marshal to JSON - todoBytes, err := json.Marshal(&todo) + todosBytes, err := json.Marshal(&todos) if err != nil { - http.Error(w, "Failed to marhsal TODO JSON", http.StatusInternalServerError) + http.Error(w, "Failed to marhsal TODOs JSON", http.StatusInternalServerError) return } // Send out w.Header().Add("Content-Type", "application/json") - w.Write(todoBytes) + w.Write(todosBytes) case http.MethodPatch: // Change TODO due date and text @@ -350,7 +354,7 @@ func (s *Server) TodoGroupEndpoint(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) logger.Info("[Server] Created a new TODO group for %s", newGroup.OwnerUsername) case http.MethodGet: - // Retrieve todo group + // Retrieve all todo groups // Check authentication information if !IsRequestAuthValid(req, s.db) { @@ -358,28 +362,17 @@ func (s *Server) TodoGroupEndpoint(w http.ResponseWriter, req *http.Request) { return } - groupID, err := GetTodoIDFromReq(req) - if err != nil { - http.Error(w, "Invalid group ID", http.StatusBadRequest) - return - } - - if !DoesUserOwnTodoGroup(GetUsernameFromAuth(req), groupID, s.db) { - http.Error(w, "You don't own this group", http.StatusForbidden) - return - } - - // Get group - group, err := s.db.GetTodoGroup(groupID) + // Get groups + groups, err := s.db.GetAllUserTodoGroups(GetUsernameFromAuth(req)) if err != nil { - http.Error(w, "Failed to get TODO group", http.StatusInternalServerError) + http.Error(w, "Failed to get TODO groups", http.StatusInternalServerError) return } // Marshal to JSON - groupBytes, err := json.Marshal(&group) + groupBytes, err := json.Marshal(&groups) if err != nil { - http.Error(w, "Failed to marhsal TODO group JSON", http.StatusInternalServerError) + http.Error(w, "Failed to marhsal TODO groups JSON", http.StatusInternalServerError) return } diff --git a/src/server/server.go b/src/server/server.go index 546973e..cd547ce 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -125,7 +125,7 @@ func New(config conf.Conf) (*Server, error) { }) mux.HandleFunc("/api/user", server.UserEndpoint) mux.HandleFunc("/api/todo", server.TodoEndpoint) - mux.HandleFunc("/api/groups", server.TodoGroupEndpoint) + mux.HandleFunc("/api/group", server.TodoGroupEndpoint) server.http.Handler = mux logger.Info("[Server] Created an HTTP server instance")