diff --git a/backend/db/cards.go b/backend/db/cards.go index 84347cc..bd97368 100644 --- a/backend/db/cards.go +++ b/backend/db/cards.go @@ -16,7 +16,7 @@ func CreateCard(c types.Card) (int, error) { return int(id), nil } -func GetAllCardsOf(projectID int) ([]types.FullCard, error) { +func GetProjectsCards(projectID int) ([]types.FullCard, error) { rows, err := db.Query("SELECT * FROM cards WHERE project_id = ?", projectID) if err != nil { return nil, err @@ -30,7 +30,7 @@ func GetAllCardsOf(projectID int) ([]types.FullCard, error) { return nil, err } - tags, err := GetAllTagsOfCard(c.ID, projectID) + tags, err := GetCardTags(c.ID, projectID) if err != nil { return nil, err } @@ -47,14 +47,21 @@ func GetAllCardsOf(projectID int) ([]types.FullCard, error) { } func GetCard(id int) (*types.FullCard, error) { - var c types.FullCard - err := db.QueryRow("SELECT * FROM cards WHERE id = ?", id).Scan(&c.ID, &c.ProjectID, &c.Title, &c.Content) + rows, err := db.Query("SELECT * FROM cards WHERE id = ?", id) if err != nil { return nil, err } + defer rows.Close() - tags, err := GetAllTagsOfCard(id, c.ProjectID) + if !rows.Next() { + return nil, nil + } + + var c types.FullCard + rows.Scan(&c.ID, &c.ProjectID, &c.Title, &c.Content) + + tags, err := GetCardTags(id, c.ProjectID) if err != nil { return nil, err } @@ -63,12 +70,28 @@ func GetCard(id int) (*types.FullCard, error) { return &c, nil } -func DeleteCard(id int) error { - _, err := db.Exec("DELETE FROM cards WHERE id = ?", id) - return err +func DeleteCard(id int) (int64, error) { + res, err := db.Exec("DELETE FROM cards WHERE id = ?", id) + if err != nil { + return 0, err + } + return res.RowsAffected() } -func UpdateCard(c types.Card) error { - _, err := db.Exec("UPDATE cards SET project_id = ?, title = ?, content = ? WHERE id = ?", c.ProjectID, c.Title, c.Content, c.ID) - return err +func UpdateCard(c types.Card) (int64, error) { + res, err := db.Exec("UPDATE cards SET project_id = ?, title = ?, content = ? WHERE id = ?", c.ProjectID, c.Title, c.Content, c.ID) + if err != nil { + return 0, err + } + return res.RowsAffected() +} + +func ExistCard(id int) (bool, error) { + var count int + err := db.QueryRow("SELECT COUNT(*) FROM cards WHERE id = ?", id).Scan(&count) + if err != nil { + return false, err + } + + return count > 0, nil } diff --git a/backend/db/cardtags.go b/backend/db/cardstags.go similarity index 54% rename from backend/db/cardtags.go rename to backend/db/cardstags.go index 650c56f..0dc58d4 100644 --- a/backend/db/cardtags.go +++ b/backend/db/cardstags.go @@ -4,12 +4,12 @@ import ( "git.bhasher.com/bhasher/focus/backend/types" ) -func AddTagToCard(ct types.CardTag) error { +func CreateCardTag(ct types.CardTag) error { _, err := db.Exec("INSERT INTO cardtags (card_id, tag_id, value) VALUES (?, ?, ?)", ct.CardID, ct.TagID, ct.Value) return err } -func GetAllTagsOfCard(cardID int, projectID int) ([]types.FullCardTag, error) { +func GetCardTags(cardID int, projectID int) ([]types.FullCardTag, error) { if projectID < 0 { card, err := GetCard(cardID) if err != nil { @@ -44,17 +44,26 @@ func GetAllTagsOfCard(cardID int, projectID int) ([]types.FullCardTag, error) { return cardtags, nil } -func DeleteTagOfCard(card_id int, tag_id int) error { - _, err := db.Exec("DELETE FROM cardtags WHERE card_id = ? AND tag_id = ?", card_id, tag_id) - return err +func DeleteCardTag(card_id int, tag_id int) (int64, error) { + res, err := db.Exec("DELETE FROM cardtags WHERE card_id = ? AND tag_id = ?", card_id, tag_id) + if err != nil { + return 0, err + } + return res.RowsAffected() } -func DeleteTagsOfCard(card_id int) error { - _, err := db.Exec("DELETE FROM cardtags WHERE card_id = ?", card_id) - return err +func DeleteCardTags(card_id int) (int64, error) { + res, err := db.Exec("DELETE FROM cardtags WHERE card_id = ?", card_id) + if err != nil { + return 0, err + } + return res.RowsAffected() } -func UpdateTagOfCard(ct types.CardTag) error { - _, err := db.Exec("UPDATE cardtags SET value = ? WHERE card_id = ? AND tag_id = ?", ct.Value, ct.CardID, ct.TagID) - return err +func UpdateCardTag(ct types.CardTag) (int64, error) { + res, err := db.Exec("UPDATE cardtags SET value = ? WHERE card_id = ? AND tag_id = ?", ct.Value, ct.CardID, ct.TagID) + if err != nil { + return 0, err + } + return res.RowsAffected() } diff --git a/backend/db/main.go b/backend/db/main.go index 591cf48..9a722d4 100644 --- a/backend/db/main.go +++ b/backend/db/main.go @@ -43,6 +43,7 @@ func InitDB(driver string, connStr string) error { card_id INTEGER, tag_id INTEGER, value TEXT, + PRIMARY KEY(card_id, tag_id), FOREIGN KEY(card_id) REFERENCES cards(id) FOREIGN KEY(tag_id) REFERENCES tags(id) ); diff --git a/backend/db/projects.go b/backend/db/projects.go index de94a1e..a1bccf0 100644 --- a/backend/db/projects.go +++ b/backend/db/projects.go @@ -44,22 +44,37 @@ func GetAllProjects() ([]types.Project, error) { func GetProject(id int) (*types.Project, error) { var p types.Project - err := db.QueryRow("SELECT * FROM projects WHERE id = ?", id).Scan(&p.ID, &p.Title) + rows, err := db.Query("SELECT * FROM projects WHERE id = ?", id) if err != nil { return nil, err } + defer rows.Close() + if !rows.Next() { + return nil, nil + } + + if err := rows.Scan(&p.ID, &p.Title); err != nil { + return nil, err + } return &p, nil + } -func DeleteProject(id int) error { - _, err := db.Exec("DELETE FROM projects WHERE id = ?", id) - return err +func DeleteProject(id int) (int64, error) { + res, err := db.Exec("DELETE FROM projects WHERE id = ?", id) + if err != nil { + return 0, err + } + return res.RowsAffected() } -func UpdateProject(p types.Project) error { - _, err := db.Exec("UPDATE projects SET title = ? WHERE id = ?", p.Title, p.ID) - return err +func UpdateProject(p types.Project) (int64, error) { + res, err := db.Exec("UPDATE projects SET title = ? WHERE id = ?", p.Title, p.ID) + if err != nil { + return 0, err + } + return res.RowsAffected() } func ExistProject(id int) (bool, error) { diff --git a/backend/db/tags.go b/backend/db/tags.go index eb62322..aff703b 100644 --- a/backend/db/tags.go +++ b/backend/db/tags.go @@ -16,7 +16,7 @@ func CreateTag(t types.Tag) (int, error) { return int(id), nil } -func GetAllTagsOf(projectID int) ([]types.Tag, error) { +func GetProjectTags(projectID int) ([]types.Tag, error) { rows, err := db.Query("SELECT * FROM tags WHERE project_id = ?", projectID) if err != nil { return nil, err @@ -42,20 +42,42 @@ func GetAllTagsOf(projectID int) ([]types.Tag, error) { func GetTag(id int) (*types.Tag, error) { var t types.Tag - err := db.QueryRow("SELECT * FROM tags WHERE id = ?", id).Scan(&t.ID, &t.ProjectID, &t.Title, &t.Type) + rows, err := db.Query("SELECT * FROM tags WHERE id = ?", id) if err != nil { return nil, err } + if !rows.Next() { + return nil, nil + } + + rows.Scan(&t.ID, &t.ProjectID, &t.Title, &t.Type) + return &t, nil } -func DeleteTag(id int) error { - _, err := db.Exec("DELETE FROM tags WHERE id = ?", id) - return err +func DeleteTag(id int) (int64, error) { + res, err := db.Exec("DELETE FROM tags WHERE id = ?", id) + if err != nil { + return 0, err + } + return res.RowsAffected() } -func UpdateTag(t types.Tag) error { - _, err := db.Exec("UPDATE tags SET project_id = ?, title = ?, type = ? WHERE id = ?", t.ProjectID, t.Title, t.Type, t.ID) - return err +func UpdateTag(t types.Tag) (int64, error) { + res, err := db.Exec("UPDATE tags SET project_id = ?, title = ?, type = ? WHERE id = ?", t.ProjectID, t.Title, t.Type, t.ID) + if err != nil { + return 0, err + } + return res.RowsAffected() +} + +func ExistTag(id int) (bool, error) { + var count int + err := db.QueryRow("SELECT COUNT(*) FROM tas WHERE id = ?", id).Scan(&count) + if err != nil { + return false, err + } + + return count > 0, nil } diff --git a/backend/handlers/cards.go b/backend/handlers/cards.go index 8eaab3b..c2fa794 100644 --- a/backend/handlers/cards.go +++ b/backend/handlers/cards.go @@ -6,7 +6,6 @@ import ( "git.bhasher.com/bhasher/focus/backend/db" "git.bhasher.com/bhasher/focus/backend/types" - "git.bhasher.com/bhasher/focus/backend/utils" "github.com/gofiber/fiber/v2" ) @@ -27,54 +26,85 @@ func CreateCard(c *fiber.Ctx) error { }) } - c.Status(fiber.StatusCreated) - c.Location(fmt.Sprintf("/api/cards/%v", id)) - return c.JSON(fiber.Map{ - "id": id, - "_links": utils.HALProjectLinks(id), + return c.Status(fiber.StatusCreated).JSON(fiber.Map{ + "id": id, }) } -func GetAllCardsOf(c *fiber.Ctx) error { +func GetProjectCards(c *fiber.Ctx) error { projectID, err := strconv.Atoi(c.Params("project_id")) if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "error", "error": "Invalid project_id", "trace": fmt.Sprint(err)}) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid project_id", + "trace": fmt.Sprint(err), + }) } - projects, err := db.GetAllCardsOf(projectID) + exists, err := db.ExistProject(projectID) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"status": "error", "error": "Cannot retrieve cards", "trace": fmt.Sprint(err)}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding project", + "trace": fmt.Sprint(err), + }) } - return c.JSON(fiber.Map{"status": "ok", "data": projects}) + if !exists { + return c.SendStatus(fiber.StatusNotFound) + } + + cards, err := db.GetProjectsCards(projectID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot retrieve cards", + "trace": fmt.Sprint(err), + }) + } + + return c.Status(fiber.StatusOK).JSON(cards) } func GetCard(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid card ID", + "trace": fmt.Sprint(err), + }) } card, err := db.GetCard(id) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot retrieve card"}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot retrieve card", + "trace": fmt.Sprint(err), + }) } if card == nil { - return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Card not found"}) + return c.SendStatus(fiber.StatusNotFound) } - return c.JSON(card) + return c.Status(fiber.StatusOK).JSON(card) } func DeleteCard(c *fiber.Ctx) error { id, err := strconv.Atoi(c.Params("id")) if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "error", "error": "Invalid card ID", "trace": fmt.Sprint(err)}) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid card ID", + "trace": fmt.Sprint(err), + }) } - err = db.DeleteCard(id) + count, err := db.DeleteCard(id) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"status": "error", "error": "Cannot delete card", "trace": fmt.Sprint(err)}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot delete card", + "trace": fmt.Sprint(err), + }) + } + + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) } return c.SendStatus(fiber.StatusNoContent) @@ -91,9 +121,16 @@ func UpdateCard(c *fiber.Ctx) error { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"}) } - err = db.UpdateCard(card) + count, err := db.UpdateCard(card) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot update card"}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot update card", + "trace": fmt.Sprint(err), + }) + } + + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) } return c.SendStatus(fiber.StatusOK) diff --git a/backend/handlers/cardstags.go b/backend/handlers/cardstags.go new file mode 100644 index 0000000..a5797c4 --- /dev/null +++ b/backend/handlers/cardstags.go @@ -0,0 +1,219 @@ +package handlers + +import ( + "fmt" + "strconv" + "strings" + + "git.bhasher.com/bhasher/focus/backend/db" + "git.bhasher.com/bhasher/focus/backend/types" + "github.com/gofiber/fiber/v2" +) + +func CreateCardTag(c *fiber.Ctx) error { + cardID, err := strconv.Atoi(c.Params("card_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card_id"}) + } + tagID, err := strconv.Atoi(c.Params("tag_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag_id"}) + } + + cardtag := types.CardTag{CardID: cardID, TagID: tagID} + if err := c.BodyParser(&cardtag); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"}) + } + + exist, err := db.ExistCard(cardID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding card", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Card not found"}) + } + + exist, err = db.ExistTag(tagID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding tag", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Tag not found"}) + } + + err = db.CreateCardTag(cardtag) + if err != nil { + if strings.HasPrefix(err.Error(), "UNIQUE constraint failed") { + return c.SendStatus(fiber.StatusConflict) + } + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot add tag to card", + "trace": fmt.Sprint(err), + }) + } + + return c.SendStatus(fiber.StatusCreated) +} + +func GetCardTags(c *fiber.Ctx) error { + cardID, err := strconv.Atoi(c.Params("card_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card_id"}) + } + + exist, err := db.ExistCard(cardID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding card", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.SendStatus(fiber.StatusNotFound) + } + + cardtags, err := db.GetCardTags(cardID, -1) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot retrieve tags of card", + "stack": fmt.Sprint(err), + }) + } + + return c.Status(fiber.StatusOK).JSON(cardtags) +} + +func DeleteCardTag(c *fiber.Ctx) error { + cardID, err := strconv.Atoi(c.Params("card_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) + } + + tagID, err := strconv.Atoi(c.Params("tag_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"}) + } + + exist, err := db.ExistCard(cardID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding card", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Card not found"}) + } + + exist, err = db.ExistTag(tagID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding tag", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Tag not found"}) + } + + count, err := db.DeleteCardTag(cardID, tagID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot delete tag of card", + "stack": fmt.Sprint(err), + }) + } + + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) + } + + return c.SendStatus(fiber.StatusNoContent) +} + +func DeleteCardTags(c *fiber.Ctx) error { + cardID, err := strconv.Atoi(c.Params("card_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) + } + + exist, err := db.ExistCard(cardID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding card", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Card not found"}) + } + + _, err = db.DeleteCardTags(cardID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot delete tags of card", + "stack": fmt.Sprint(err), + }) + } + + return c.SendStatus(fiber.StatusNoContent) +} + +func UpdateCardTag(c *fiber.Ctx) error { + cardID, err := strconv.Atoi(c.Params("card_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) + } + + tagID, err := strconv.Atoi(c.Params("tag_id")) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"}) + } + + cardtag := types.CardTag{CardID: cardID, TagID: tagID} + if err := c.BodyParser(&cardtag); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"}) + } + + exist, err := db.ExistCard(cardID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding card", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Card not found"}) + } + + exist, err = db.ExistTag(tagID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding tag", + "trace": fmt.Sprint(err), + }) + } + if !exist { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Tag not found"}) + } + + count, err := db.UpdateCardTag(cardtag) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot update tag of card", + "stack": fmt.Sprint(err), + }) + } + + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) + } + + return c.SendStatus(fiber.StatusNoContent) +} diff --git a/backend/handlers/cardtags.go b/backend/handlers/cardtags.go deleted file mode 100644 index c775bc2..0000000 --- a/backend/handlers/cardtags.go +++ /dev/null @@ -1,95 +0,0 @@ -package handlers - -import ( - "fmt" - "strconv" - - "git.bhasher.com/bhasher/focus/backend/db" - "git.bhasher.com/bhasher/focus/backend/types" - "github.com/gofiber/fiber/v2" -) - -func CreateTagOfCard(c *fiber.Ctx) error { - cardtag := types.CardTag{} - if err := c.BodyParser(&cardtag); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"}) - } - - err := db.AddTagToCard(cardtag) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot add tag to card"}) - } - - return c.SendStatus(fiber.StatusOK) -} - -func GetAllTagsOfCard(c *fiber.Ctx) error { - cardID, err := strconv.Atoi(c.Params("card_id")) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "error", "error": "Invalid card_id"}) - } - - cardtags, err := db.GetAllTagsOfCard(cardID, -1) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"status": "error", "error": "Cannot retrieve tags of card", "stack": fmt.Sprint(err)}) - } - - return c.JSON(fiber.Map{"status": "ok", "data": cardtags}) -} - -func DeleteTagOfCard(c *fiber.Ctx) error { - card_id, err := strconv.Atoi(c.Params("card_id")) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) - } - - tag_id, err := strconv.Atoi(c.Params("tag_id")) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"}) - } - - err = db.DeleteTagOfCard(card_id, tag_id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot delete tag of card"}) - } - - return c.SendStatus(fiber.StatusNoContent) -} - -func DeleteTagsOfCard(c *fiber.Ctx) error { - card_id, err := strconv.Atoi(c.Params("card_id")) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) - } - - err = db.DeleteTagsOfCard(card_id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot delete tags of card"}) - } - - return c.SendStatus(fiber.StatusNoContent) -} - -func UpdateTagOfCard(c *fiber.Ctx) error { - card_id, err := strconv.Atoi(c.Params("card_id")) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid card ID"}) - } - - tag_id, err := strconv.Atoi(c.Params("tag_id")) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "error", "error": "Invalid tag ID", "stack": fmt.Sprint(err)}) - } - - cardtag := types.CardTag{CardID: card_id, TagID: tag_id} - if err := c.BodyParser(&cardtag); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"}) - } - - err = db.UpdateTagOfCard(cardtag) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot update tag of card"}) - } - - return c.SendStatus(fiber.StatusOK) -} diff --git a/backend/handlers/projects.go b/backend/handlers/projects.go index 68e4830..f2f677d 100644 --- a/backend/handlers/projects.go +++ b/backend/handlers/projects.go @@ -5,7 +5,6 @@ import ( "git.bhasher.com/bhasher/focus/backend/db" "git.bhasher.com/bhasher/focus/backend/types" - "git.bhasher.com/bhasher/focus/backend/utils" "github.com/gofiber/fiber/v2" ) @@ -18,22 +17,7 @@ func GetAllProjects(c *fiber.Ctx) error { }) } - halProjects := make([]fiber.Map, len(projects)) - for i, p := range projects { - halProjects[i] = fiber.Map{ - "project": p, - "_links": utils.HALProjectLinks(p.ID), - } - } - - return utils.SendHAL(c, fiber.StatusOK, fiber.Map{ - "_links": fiber.Map{ - "self": fiber.Map{"href": "/api/projects"}, - }, - "_embedded": fiber.Map{ - "projects": halProjects, - }, - }) + return c.Status(fiber.StatusOK).JSON(projects) } func GetProject(c *fiber.Ctx) error { @@ -53,10 +37,7 @@ func GetProject(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusNotFound) } - return utils.SendHAL(c, fiber.StatusOK, fiber.Map{ - "project": project, - "_links": utils.HALProjectLinks(project.ID), - }) + return c.Status(fiber.StatusOK).JSON(project) } func CreateProject(c *fiber.Ctx) error { @@ -73,10 +54,8 @@ func CreateProject(c *fiber.Ctx) error { }) } - c.Location(fmt.Sprintf("/api/projects/%v", id)) - return utils.SendHAL(c, fiber.StatusCreated, fiber.Map{ - "id": id, - "_links": utils.HALProjectLinks(id), + return c.Status(fiber.StatusCreated).JSON(fiber.Map{ + "id": id, }) } @@ -91,19 +70,7 @@ func UpdateProject(c *fiber.Ctx) error { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Error parsing request"}) } - exists, err := db.ExistProject(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Error finding project", - "trace": fmt.Sprint(err), - }) - } - - if !exists { - return c.SendStatus(fiber.StatusNotFound) - } - - err = db.UpdateProject(p) + count, err := db.UpdateProject(p) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": "Error updating project", @@ -111,6 +78,10 @@ func UpdateProject(c *fiber.Ctx) error { }) } + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) + } + return c.SendStatus(fiber.StatusNoContent) } @@ -120,19 +91,7 @@ func DeleteProject(c *fiber.Ctx) error { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"}) } - exists, err := db.ExistProject(id) - if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "error": "Error finding project", - "trace": fmt.Sprint(err), - }) - } - - if !exists { - return c.SendStatus(fiber.StatusNotFound) - } - - err = db.DeleteProject(id) + count, err := db.DeleteProject(id) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": "Error deleting project", @@ -140,5 +99,9 @@ func DeleteProject(c *fiber.Ctx) error { }) } + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) + } + return c.SendStatus(fiber.StatusNoContent) } diff --git a/backend/handlers/tags.go b/backend/handlers/tags.go index ed0ebd1..524bed7 100644 --- a/backend/handlers/tags.go +++ b/backend/handlers/tags.go @@ -17,24 +17,42 @@ func CreateTag(c *fiber.Ctx) error { id, err := db.CreateTag(tag) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot create tag", "trace": fmt.Sprint(err)}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot create tag", + "trace": fmt.Sprint(err), + }) } return c.Status(fiber.StatusCreated).JSON(fiber.Map{"id": id}) } -func GetAllTagsOf(c *fiber.Ctx) error { +func GetProjectTags(c *fiber.Ctx) error { projectID, err := strconv.Atoi(c.Params("project_id")) if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "error", "error": "Invalid project_id"}) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project_id"}) } - projects, err := db.GetAllTagsOf(projectID) + exists, err := db.ExistProject(projectID) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot retrieve tags"}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Error finding project", + "trace": fmt.Sprint(err), + }) } - return c.JSON(fiber.Map{"status": "ok", "data": projects}) + if !exists { + return c.SendStatus(fiber.StatusNotFound) + } + + tags, err := db.GetProjectTags(projectID) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot retrieve tags", + "trace": fmt.Sprint(err), + }) + } + + return c.JSON(tags) } func GetTag(c *fiber.Ctx) error { @@ -45,10 +63,13 @@ func GetTag(c *fiber.Ctx) error { tag, err := db.GetTag(id) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot retrieve tag"}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot retrieve tag", + "trace": fmt.Sprint(err), + }) } if tag == nil { - return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Tag not found"}) + return c.SendStatus(fiber.StatusNotFound) } return c.JSON(tag) @@ -60,9 +81,16 @@ func DeleteTag(c *fiber.Ctx) error { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"}) } - err = db.DeleteTag(id) + count, err := db.DeleteTag(id) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot delete tag"}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot delete tag", + "trace": fmt.Sprint(err), + }) + } + + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) } return c.SendStatus(fiber.StatusNoContent) @@ -79,9 +107,16 @@ func UpdateTag(c *fiber.Ctx) error { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"}) } - err = db.UpdateTag(tag) + count, err := db.UpdateTag(tag) if err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot update tag"}) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Cannot update tag", + "trace": fmt.Sprint(err), + }) + } + + if count == 0 { + return c.SendStatus(fiber.StatusNotFound) } return c.SendStatus(fiber.StatusOK) diff --git a/backend/main.go b/backend/main.go index 72c7a13..e199de5 100644 --- a/backend/main.go +++ b/backend/main.go @@ -35,8 +35,8 @@ func main() { app.Get("/api/projects/:id", handlers.GetProject) app.Put("/api/projects/:id", handlers.UpdateProject) app.Delete("/api/projects/:id", handlers.DeleteProject) - app.Get("/api/projects/:project_id/cards", handlers.GetAllCardsOf) - app.Get("/api/projects/:project_id/tags", handlers.GetAllTagsOf) + app.Get("/api/projects/:project_id/cards", handlers.GetProjectCards) + app.Get("/api/projects/:project_id/tags", handlers.GetProjectTags) app.Post("/api/cards", handlers.CreateCard) app.Get("/api/cards/:id", handlers.GetCard) @@ -48,11 +48,11 @@ func main() { app.Delete("/api/tags/:id", handlers.DeleteTag) app.Put("/api/tags/:id", handlers.UpdateTag) - app.Post("/api/cards/:card_id/tags/:tag_id", handlers.CreateTagOfCard) - app.Get("/api/cards/:card_id/tags", handlers.GetAllTagsOfCard) - app.Put("/api/cards/:card_id/tags/:tag_id", handlers.UpdateTagOfCard) - app.Delete("/api/cards/:card_id/tags/:tag_id", handlers.DeleteTagOfCard) - app.Delete("/api/cards/:card_id/tags", handlers.DeleteTagsOfCard) + app.Post("/api/cards/:card_id/tags/:tag_id", handlers.CreateCardTag) + app.Get("/api/cards/:card_id/tags", handlers.GetCardTags) + app.Put("/api/cards/:card_id/tags/:tag_id", handlers.UpdateCardTag) + app.Delete("/api/cards/:card_id/tags/:tag_id", handlers.DeleteCardTag) + app.Delete("/api/cards/:card_id/tags", handlers.DeleteCardTags) log.Fatal(app.Listen(fmt.Sprintf(":%v", port))) } diff --git a/backend/utils/hal.go b/backend/utils/hal.go deleted file mode 100644 index 345bf74..0000000 --- a/backend/utils/hal.go +++ /dev/null @@ -1,27 +0,0 @@ -package utils - -import ( - "fmt" - - "github.com/gofiber/fiber/v2" -) - -func SendHAL(c *fiber.Ctx, status int, data fiber.Map) error { - if err := c.JSON(data); err != nil { - return err - } - - c.Status(status) - c.Context().SetContentType("application/hal+json") - return nil -} - -func HALProjectLinks(id int) fiber.Map { - return fiber.Map{ - "_links": fiber.Map{ - "self": fiber.Map{"href": fmt.Sprintf("/api/projects/%v", id)}, - "cards": fiber.Map{"href": fmt.Sprintf("/api/projects/%v/cards", id)}, - "tags": fiber.Map{"href": fmt.Sprintf("/api/projects/%v/tags", id)}, - }, - } -}