From 47cc246e953a236dd41e5ee4c58f0210174f9c18 Mon Sep 17 00:00:00 2001 From: jesperkha Date: Sat, 28 Jun 2025 20:34:36 +0200 Subject: [PATCH 1/9] Create Service --- api/database/database.go | 14 ++---- api/database/model.go | 29 +++-------- api/database/query.go | 23 ++------- api/database/turso.go | 2 +- api/service/service.go | 103 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 51 deletions(-) diff --git a/api/database/database.go b/api/database/database.go index 46ed36a..2cb5973 100644 --- a/api/database/database.go +++ b/api/database/database.go @@ -1,6 +1,8 @@ package database type Database interface { + // Username must be identical to GitHub username. + CreateUser(displayName, githubUsername string) error GetUserById(id uint) (User, error) DeleteUserById(id uint) error GetAllUsers() ([]User, error) @@ -9,14 +11,6 @@ type Database interface { CreateItem(item Item) error GetAllItems() ([]Item, error) DeleteItemByID(id uint) error - GetAllItemsFromLits(list List) ([]Item, error) - MoveItemToList(id uint, list List) error - ChangeItemTitle(id uint, title string) error - ChangeItemDescription(id uint, description string) error - - CreateNewRepo(name, url string) error - DeleteRepoById(id uint) error - - // Username must be identical to GitHub username. - CreateUser(username string) error + GetAllItemsFromLits(list uint) ([]Item, error) + MoveItemToList(id uint, list uint) error } diff --git a/api/database/model.go b/api/database/model.go index 0af3117..276f1ee 100644 --- a/api/database/model.go +++ b/api/database/model.go @@ -4,37 +4,24 @@ import ( "gorm.io/gorm" ) -type List int - -const ( - BACKLOG = iota - TODO - DOING - REVIEW - DONE -) +type Board struct { + gorm.Model +} type Item struct { gorm.Model - RepoID uint - Repo Repo + RepoName string + RepoURL string Title string Description string - CreatorID uint Creator User - AssigneeID uint Assignee User ConnectedBranch string - List List + List uint } type User struct { gorm.Model - Name string -} - -type Repo struct { - gorm.Model - Name string - URL string + DisplayName string + GithubUsername string } diff --git a/api/database/query.go b/api/database/query.go index 4dc0883..8352bb8 100644 --- a/api/database/query.go +++ b/api/database/query.go @@ -12,8 +12,8 @@ func (db *tursoDB) GetUserById(id uint) (User, error) { return user, nil } -func (db *tursoDB) CreateUser(name string) error { - if res := db.db.Create(User{Name: name}); res.Error != nil { +func (db *tursoDB) CreateUser(displayName, githubUsername string) error { + if res := db.db.Create(User{DisplayName: displayName, GithubUsername: githubUsername}); res.Error != nil { return errors.New("could not create a new user") } return nil @@ -64,7 +64,7 @@ func (db *tursoDB) DeleteItemByID(id uint) error { return nil } -func (db *tursoDB) GetAllItemsFromLits(list List) ([]Item, error) { +func (db *tursoDB) GetAllItemsFromLits(list uint) ([]Item, error) { var items []Item if res := db.db.Find(&items, "list = ?", list); res.Error != nil { return nil, errors.New("could not find all items from list") @@ -72,7 +72,7 @@ func (db *tursoDB) GetAllItemsFromLits(list List) ([]Item, error) { return items, nil } -func (db *tursoDB) MoveItemToList(id uint, list List) error { +func (db *tursoDB) MoveItemToList(id uint, list uint) error { if res := db.db.Model(&Item{}).Where("id = ?", id).Update("list", list); res.Error != nil { return errors.New("could not move item") } @@ -92,18 +92,3 @@ func (db *tursoDB) ChangeItemDescription(id uint, description string) error { } return nil } - -func (db *tursoDB) CreateNewRepo(name, url string) error { - repo := Repo{Name: name, URL: url} - if res := db.db.Create(&repo); res.Error != nil { - return errors.New("could not create new user") - } - return nil -} - -func (db *tursoDB) DeleteRepoById(id uint) error { - if res := db.db.Delete(&Repo{}, id); res.Error != nil { - return errors.New("could not delet the repo") - } - return nil -} diff --git a/api/database/turso.go b/api/database/turso.go index e3656b8..1063569 100644 --- a/api/database/turso.go +++ b/api/database/turso.go @@ -32,7 +32,7 @@ func NewTursoDB(config *config.Config) Database { log.Fatal("could not load remote database", err) } - if err := db.AutoMigrate(&Item{}, &User{}, &Repo{}); err != nil { + if err := db.AutoMigrate(&Item{}, &User{}, &Board{}); err != nil { log.Fatalf("migration: %v", err) } return &tursoDB{db} diff --git a/api/service/service.go b/api/service/service.go index bb172b3..f0afea8 100644 --- a/api/service/service.go +++ b/api/service/service.go @@ -16,3 +16,106 @@ func New(config *config.Config) *Service { database.NewTursoDB(config), } } + +// Get all users across all boards. +func (s *Service) GetAllUsers() (users []database.User, err error) { + return users, err +} + +// Create new user from object. Returns id of created user. +func (s *Service) CreateUser(user database.User) (id uint, err error) { + return id, err +} + +// Get a user by its ID. +func (s *Service) GetUserById(id uint) (user database.User, err error) { + return user, nil +} + +// Update a user. All values are updated to those given. +func (s *Service) UpdateUser(id uint, user database.User) error { + return nil +} + +// Delete user and remove it from all boards. +func (s *Service) DeleteUser(id uint) error { + return nil +} + +// Get a list of all boards. +func (s *Service) GetAllBoards() (boards []database.Board, err error) { + return boards, err +} + +// Create a new board from object. Returns ID of created board. +func (s *Service) CreateBoard(board database.Board) (id uint, err error) { + return id, err +} + +// Gets a board by its ID. +func (s *Service) GetBoardById(id uint) (board database.Board, err error) { + return board, err +} + +// Update a board. All values are updated to those given. +func (s *Service) UpdateBoard(id uint, board database.Board) error { + return nil +} + +// Delete a board. +func (s *Service) DeleteBoard(id uint) error { + return nil +} + +// Get all users in the board. +func (s *Service) GetUsersInBoard(id uint) (users []database.User, err error) { + return users, err +} + +// Get all items in the board. +func (s *Service) GetItemsInBoard(id uint) (items []database.Item, err error) { + return items, err +} + +// Add an existing user to a board. +func (s *Service) AddUserToBoard(boardId, userId uint) error { + return nil +} + +// Remove an existing user from a board. +func (s *Service) RemoveUserFromBoard(boardId, userId uint) error { + return nil +} + +// Get all items in given list in board. +func (s *Service) GetAllItemsInList(boardId, listId uint) (items []database.Item, err error) { + return items, err +} + +// Get all items across all boards. +func (s *Service) GetAllItems() (items []database.Item, err error) { + return items, err +} + +// Create new item from object. Returns id of created item. +func (s *Service) CreateItem(item database.Item) (id uint, err error) { + return id, err +} + +func (s *Service) GetItemById(id uint) (item database.Item, err error) { + return item, err +} + +// Update an existing item. +func (s *Service) UpdateItem(item database.Item) error { + return nil +} + +func (s *Service) DeleteItem(id uint) error { + return nil +} + +// Move an item to another list. +func (s *Service) MoveItem(id, list uint) error { + return nil +} From 3673213edaa2e59d9c6906a27bf30b309372432b Mon Sep 17 00:00:00 2001 From: jesperkha Date: Sat, 28 Jun 2025 21:38:50 +0200 Subject: [PATCH 2/9] Remove Service and update models --- api/cmd/main.go | 6 +- api/database/database.go | 15 ++--- api/database/model.go | 36 +++++++----- api/database/query.go | 10 ++-- api/server/server.go | 4 +- api/service/service.go | 121 --------------------------------------- 6 files changed, 40 insertions(+), 152 deletions(-) delete mode 100644 api/service/service.go diff --git a/api/cmd/main.go b/api/cmd/main.go index d9cd685..98ae76f 100644 --- a/api/cmd/main.go +++ b/api/cmd/main.go @@ -5,16 +5,16 @@ import ( "syscall" "github.com/echo-webkom/ludo/api/config" + "github.com/echo-webkom/ludo/api/database" "github.com/echo-webkom/ludo/api/server" - "github.com/echo-webkom/ludo/api/service" "github.com/jesperkha/notifier" ) func main() { config := config.Load() notif := notifier.New() - service := service.New(config) - server := server.New(config, service) + db := database.NewTursoDB(config) + server := server.New(config, db) go server.ListenAndServe(notif) diff --git a/api/database/database.go b/api/database/database.go index 2cb5973..54cb6bf 100644 --- a/api/database/database.go +++ b/api/database/database.go @@ -1,16 +1,17 @@ package database type Database interface { - // Username must be identical to GitHub username. - CreateUser(displayName, githubUsername string) error + GetAllUsers() ([]User, error) + // Create new user, returns its ID. + CreateUser(user User) (id uint, err error) GetUserById(id uint) (User, error) + // Delete a user and remove it from all boards. DeleteUserById(id uint) error - GetAllUsers() ([]User, error) - - GetItemById(id uint) (Item, error) - CreateItem(item Item) error GetAllItems() ([]Item, error) + // Create new item, returns its ID. + CreateItem(item Item) error + GetItemById(id uint) (Item, error) DeleteItemByID(id uint) error - GetAllItemsFromLits(list uint) ([]Item, error) + GetAllItemsFromList(boardId, list uint) ([]Item, error) MoveItemToList(id uint, list uint) error } diff --git a/api/database/model.go b/api/database/model.go index 276f1ee..6cf7436 100644 --- a/api/database/model.go +++ b/api/database/model.go @@ -1,27 +1,35 @@ package database import ( - "gorm.io/gorm" + "time" ) +type model struct { + ID uint `gorm:"primarykey" json:"id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + type Board struct { - gorm.Model + model + Items []Item `json:"items"` + Users []User `gorm:"many2many:board_users;" json:"users"` } type Item struct { - gorm.Model - RepoName string - RepoURL string - Title string - Description string - Creator User - Assignee User - ConnectedBranch string - List uint + model + RepoName string `json:"repoName"` + RepoURL string `json:"repoURL"` + Title string `json:"title"` + Description string `json:"description"` + ConnectedBranch string `json:"connectedBranch"` + List uint `json:"list"` + Creator User `gorm:"many2many:item_user;" json:"creator"` + Assignee User `gorm:"many2many:item_user;" json:"assignee"` } type User struct { - gorm.Model - DisplayName string - GithubUsername string + model + DisplayName string `json:"displayName"` + GithubUsername string `json:"githubUsername"` } diff --git a/api/database/query.go b/api/database/query.go index 8352bb8..dd107f9 100644 --- a/api/database/query.go +++ b/api/database/query.go @@ -12,11 +12,11 @@ func (db *tursoDB) GetUserById(id uint) (User, error) { return user, nil } -func (db *tursoDB) CreateUser(displayName, githubUsername string) error { - if res := db.db.Create(User{DisplayName: displayName, GithubUsername: githubUsername}); res.Error != nil { - return errors.New("could not create a new user") +func (db *tursoDB) CreateUser(user User) (uint, error) { + if res := db.db.Create(&user); res.Error != nil { + return 0, errors.New("could not create a new user") } - return nil + return user.ID, nil } func (db *tursoDB) DeleteUserById(id uint) error { @@ -64,7 +64,7 @@ func (db *tursoDB) DeleteItemByID(id uint) error { return nil } -func (db *tursoDB) GetAllItemsFromLits(list uint) ([]Item, error) { +func (db *tursoDB) GetAllItemsFromList(boardId, list uint) ([]Item, error) { var items []Item if res := db.db.Find(&items, "list = ?", list); res.Error != nil { return nil, errors.New("could not find all items from list") diff --git a/api/server/server.go b/api/server/server.go index 456393e..b4825ab 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/echo-webkom/ludo/api/config" - "github.com/echo-webkom/ludo/api/service" + "github.com/echo-webkom/ludo/api/database" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/jesperkha/notifier" @@ -17,7 +17,7 @@ type Server struct { router http.Handler } -func New(config *config.Config, service *service.Service) *Server { +func New(config *config.Config, db database.Database) *Server { r := chi.NewRouter() r.Use(middleware.Logger) diff --git a/api/service/service.go b/api/service/service.go deleted file mode 100644 index f0afea8..0000000 --- a/api/service/service.go +++ /dev/null @@ -1,121 +0,0 @@ -package service - -import ( - "github.com/echo-webkom/ludo/api/config" - "github.com/echo-webkom/ludo/api/database" -) - -type Service struct { - config *config.Config - db database.Database -} - -func New(config *config.Config) *Service { - return &Service{ - config, - database.NewTursoDB(config), - } -} - -// Get all users across all boards. -func (s *Service) GetAllUsers() (users []database.User, err error) { - return users, err -} - -// Create new user from object. Returns id of created user. -func (s *Service) CreateUser(user database.User) (id uint, err error) { - return id, err -} - -// Get a user by its ID. -func (s *Service) GetUserById(id uint) (user database.User, err error) { - return user, nil -} - -// Update a user. All values are updated to those given. -func (s *Service) UpdateUser(id uint, user database.User) error { - return nil -} - -// Delete user and remove it from all boards. -func (s *Service) DeleteUser(id uint) error { - return nil -} - -// Get a list of all boards. -func (s *Service) GetAllBoards() (boards []database.Board, err error) { - return boards, err -} - -// Create a new board from object. Returns ID of created board. -func (s *Service) CreateBoard(board database.Board) (id uint, err error) { - return id, err -} - -// Gets a board by its ID. -func (s *Service) GetBoardById(id uint) (board database.Board, err error) { - return board, err -} - -// Update a board. All values are updated to those given. -func (s *Service) UpdateBoard(id uint, board database.Board) error { - return nil -} - -// Delete a board. -func (s *Service) DeleteBoard(id uint) error { - return nil -} - -// Get all users in the board. -func (s *Service) GetUsersInBoard(id uint) (users []database.User, err error) { - return users, err -} - -// Get all items in the board. -func (s *Service) GetItemsInBoard(id uint) (items []database.Item, err error) { - return items, err -} - -// Add an existing user to a board. -func (s *Service) AddUserToBoard(boardId, userId uint) error { - return nil -} - -// Remove an existing user from a board. -func (s *Service) RemoveUserFromBoard(boardId, userId uint) error { - return nil -} - -// Get all items in given list in board. -func (s *Service) GetAllItemsInList(boardId, listId uint) (items []database.Item, err error) { - return items, err -} - -// Get all items across all boards. -func (s *Service) GetAllItems() (items []database.Item, err error) { - return items, err -} - -// Create new item from object. Returns id of created item. -func (s *Service) CreateItem(item database.Item) (id uint, err error) { - return id, err -} - -func (s *Service) GetItemById(id uint) (item database.Item, err error) { - return item, err -} - -// Update an existing item. -func (s *Service) UpdateItem(item database.Item) error { - return nil -} - -func (s *Service) DeleteItem(id uint) error { - return nil -} - -// Move an item to another list. -func (s *Service) MoveItem(id, list uint) error { - return nil -} From fc6df85ed3fc5ff96c03215d8716f6ff0b3d625c Mon Sep 17 00:00:00 2001 From: Zeno Date: Sat, 28 Jun 2025 20:35:46 +0200 Subject: [PATCH 3/9] add handler --- api/server/handler.go | 107 ++++++++++++++++++++++++++++++++++++++++++ api/server/server.go | 2 + 2 files changed, 109 insertions(+) diff --git a/api/server/handler.go b/api/server/handler.go index c976032..faf5400 100644 --- a/api/server/handler.go +++ b/api/server/handler.go @@ -1,7 +1,13 @@ package server import ( + "encoding/json" + "io" "net/http" + "strconv" + + "github.com/echo-webkom/ludo/api/database" + "github.com/go-chi/chi/v5" ) func pingHandler() http.HandlerFunc { @@ -9,3 +15,104 @@ func pingHandler() http.HandlerFunc { w.Write([]byte("pong")) } } + +func usersRouter() *chi.Mux { + router := chi.NewRouter() + router.Get("/", func(w http.ResponseWriter, r *http.Request) { + // service.GetAllUser() + }) + + router.Post("/", func(w http.ResponseWriter, r *http.Request) { + b, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "failed to read body", http.StatusInternalServerError) + } + + var user database.User + if err := json.Unmarshal(b, &user); err != nil { + http.Error(w, "invalid user data", http.StatusBadRequest) + return + } + // service.CreateUser(User) + }) + + router.Get("/{userId}", func(w http.ResponseWriter, r *http.Request) { + userIdString := r.PathValue("userId") + userId, err := strconv.Atoi(userIdString) + + if err != nil && userId < 0 { + http.Error(w, "not a valid user id", http.StatusBadRequest) + return + } + + // service.GetUserById(userId) + + }) + + router.Delete("/{userId}", func(w http.ResponseWriter, r *http.Request) { + userIdString := r.PathValue("userId") + + userId, err := strconv.Atoi(userIdString) + if err != nil && userId < 0 { + http.Error(w, "not a valid user id", http.StatusBadRequest) + return + } + // service.DeleteUserById(userId) + }) + + router.Patch("/{userId}", func(w http.ResponseWriter, r *http.Request) { + userIdString := r.PathValue("userId") + + userId, err := strconv.Atoi(userIdString) + if err != nil && userId < 0 { + http.Error(w, "not a valid user id", http.StatusBadRequest) + return + } + + b, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "failed to read body", http.StatusInternalServerError) + } + + var user database.User + if err := json.Unmarshal(b, &user); err != nil { + http.Error(w, "invalid user data", http.StatusBadRequest) + return + } + // service.updateUser(user) + + }) + return router +} + + +func itemRouter() *chi.Mux { + router := chi.NewRouter() + router.Get("/", func(w http.ResponseWriter, r *http.Request) { + // services.getAllItems() + }) + + router.Post("/", func(w http.ResponseWriter, r *http.Request) { + b, err := io.ReadAll((r.Body)) + if err != nil { + http.Error(w, "invalid item data", http.StatusBadGateway) + } + + var item database.Item + if err := json.Unmarshal(b, &item); err != nil { + http.Error(w, "invalid item data", http.StatusBadRequest) + return + } + + // service.createItem(item) + }) + + router.Delete("/{itemId}", func(w http.ResponseWriter, r *http.Request) { + + }) + + + return router +} + + diff --git a/api/server/server.go b/api/server/server.go index b4825ab..0ae79f2 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -22,6 +22,8 @@ func New(config *config.Config, db database.Database) *Server { r.Use(middleware.Logger) r.Get("/ping", pingHandler()) + r.Mount("/users", usersRouter()) + return &Server{ router: r, From a174e75522fb9de393f0ddcaad617643402c8fae Mon Sep 17 00:00:00 2001 From: Zeno Date: Sat, 28 Jun 2025 21:46:09 +0200 Subject: [PATCH 4/9] add more handler --- api/server/handler.go | 93 +++++++++++++++++++++++++++++++++++-------- api/server/server.go | 2 +- 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/api/server/handler.go b/api/server/handler.go index faf5400..00cb8a1 100644 --- a/api/server/handler.go +++ b/api/server/handler.go @@ -7,25 +7,47 @@ import ( "strconv" "github.com/echo-webkom/ludo/api/database" + "github.com/echo-webkom/ludo/api/service" "github.com/go-chi/chi/v5" ) +type ResponseId struct { + ID uint `json:"id"` +} + +func JSON(w http.ResponseWriter, data any) { + resp, err := json.Marshal(&data) + if err != nil { + http.Error(w, "parse error", http.StatusInternalServerError) + return + } + + w.Write(resp) +} + func pingHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("pong")) } } -func usersRouter() *chi.Mux { +func usersRouter(service *service.Service) *chi.Mux { router := chi.NewRouter() + router.Get("/", func(w http.ResponseWriter, r *http.Request) { - // service.GetAllUser() + users, err := service.GetAllUsers() + if err != nil { + http.Error(w, "failed to get all users", http.StatusNotFound) + return + } + JSON(w, users) }) router.Post("/", func(w http.ResponseWriter, r *http.Request) { b, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "failed to read body", http.StatusInternalServerError) + return } var user database.User @@ -33,38 +55,53 @@ func usersRouter() *chi.Mux { http.Error(w, "invalid user data", http.StatusBadRequest) return } - // service.CreateUser(User) + id, err := service.CreateUser(user) + if err != nil { + http.Error(w, "database error", http.StatusInternalServerError) + return + } + + res := ResponseId{id} + JSON(w, res) }) router.Get("/{userId}", func(w http.ResponseWriter, r *http.Request) { userIdString := r.PathValue("userId") userId, err := strconv.Atoi(userIdString) - if err != nil && userId < 0 { + if err != nil || userId < 0 { http.Error(w, "not a valid user id", http.StatusBadRequest) return } - // service.GetUserById(userId) - + user, err := service.GetUserById(uint(userId)) + if err != nil { + http.Error(w, "could not find user", http.StatusNotFound) + return + } + JSON(w, user) }) router.Delete("/{userId}", func(w http.ResponseWriter, r *http.Request) { userIdString := r.PathValue("userId") userId, err := strconv.Atoi(userIdString) - if err != nil && userId < 0 { + if err != nil || userId < 0 { http.Error(w, "not a valid user id", http.StatusBadRequest) return } - // service.DeleteUserById(userId) + + if err := service.DeleteUser(uint(userId)); err != nil { + http.Error(w, "not valid user id", http.StatusNotFound) + return + } }) router.Patch("/{userId}", func(w http.ResponseWriter, r *http.Request) { userIdString := r.PathValue("userId") userId, err := strconv.Atoi(userIdString) - if err != nil && userId < 0 { + if err != nil || userId < 0 { http.Error(w, "not a valid user id", http.StatusBadRequest) return } @@ -72,6 +109,7 @@ func usersRouter() *chi.Mux { b, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "failed to read body", http.StatusInternalServerError) + return } var user database.User @@ -79,23 +117,29 @@ func usersRouter() *chi.Mux { http.Error(w, "invalid user data", http.StatusBadRequest) return } - // service.updateUser(user) + + service.UpdateUser(uint(userId), user) }) return router } - -func itemRouter() *chi.Mux { +func itemRouter(service *service.Service) *chi.Mux { router := chi.NewRouter() router.Get("/", func(w http.ResponseWriter, r *http.Request) { - // services.getAllItems() + items, err := service.GetAllItems() + if err != nil { + http.Error(w, "could not find items", http.StatusNotFound) + return + } + JSON(w, items) }) router.Post("/", func(w http.ResponseWriter, r *http.Request) { b, err := io.ReadAll((r.Body)) if err != nil { http.Error(w, "invalid item data", http.StatusBadGateway) + return } var item database.Item @@ -104,15 +148,30 @@ func itemRouter() *chi.Mux { return } - // service.createItem(item) + itemId, err := service.CreateItem(item) + if err != nil { + http.Error(w, "database error", http.StatusInternalServerError) + return + } + + res := ResponseId{itemId} + JSON(w, res) }) router.Delete("/{itemId}", func(w http.ResponseWriter, r *http.Request) { + itemIdString := r.PathValue("itemId") + itemId, err := strconv.Atoi(itemIdString) + if err != nil || itemId < 0{ + http.Error(w, "not valid item id", http.StatusBadRequest) + } - }) + if err := service.DeleteItem(uint(itemId)); err != nil { + http.Error(w, "could not delet item", http.StatusBadRequest) + } + + + }) return router } - - diff --git a/api/server/server.go b/api/server/server.go index 0ae79f2..6761ce8 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -22,7 +22,7 @@ func New(config *config.Config, db database.Database) *Server { r.Use(middleware.Logger) r.Get("/ping", pingHandler()) - r.Mount("/users", usersRouter()) + r.Mount("/users", usersRouter(service)) return &Server{ From 753b7b611d7efb3f82f3e6c2158e729ea54a7048 Mon Sep 17 00:00:00 2001 From: Zeno Date: Sat, 28 Jun 2025 22:47:09 +0200 Subject: [PATCH 5/9] fix item update --- api/database/query.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/api/database/query.go b/api/database/query.go index dd107f9..d2b0409 100644 --- a/api/database/query.go +++ b/api/database/query.go @@ -12,6 +12,10 @@ func (db *tursoDB) GetUserById(id uint) (User, error) { return user, nil } +func (db *tursoDB) UpdateUser(id uint, user User) error { + return nil +} + func (db *tursoDB) CreateUser(user User) (uint, error) { if res := db.db.Create(&user); res.Error != nil { return 0, errors.New("could not create a new user") @@ -42,11 +46,11 @@ func (db *tursoDB) GetItemById(id uint) (Item, error) { return item, nil } -func (db *tursoDB) CreateItem(item Item) error { +func (db *tursoDB) CreateItem(item Item) (uint, error) { if res := db.db.Create(&item); res.Error != nil { - return errors.New("could not create item") + return 0, errors.New("could not create item") } - return nil + return item.ID, nil } func (db *tursoDB) GetAllItems() ([]Item, error) { @@ -79,16 +83,9 @@ func (db *tursoDB) MoveItemToList(id uint, list uint) error { return nil } -func (db *tursoDB) ChangeItemTitle(id uint, title string) error { - if res := db.db.Model(&Item{}).Where("id = ?", id).Update("title", title); res.Error != nil { - return errors.New("could not change item title") +func (db *tursoDB) UpdateItem(id uint, item Item) error { + if res := db.db.Model(&item).Where("id = ?", id).Updates(item); res.Error != nil { + return errors.New("could not update item") } return nil -} - -func (db *tursoDB) ChangeItemDescription(id uint, description string) error { - if res := db.db.Model(&Item{}).Where("id = ?", id).Update("description", description); res.Error != nil { - return errors.New("could not change item description") - } - return nil -} +} \ No newline at end of file From 618c7757215896b779e31d97809ae5728c35f8f1 Mon Sep 17 00:00:00 2001 From: Zeno Date: Sat, 28 Jun 2025 22:49:02 +0200 Subject: [PATCH 6/9] update interface --- api/database/database.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/database/database.go b/api/database/database.go index 54cb6bf..7379feb 100644 --- a/api/database/database.go +++ b/api/database/database.go @@ -9,9 +9,11 @@ type Database interface { DeleteUserById(id uint) error GetAllItems() ([]Item, error) // Create new item, returns its ID. - CreateItem(item Item) error + CreateItem(item Item) (uint, error) GetItemById(id uint) (Item, error) DeleteItemByID(id uint) error GetAllItemsFromList(boardId, list uint) ([]Item, error) MoveItemToList(id uint, list uint) error + UpdateUser(id uint, user User) error + UpdateItem(id uint, item Item) error } From 1fbab0eaa058ff8eb402a682d986bca5f6eb3181 Mon Sep 17 00:00:00 2001 From: Zeno Date: Sat, 28 Jun 2025 23:04:43 +0200 Subject: [PATCH 7/9] add item handlers --- api/server/handler.go | 106 ++++++++++++++++++++++++++++++++---------- api/server/server.go | 5 +- 2 files changed, 85 insertions(+), 26 deletions(-) diff --git a/api/server/handler.go b/api/server/handler.go index 00cb8a1..d430b7d 100644 --- a/api/server/handler.go +++ b/api/server/handler.go @@ -7,7 +7,6 @@ import ( "strconv" "github.com/echo-webkom/ludo/api/database" - "github.com/echo-webkom/ludo/api/service" "github.com/go-chi/chi/v5" ) @@ -25,17 +24,27 @@ func JSON(w http.ResponseWriter, data any) { w.Write(resp) } +func getId(w http.ResponseWriter, id string) uint { + itemId, err := strconv.Atoi(id) + if err != nil || itemId < 0 { + http.Error(w, "not valid item id", http.StatusBadRequest) + return 0 + } + + return uint(itemId) +} + func pingHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("pong")) } } -func usersRouter(service *service.Service) *chi.Mux { +func usersRouter(db database.Database) *chi.Mux { router := chi.NewRouter() router.Get("/", func(w http.ResponseWriter, r *http.Request) { - users, err := service.GetAllUsers() + users, err := db.GetAllUsers() if err != nil { http.Error(w, "failed to get all users", http.StatusNotFound) return @@ -45,6 +54,8 @@ func usersRouter(service *service.Service) *chi.Mux { router.Post("/", func(w http.ResponseWriter, r *http.Request) { b, err := io.ReadAll(r.Body) + defer r.Body.Close() + if err != nil { http.Error(w, "failed to read body", http.StatusInternalServerError) return @@ -55,7 +66,7 @@ func usersRouter(service *service.Service) *chi.Mux { http.Error(w, "invalid user data", http.StatusBadRequest) return } - id, err := service.CreateUser(user) + id, err := db.CreateUser(user) if err != nil { http.Error(w, "database error", http.StatusInternalServerError) return @@ -74,7 +85,7 @@ func usersRouter(service *service.Service) *chi.Mux { return } - user, err := service.GetUserById(uint(userId)) + user, err := db.GetUserById(uint(userId)) if err != nil { http.Error(w, "could not find user", http.StatusNotFound) return @@ -91,7 +102,7 @@ func usersRouter(service *service.Service) *chi.Mux { return } - if err := service.DeleteUser(uint(userId)); err != nil { + if err := db.DeleteUserById(uint(userId)); err != nil { http.Error(w, "not valid user id", http.StatusNotFound) return } @@ -100,13 +111,10 @@ func usersRouter(service *service.Service) *chi.Mux { router.Patch("/{userId}", func(w http.ResponseWriter, r *http.Request) { userIdString := r.PathValue("userId") - userId, err := strconv.Atoi(userIdString) - if err != nil || userId < 0 { - http.Error(w, "not a valid user id", http.StatusBadRequest) - return - } + userId := getId(w, userIdString) b, err := io.ReadAll(r.Body) + defer r.Body.Close() if err != nil { http.Error(w, "failed to read body", http.StatusInternalServerError) return @@ -118,16 +126,18 @@ func usersRouter(service *service.Service) *chi.Mux { return } - service.UpdateUser(uint(userId), user) + if err := db.UpdateUser(userId, user); err != nil { + http.Error(w, "could not update user", http.StatusInternalServerError) + } }) return router } -func itemRouter(service *service.Service) *chi.Mux { +func itemRouter(db database.Database) *chi.Mux { router := chi.NewRouter() router.Get("/", func(w http.ResponseWriter, r *http.Request) { - items, err := service.GetAllItems() + items, err := db.GetAllItems() if err != nil { http.Error(w, "could not find items", http.StatusNotFound) return @@ -136,7 +146,8 @@ func itemRouter(service *service.Service) *chi.Mux { }) router.Post("/", func(w http.ResponseWriter, r *http.Request) { - b, err := io.ReadAll((r.Body)) + b, err := io.ReadAll(r.Body) + defer r.Body.Close() if err != nil { http.Error(w, "invalid item data", http.StatusBadGateway) return @@ -148,30 +159,77 @@ func itemRouter(service *service.Service) *chi.Mux { return } - itemId, err := service.CreateItem(item) + itemId, err := db.CreateItem(item) if err != nil { http.Error(w, "database error", http.StatusInternalServerError) return } res := ResponseId{itemId} - JSON(w, res) + JSON(w, res) }) - router.Delete("/{itemId}", func(w http.ResponseWriter, r *http.Request) { + router.Get("/{itemId}", func(w http.ResponseWriter, r *http.Request) { itemIdString := r.PathValue("itemId") - itemId, err := strconv.Atoi(itemIdString) - if err != nil || itemId < 0{ - http.Error(w, "not valid item id", http.StatusBadRequest) + itemId := getId(w, itemIdString) + + item, err := db.GetItemById(uint(itemId)) + if err != nil { + http.Error(w, "could not find item", http.StatusBadRequest) + return } - - if err := service.DeleteItem(uint(itemId)); err != nil { + JSON(w, item) + }) + + router.Patch("/{itemId}", func(w http.ResponseWriter, r *http.Request) { + + }) + + router.Delete("/{itemId}", func(w http.ResponseWriter, r *http.Request) { + itemIdString := r.PathValue("itemId") + itemId := getId(w, itemIdString) + + if err := db.DeleteItemByID(uint(itemId)); err != nil { http.Error(w, "could not delet item", http.StatusBadRequest) + return + } + }) + + router.Patch("/{itemId}", func(w http.ResponseWriter, r *http.Request) { + itemIdString := r.PathValue("itemId") + itemId := getId(w, itemIdString) + + b, err := io.ReadAll(r.Body) + defer r.Body.Close() + if err != nil { + http.Error(w, "could not find user", http.StatusInternalServerError) } - + var item database.Item + if err := json.Unmarshal(b, &item); err != nil { + http.Error(w, "invalid item data", http.StatusBadRequest) + } + if err := db.UpdateItem(itemId, item); err != nil { + http.Error(w, "could not update item", http.StatusInternalServerError) + } + }) + + + router.Patch("/{itemId}/move/{listId}", func(w http.ResponseWriter, r *http.Request) { + itemIdString := r.PathValue("itemId") + listIdString := r.PathValue("listId") + + itemId := getId(w, itemIdString) + listId := getId(w, listIdString) + + if err := db.MoveItemToList(itemId, listId); err != nil { + http.Error(w, "could not move item to list", http.StatusInternalServerError) + } }) return router } + + + diff --git a/api/server/server.go b/api/server/server.go index 6761ce8..58ae95e 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -22,8 +22,9 @@ func New(config *config.Config, db database.Database) *Server { r.Use(middleware.Logger) r.Get("/ping", pingHandler()) - r.Mount("/users", usersRouter(service)) - + r.Mount("/users", usersRouter(db)) + r.Mount("/items", itemRouter(db)) + return &Server{ router: r, From 126c1c79ff2c7d842ec6556c44e6f373614a0894 Mon Sep 17 00:00:00 2001 From: Zeno Date: Sun, 29 Jun 2025 22:55:56 +0200 Subject: [PATCH 8/9] more qurey more handler --- api/database/database.go | 5 ++ api/database/query.go | 40 ++++++++++++++ api/server/handler.go | 110 +++++++++++++++++++++++++++++++++++++-- api/server/server.go | 2 +- 4 files changed, 153 insertions(+), 4 deletions(-) diff --git a/api/database/database.go b/api/database/database.go index 7379feb..c8899fa 100644 --- a/api/database/database.go +++ b/api/database/database.go @@ -16,4 +16,9 @@ type Database interface { MoveItemToList(id uint, list uint) error UpdateUser(id uint, user User) error UpdateItem(id uint, item Item) error + GetAllBoards() ([]Board, error) + CreateBoard(board Board) (uint, error) + GetBoardById(id uint) (Board, error) + UpdateBoard(id uint, board Board) error + DeleteBoardById(id uint) error } diff --git a/api/database/query.go b/api/database/query.go index d2b0409..95b99a3 100644 --- a/api/database/query.go +++ b/api/database/query.go @@ -12,6 +12,7 @@ func (db *tursoDB) GetUserById(id uint) (User, error) { return user, nil } +// TODO: do this func (db *tursoDB) UpdateUser(id uint, user User) error { return nil } @@ -88,4 +89,43 @@ func (db *tursoDB) UpdateItem(id uint, item Item) error { return errors.New("could not update item") } return nil +} + + +func (db *tursoDB) GetAllBoards() ([]Board, error) { + var boards []Board + if res := db.db.Find(&boards); res.Error != nil { + return nil, errors.New("could not find boards") + } + + return boards, nil +} + +func (db *tursoDB) CreateBoard(board Board) (uint, error) { + if res := db.db.Create(&board); res.Error != nil { + return 0, errors.New("could not create a new board") + } + return board.ID, nil +} + +func (db *tursoDB) GetBoardById(id uint) (Board, error) { + var board Board + if res := db.db.First(&board, id); res.Error != nil { + return Board{}, errors.New("courld not find board") + } + return board, nil +} + +func (db *tursoDB) UpdateBoard(id uint, board Board) error { + if res := db.db.Model(&board).Where("id = ?", id).Updates(board); res.Error != nil { + return errors.New("could not update board") + } + return nil +} + +func (db *tursoDB) DeleteBoardById(id uint) error { + if res := db.db.Delete(Board{}, id); res.Error != nil { + return errors.New("could not delete board") + } + return nil } \ No newline at end of file diff --git a/api/server/handler.go b/api/server/handler.go index d430b7d..9c98e8e 100644 --- a/api/server/handler.go +++ b/api/server/handler.go @@ -66,6 +66,7 @@ func usersRouter(db database.Database) *chi.Mux { http.Error(w, "invalid user data", http.StatusBadRequest) return } + id, err := db.CreateUser(user) if err != nil { http.Error(w, "database error", http.StatusInternalServerError) @@ -128,6 +129,7 @@ func usersRouter(db database.Database) *chi.Mux { if err := db.UpdateUser(userId, user); err != nil { http.Error(w, "could not update user", http.StatusInternalServerError) + return } }) @@ -176,7 +178,7 @@ func itemRouter(db database.Database) *chi.Mux { item, err := db.GetItemById(uint(itemId)) if err != nil { http.Error(w, "could not find item", http.StatusBadRequest) - return + return } JSON(w, item) }) @@ -191,7 +193,7 @@ func itemRouter(db database.Database) *chi.Mux { if err := db.DeleteItemByID(uint(itemId)); err != nil { http.Error(w, "could not delet item", http.StatusBadRequest) - return + return } }) @@ -215,7 +217,6 @@ func itemRouter(db database.Database) *chi.Mux { } }) - router.Patch("/{itemId}/move/{listId}", func(w http.ResponseWriter, r *http.Request) { itemIdString := r.PathValue("itemId") listIdString := r.PathValue("listId") @@ -231,5 +232,108 @@ func itemRouter(db database.Database) *chi.Mux { return router } +func boardsRouter(db database.Database) *chi.Mux { + router := chi.NewRouter() + + router.Get("/", func(w http.ResponseWriter, r *http.Request) { + boards, err := db.GetAllBoards() + if err != nil { + http.Error(w, "failed to get all boards", http.StatusNotFound) + } + + JSON(w, boards) + + }) + + router.Post("/", func(w http.ResponseWriter, r *http.Request) { + b, err := io.ReadAll(r.Body) + defer r.Body.Close() + if err != nil { + http.Error(w, "failed to read body", http.StatusInternalServerError) + return + } + + var board database.Board + if err := json.Unmarshal(b, &board); err != nil { + http.Error(w, "invalid user data", http.StatusBadRequest) + return + } + + + id, err := db.CreateBoard(board) + if err != nil { + http.Error(w, "database error", http.StatusInternalServerError) + return + } + + res := ResponseId{id} + JSON(w, res) + + }) + + router.Get("/{boardId}", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + boardId := getId(w, boardIdString) + + board, err := db.GetBoardById(boardId) + if err != nil { + http.Error(w, "failed to get board by id", http.StatusNotFound) + } + JSON(w, board) + }) + + router.Patch("/{boardId}", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + boardId := getId(w, boardIdString) + + + b, err := io.ReadAll(r.Body) + defer r.Body.Close() + if err != nil { + http.Error(w, "could not find user", http.StatusInternalServerError) + } + + var board database.Board + if err := json.Unmarshal(b, &board); err != nil { + http.Error(w, "invalid item data", http.StatusBadRequest) + } + + if err := db.UpdateBoard(boardId, board); err != nil { + http.Error(w, "could not update user", http.StatusInternalServerError) + } + }) + + router.Delete("/{boardId}", func(w http.ResponseWriter, r *http.Request) { + + boardIdString := r.PathValue("boardId") + boardId := getId(w, boardIdString) + + if err := db.DeleteBoardById(boardId); err != nil { + http.Error(w, "could not delete", http.StatusBadRequest) + } + }) + + router.Get("{boardId}/users", func(w http.ResponseWriter, r *http.Request) { + + }) + + router.Get("/{boardId}/items", func(w http.ResponseWriter, r *http.Request) { + + }) + + router.Get("/{boardId}/users/{userId}", func(w http.ResponseWriter, r *http.Request) { + + }) + + router.Delete("/{boardId}/users/{userId}", func(w http.ResponseWriter, r *http.Request) { + + }) + + router.Get("/{boardId}/lists/{listId}/items", func(w http.ResponseWriter, r *http.Request) { + + }) + + return router +} diff --git a/api/server/server.go b/api/server/server.go index 58ae95e..434231b 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -24,7 +24,7 @@ func New(config *config.Config, db database.Database) *Server { r.Get("/ping", pingHandler()) r.Mount("/users", usersRouter(db)) r.Mount("/items", itemRouter(db)) - + r.Mount("/boards", boardsRouter(db)) return &Server{ router: r, From bf3e5094e4d290fe87767238f04b87d43e347fa1 Mon Sep 17 00:00:00 2001 From: Zeno Date: Sun, 6 Jul 2025 14:22:07 +0200 Subject: [PATCH 9/9] ferdig med handlers --- api/database/database.go | 20 +++--- api/database/query.go | 97 ++++++++++++++++++++++++------ api/server/handler.go | 127 ++++++++++++++++++++++++++++++++------- 3 files changed, 193 insertions(+), 51 deletions(-) diff --git a/api/database/database.go b/api/database/database.go index c8899fa..b043608 100644 --- a/api/database/database.go +++ b/api/database/database.go @@ -1,24 +1,28 @@ package database type Database interface { - GetAllUsers() ([]User, error) - // Create new user, returns its ID. - CreateUser(user User) (id uint, err error) GetUserById(id uint) (User, error) - // Delete a user and remove it from all boards. + UpdateUser(id uint, user User) error + CreateUser(user User) (uint, error) DeleteUserById(id uint) error - GetAllItems() ([]Item, error) - // Create new item, returns its ID. - CreateItem(item Item) (uint, error) + GetAllUsers() ([]User, error) + GetItemById(id uint) (Item, error) + CreateItem(item Item) (uint, error) + GetAllItems() ([]Item, error) DeleteItemByID(id uint) error GetAllItemsFromList(boardId, list uint) ([]Item, error) MoveItemToList(id uint, list uint) error - UpdateUser(id uint, user User) error UpdateItem(id uint, item Item) error + GetAllBoards() ([]Board, error) CreateBoard(board Board) (uint, error) GetBoardById(id uint) (Board, error) UpdateBoard(id uint, board Board) error DeleteBoardById(id uint) error + + GetBoardUsers(boardId uint) ([]User, error) + GetBoardItems(boardId uint) ([]Item, error) + AddUserToBoard(boardId, userId uint) error + RemoveUserFromBoard(boardId, userId uint) error } diff --git a/api/database/query.go b/api/database/query.go index 95b99a3..4327641 100644 --- a/api/database/query.go +++ b/api/database/query.go @@ -7,13 +7,15 @@ import ( func (db *tursoDB) GetUserById(id uint) (User, error) { var user User if res := db.db.First(&user, id); res.Error != nil { - return User{}, errors.New("could not find usre with id") + return User{}, errors.New("could not find user with id") } return user, nil } -// TODO: do this func (db *tursoDB) UpdateUser(id uint, user User) error { + if res := db.db.Model(&User{}).Where("id = ?", id).Updates(user); res.Error != nil { + return errors.New("could not update user") + } return nil } @@ -34,14 +36,14 @@ func (db *tursoDB) DeleteUserById(id uint) error { func (db *tursoDB) GetAllUsers() ([]User, error) { var users []User if res := db.db.Find(&users); res.Error != nil { - return nil, errors.New("courl not get all userts") + return nil, errors.New("could not get all users") } return users, nil } func (db *tursoDB) GetItemById(id uint) (Item, error) { var item Item - if res := db.db.First(&item, id); res.Error != nil { + if res := db.db.Preload("Creator").Preload("Assignee").First(&item, id); res.Error != nil { return Item{}, errors.New("could not get item") } return item, nil @@ -49,14 +51,14 @@ func (db *tursoDB) GetItemById(id uint) (Item, error) { func (db *tursoDB) CreateItem(item Item) (uint, error) { if res := db.db.Create(&item); res.Error != nil { - return 0, errors.New("could not create item") + return 0, errors.New("could not create item") } return item.ID, nil } func (db *tursoDB) GetAllItems() ([]Item, error) { var items []Item - if res := db.db.Find(&items); res.Error != nil { + if res := db.db.Preload("Creator").Preload("Assignee").Find(&items); res.Error != nil { return nil, errors.New("could not get all items") } return items, nil @@ -70,11 +72,16 @@ func (db *tursoDB) DeleteItemByID(id uint) error { } func (db *tursoDB) GetAllItemsFromList(boardId, list uint) ([]Item, error) { - var items []Item - if res := db.db.Find(&items, "list = ?", list); res.Error != nil { - return nil, errors.New("could not find all items from list") + var board Board + if res := db.db.Preload("Items", "list = ?", list).First(&board, boardId); res.Error != nil { + return nil, errors.New("could not find board") } - return items, nil + + for i := range board.Items { + db.db.Preload("Creator").Preload("Assignee").First(&board.Items[i], board.Items[i].ID) + } + + return board.Items, nil } func (db *tursoDB) MoveItemToList(id uint, list uint) error { @@ -85,19 +92,17 @@ func (db *tursoDB) MoveItemToList(id uint, list uint) error { } func (db *tursoDB) UpdateItem(id uint, item Item) error { - if res := db.db.Model(&item).Where("id = ?", id).Updates(item); res.Error != nil { - return errors.New("could not update item") + if res := db.db.Model(&Item{}).Where("id = ?", id).Updates(item); res.Error != nil { + return errors.New("could not update item") } return nil } - func (db *tursoDB) GetAllBoards() ([]Board, error) { var boards []Board - if res := db.db.Find(&boards); res.Error != nil { + if res := db.db.Preload("Items").Preload("Users").Find(&boards); res.Error != nil { return nil, errors.New("could not find boards") } - return boards, nil } @@ -110,22 +115,74 @@ func (db *tursoDB) CreateBoard(board Board) (uint, error) { func (db *tursoDB) GetBoardById(id uint) (Board, error) { var board Board - if res := db.db.First(&board, id); res.Error != nil { - return Board{}, errors.New("courld not find board") + if res := db.db.Preload("Items").Preload("Users").First(&board, id); res.Error != nil { + return Board{}, errors.New("could not find board") } - return board, nil + return board, nil } func (db *tursoDB) UpdateBoard(id uint, board Board) error { - if res := db.db.Model(&board).Where("id = ?", id).Updates(board); res.Error != nil { + if res := db.db.Model(&Board{}).Where("id = ?", id).Updates(board); res.Error != nil { return errors.New("could not update board") } return nil } func (db *tursoDB) DeleteBoardById(id uint) error { - if res := db.db.Delete(Board{}, id); res.Error != nil { + if res := db.db.Delete(&Board{}, id); res.Error != nil { return errors.New("could not delete board") } + return nil +} + +func (db *tursoDB) GetBoardUsers(boardId uint) ([]User, error) { + var board Board + if res := db.db.Preload("Users").First(&board, boardId); res.Error != nil { + return nil, errors.New("could not find board") + } + return board.Users, nil +} + +func (db *tursoDB) GetBoardItems(boardId uint) ([]Item, error) { + var board Board + if res := db.db.Preload("Items").Preload("Items.Creator").Preload("Items.Assignee").First(&board, boardId); res.Error != nil { + return nil, errors.New("could not find board") + } + return board.Items, nil +} + +func (db *tursoDB) AddUserToBoard(boardId, userId uint) error { + var board Board + if res := db.db.First(&board, boardId); res.Error != nil { + return errors.New("could not find board") + } + + var user User + if res := db.db.First(&user, userId); res.Error != nil { + return errors.New("could not find user") + } + + if res := db.db.Model(&board).Association("Users").Append(&user); res != nil { + return errors.New("could not add user to board") + } + + return nil +} + +func (db *tursoDB) RemoveUserFromBoard(boardId, userId uint) error { + var board Board + if res := db.db.First(&board, boardId); res.Error != nil { + return errors.New("could not find board") + } + + var user User + if res := db.db.First(&user, userId); res.Error != nil { + return errors.New("could not find user") + } + + if res := db.db.Model(&board).Association("Users").Delete(&user); res != nil { + return errors.New("could not remove user from board") + } + return nil } \ No newline at end of file diff --git a/api/server/handler.go b/api/server/handler.go index 9c98e8e..bf49734 100644 --- a/api/server/handler.go +++ b/api/server/handler.go @@ -21,6 +21,7 @@ func JSON(w http.ResponseWriter, data any) { return } + w.Header().Set("Content-Type", "application/json") w.Write(resp) } @@ -107,6 +108,8 @@ func usersRouter(db database.Database) *chi.Mux { http.Error(w, "not valid user id", http.StatusNotFound) return } + + w.WriteHeader(http.StatusNoContent) }) router.Patch("/{userId}", func(w http.ResponseWriter, r *http.Request) { @@ -132,6 +135,7 @@ func usersRouter(db database.Database) *chi.Mux { return } + w.WriteHeader(http.StatusNoContent) }) return router } @@ -151,7 +155,7 @@ func itemRouter(db database.Database) *chi.Mux { b, err := io.ReadAll(r.Body) defer r.Body.Close() if err != nil { - http.Error(w, "invalid item data", http.StatusBadGateway) + http.Error(w, "failed to read body", http.StatusInternalServerError) return } @@ -174,27 +178,28 @@ func itemRouter(db database.Database) *chi.Mux { router.Get("/{itemId}", func(w http.ResponseWriter, r *http.Request) { itemIdString := r.PathValue("itemId") itemId := getId(w, itemIdString) + if itemId == 0 { + return + } item, err := db.GetItemById(uint(itemId)) if err != nil { - http.Error(w, "could not find item", http.StatusBadRequest) + http.Error(w, "could not find item", http.StatusNotFound) return } JSON(w, item) }) - router.Patch("/{itemId}", func(w http.ResponseWriter, r *http.Request) { - - }) - router.Delete("/{itemId}", func(w http.ResponseWriter, r *http.Request) { itemIdString := r.PathValue("itemId") itemId := getId(w, itemIdString) if err := db.DeleteItemByID(uint(itemId)); err != nil { - http.Error(w, "could not delet item", http.StatusBadRequest) + http.Error(w, "could not delete item", http.StatusNotFound) return } + + w.WriteHeader(http.StatusNoContent) }) router.Patch("/{itemId}", func(w http.ResponseWriter, r *http.Request) { @@ -204,17 +209,22 @@ func itemRouter(db database.Database) *chi.Mux { b, err := io.ReadAll(r.Body) defer r.Body.Close() if err != nil { - http.Error(w, "could not find user", http.StatusInternalServerError) + http.Error(w, "failed to read body", http.StatusInternalServerError) + return } var item database.Item if err := json.Unmarshal(b, &item); err != nil { http.Error(w, "invalid item data", http.StatusBadRequest) + return } if err := db.UpdateItem(itemId, item); err != nil { http.Error(w, "could not update item", http.StatusInternalServerError) + return } + + w.WriteHeader(http.StatusNoContent) }) router.Patch("/{itemId}/move/{listId}", func(w http.ResponseWriter, r *http.Request) { @@ -226,7 +236,10 @@ func itemRouter(db database.Database) *chi.Mux { if err := db.MoveItemToList(itemId, listId); err != nil { http.Error(w, "could not move item to list", http.StatusInternalServerError) + return } + + w.WriteHeader(http.StatusNoContent) }) return router @@ -239,10 +252,10 @@ func boardsRouter(db database.Database) *chi.Mux { boards, err := db.GetAllBoards() if err != nil { http.Error(w, "failed to get all boards", http.StatusNotFound) + return } JSON(w, boards) - }) router.Post("/", func(w http.ResponseWriter, r *http.Request) { @@ -256,11 +269,10 @@ func boardsRouter(db database.Database) *chi.Mux { var board database.Board if err := json.Unmarshal(b, &board); err != nil { - http.Error(w, "invalid user data", http.StatusBadRequest) + http.Error(w, "invalid board data", http.StatusBadRequest) return } - id, err := db.CreateBoard(board) if err != nil { http.Error(w, "database error", http.StatusInternalServerError) @@ -269,16 +281,16 @@ func boardsRouter(db database.Database) *chi.Mux { res := ResponseId{id} JSON(w, res) - }) router.Get("/{boardId}", func(w http.ResponseWriter, r *http.Request) { boardIdString := r.PathValue("boardId") - boardId := getId(w, boardIdString) + boardId := getId(w, boardIdString) board, err := db.GetBoardById(boardId) if err != nil { http.Error(w, "failed to get board by id", http.StatusNotFound) + return } JSON(w, board) @@ -288,52 +300,121 @@ func boardsRouter(db database.Database) *chi.Mux { boardIdString := r.PathValue("boardId") boardId := getId(w, boardIdString) - b, err := io.ReadAll(r.Body) defer r.Body.Close() if err != nil { - http.Error(w, "could not find user", http.StatusInternalServerError) + http.Error(w, "failed to read body", http.StatusInternalServerError) + return } var board database.Board if err := json.Unmarshal(b, &board); err != nil { - http.Error(w, "invalid item data", http.StatusBadRequest) + http.Error(w, "invalid board data", http.StatusBadRequest) + return } if err := db.UpdateBoard(boardId, board); err != nil { - http.Error(w, "could not update user", http.StatusInternalServerError) + http.Error(w, "could not update board", http.StatusInternalServerError) + return } + + w.WriteHeader(http.StatusNoContent) }) router.Delete("/{boardId}", func(w http.ResponseWriter, r *http.Request) { - boardIdString := r.PathValue("boardId") boardId := getId(w, boardIdString) if err := db.DeleteBoardById(boardId); err != nil { - http.Error(w, "could not delete", http.StatusBadRequest) + http.Error(w, "could not delete board", http.StatusNotFound) + return } + + w.WriteHeader(http.StatusNoContent) }) - router.Get("{boardId}/users", func(w http.ResponseWriter, r *http.Request) { - + router.Get("/{boardId}/users", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + boardId := getId(w, boardIdString) + + + users, err := db.GetBoardUsers(boardId) + if err != nil { + http.Error(w, "could not get board users", http.StatusNotFound) + return + } + + JSON(w, users) }) + router.Get("/{boardId}/items", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + boardId := getId(w, boardIdString) + + items, err := db.GetBoardItems(boardId) + if err != nil { + http.Error(w, "could not get board items", http.StatusNotFound) + return + } + + JSON(w, items) }) - router.Get("/{boardId}/users/{userId}", func(w http.ResponseWriter, r *http.Request) { + router.Post("/{boardId}/users/{userId}", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + userIdString := r.PathValue("userId") + + boardId := getId(w, boardIdString) + + userId := getId(w, userIdString) + + if err := db.AddUserToBoard(boardId, userId); err != nil { + http.Error(w, "could not add user to board", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) }) router.Delete("/{boardId}/users/{userId}", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + userIdString := r.PathValue("userId") + + boardId := getId(w, boardIdString) + + userId := getId(w, userIdString) + if err := db.RemoveUserFromBoard(boardId, userId); err != nil { + http.Error(w, "could not remove user from board", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusNoContent) }) router.Get("/{boardId}/lists/{listId}/items", func(w http.ResponseWriter, r *http.Request) { + boardIdString := r.PathValue("boardId") + listIdString := r.PathValue("listId") + + boardId := getId(w, boardIdString) + + listId := getId(w, listIdString) + if listId == 0 { + return + } + + items, err := db.GetAllItemsFromList(boardId, listId) + if err != nil { + http.Error(w, "could not get items from list", http.StatusNotFound) + return + } + + JSON(w, items) }) return router -} +} \ No newline at end of file