This commit is contained in:
Brieuc Dubois 2023-12-29 03:08:08 +01:00
parent e0056809b3
commit c4b41d79a2
13 changed files with 378 additions and 6 deletions

52
backend/db/cardtags.go Normal file
View File

@ -0,0 +1,52 @@
package db
import (
"git.bhasher.com/bhasher/focus/backend/types"
)
func AddTagToCard(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) ([]types.FullCardTag, error) {
rows, err := db.Query(`SELECT ct.card_id, ct.tag_id, t.title, ct.value
FROM cardtags ct
JOIN tags t ON ct.tag_id = t.id
WHERE ct.card_id = ?;
`, cardID)
if err != nil {
return nil, err
}
defer rows.Close()
var cardtags []types.FullCardTag
for rows.Next() {
var ct types.FullCardTag
if err := rows.Scan(&ct.CardID, &ct.TagID, &ct.TagTitle, &ct.Value); err != nil {
return nil, err
}
cardtags = append(cardtags, ct)
}
if err = rows.Err(); err != nil {
return nil, err
}
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 DeleteTagsOfCard(card_id int) error {
_, err := db.Exec("DELETE FROM cardtags WHERE card_id = ?", card_id)
return err
}
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
}

View File

@ -31,6 +31,20 @@ func InitDB(driver string, connStr string) error {
title TEXT,
content TEXT,
FOREIGN KEY(project_id) REFERENCES projects(id)
);
CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id INTEGER,
title TEXT,
type int,
FOREIGN KEY(project_id) REFERENCES projects(id)
);
CREATE TABLE IF NOT EXISTS cardtags (
card_id INTEGER,
tag_id INTEGER,
value TEXT,
FOREIGN KEY(card_id) REFERENCES cards(id)
FOREIGN KEY(tag_id) REFERENCES tags(id)
);
`)
if err != nil {

61
backend/db/tags.go Normal file
View File

@ -0,0 +1,61 @@
package db
import "git.bhasher.com/bhasher/focus/backend/types"
func CreateTag(t types.Tag) (int, error) {
res, err := db.Exec("INSERT INTO tags (project_id, title, type) VALUES (?, ?, ?)", t.ProjectID, t.Title, t.Type)
if err != nil {
return 0, err
}
id, err := res.LastInsertId()
if err != nil {
return 0, err
}
return int(id), nil
}
func GetAllTagsOf(projectID int) ([]types.Tag, error) {
rows, err := db.Query("SELECT * FROM tags WHERE project_id = ?", projectID)
if err != nil {
return nil, err
}
defer rows.Close()
var tags []types.Tag
for rows.Next() {
var t types.Tag
if err := rows.Scan(&t.ID, &t.ProjectID, &t.Title, &t.Type); err != nil {
return nil, err
}
tags = append(tags, t)
}
if err = rows.Err(); err != nil {
return nil, err
}
return tags, nil
}
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)
if err != nil {
return nil, err
}
return &t, nil
}
func DeleteTag(id int) error {
_, err := db.Exec("DELETE FROM tags WHERE id = ?", id)
return err
}
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
}

View File

@ -9,7 +9,7 @@ import (
"github.com/gofiber/fiber/v2"
)
func CreateCards(c *fiber.Ctx) error {
func CreateCard(c *fiber.Ctx) error {
card := types.Card{}
if err := c.BodyParser(&card); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"})

View File

@ -0,0 +1,95 @@
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)
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{"error": "Invalid tag ID"})
}
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)
}

88
backend/handlers/tags.go Normal file
View File

@ -0,0 +1,88 @@
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 CreateTag(c *fiber.Ctx) error {
tag := types.Tag{}
if err := c.BodyParser(&tag); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"})
}
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.StatusCreated).JSON(fiber.Map{"id": id})
}
func GetAllTagsOf(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"})
}
projects, err := db.GetAllTagsOf(projectID)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot retrieve tags"})
}
return c.JSON(fiber.Map{"status": "ok", "data": projects})
}
func GetTag(c *fiber.Ctx) error {
id, err := strconv.Atoi(c.Params("id"))
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"})
}
tag, err := db.GetTag(id)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot retrieve tag"})
}
if tag == nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Tag not found"})
}
return c.JSON(tag)
}
func DeleteTag(c *fiber.Ctx) error {
id, err := strconv.Atoi(c.Params("id"))
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"})
}
err = db.DeleteTag(id)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot delete tag"})
}
return c.SendStatus(fiber.StatusNoContent)
}
func UpdateTag(c *fiber.Ctx) error {
id, err := strconv.Atoi(c.Params("id"))
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid tag ID"})
}
tag := types.Tag{ID: id}
if err := c.BodyParser(&tag); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Cannot parse request"})
}
err = db.UpdateTag(tag)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Cannot update tag"})
}
return c.SendStatus(fiber.StatusOK)
}

View File

@ -42,11 +42,23 @@ func main() {
app.Delete("/api/list/:id", handlers.DeleteList)
app.Put("/api/list/:id", handlers.UpdateList)
app.Post("/api/card", handlers.CreateCards)
app.Post("/api/card", handlers.CreateCard)
app.Get("/api/cards/:project_id", handlers.GetAllCardsOf)
app.Get("/api/card/:id", handlers.GetCard)
app.Delete("/api/card/:id", handlers.DeleteCard)
app.Put("/api/card/:id", handlers.UpdateCard)
app.Post("/api/tag", handlers.CreateTag)
app.Get("/api/tags/:project_id", handlers.GetAllTagsOf)
app.Get("/api/tag/:id", handlers.GetTag)
app.Delete("/api/tag/:id", handlers.DeleteTag)
app.Put("/api/tag/:id", handlers.UpdateTag)
app.Post("/api/cardtag", handlers.CreateTagOfCard)
app.Get("/api/cardtags/:card_id", handlers.GetAllTagsOfCard)
app.Delete("/api/cardtag/:card_id/:tag_id", handlers.DeleteTagOfCard)
app.Delete("/api/cardtags/:card_id", handlers.DeleteTagsOfCard)
app.Put("/api/cardtag/:card_id/:tag_id", handlers.UpdateTag)
log.Fatal(app.Listen(fmt.Sprintf(":%v", port)))
}

14
backend/types/cardtag.go Normal file
View File

@ -0,0 +1,14 @@
package types
type CardTag struct {
CardID int `json:"card_id"`
TagID int `json:"tag_id"`
Value string `json:"value"`
}
type FullCardTag struct {
CardID int `json:"card_id"`
TagID int `json:"tag_id"`
TagTitle string `json:"tag_title"`
Value string `json:"value"`
}

8
backend/types/tag.go Normal file
View File

@ -0,0 +1,8 @@
package types
type Tag struct {
ID int `json:"id"`
ProjectID int `json:"project_id"`
Title string `json:"title"`
Type int `json:"type"`
}

View File

@ -1,4 +1,9 @@
<script lang="ts">
import axios from 'axios';
import { onMount } from 'svelte';
const backend = 'http://127.0.0.1:3000';
interface Card {
id: number;
title: string;
@ -10,6 +15,24 @@
title: 'No title',
content: 'Nocontent'
};
interface FullTag {
tag_id: number;
tag_title: string;
value: string;
}
let tags: FullTag[];
onMount(async () => {
const response = await axios.get(`${backend}/api/cardtags/${card.id}`);
if (response.data.status === 'ok') {
tags = response.data.data;
} else {
console.error(response.data);
}
});
</script>
<svelte:head>
@ -18,8 +41,13 @@
<div class="card" draggable={true}>
<div class="title">{card.title}</div>
<div class="tags">
<span class="tag" style="background-color: #874d45;">HIGH</span>
<span class="tag" style="background-color: #4a8645;">PERSONAL</span>
</div>
{#if tags}
<div class="tags">
<!-- <span class="tag" style="background-color: #874d45;">HIGH</span>
<span class="tag" style="background-color: #4a8645;">PERSONAL</span> -->
{#each tags as tag}
<span class="tag" style="border: 1px solid #333">{tag.value}</span>
{/each}
</div>
{/if}
</div>