Tags
This commit is contained in:
parent
e0056809b3
commit
c4b41d79a2
|
@ -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
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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"})
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
|
@ -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"`
|
||||
}
|
|
@ -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>
|
||||
{#if tags}
|
||||
<div class="tags">
|
||||
<span class="tag" style="background-color: #874d45;">HIGH</span>
|
||||
<span class="tag" style="background-color: #4a8645;">PERSONAL</span>
|
||||
<!-- <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>
|
||||
|
|
Loading…
Reference in New Issue