diff --git a/pkg/api/api.go b/pkg/api/api.go index abe1c62..929a259 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -82,6 +82,10 @@ func NewAPI(config Config) (*API, error) { apiMux.HandleFunc("/login", api.HandleLogin) apiMux.HandleFunc("/register", api.HandleRegister) apiMux.HandleFunc("/logout", api.LoginAsAnonymous) + // tag + apiMux.HandleFunc("/get_tags", api.HandleGetTags) + apiMux.HandleFunc("/get_tag_info", api.HandleGetTagInfo) + apiMux.HandleFunc("/insert_tag", api.HandleInsertTag) // below needs token apiMux.HandleFunc("/walk", api.HandleWalk) apiMux.HandleFunc("/reset", api.HandleReset) diff --git a/pkg/api/handle_tag.go b/pkg/api/handle_tag.go new file mode 100644 index 0000000..2988386 --- /dev/null +++ b/pkg/api/handle_tag.go @@ -0,0 +1,93 @@ +package api + +import ( + "encoding/json" + "log" + "msw-open-music/pkg/database" + "net/http" +) + +type getTagsResponse struct { + Tags []database.Tag `json:"tags"` +} + +func (api *API) HandleGetTags(w http.ResponseWriter, r *http.Request) { + tags, err := api.Db.GetTags() + if err != nil { + api.HandleError(w, r, err) + return + } + + log.Println("Successfully got tags") + + resp := &getTagsResponse{Tags: tags} + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + api.HandleError(w, r, err) + return + } +} + +type InsertTagRequest struct { + Name string `json:"name"` + Description string `json:"description"` +} + +type InsertTagResponse struct { + Tag *database.Tag `json:"tag"` +} + +func (api *API) HandleInsertTag(w http.ResponseWriter, r *http.Request) { + var req InsertTagRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + api.HandleError(w, r, err) + return + } + + tag, err := api.Db.InsertTag(req.Name, req.Description) + if err != nil { + api.HandleError(w, r, err) + return + } + + resp := &InsertTagResponse{Tag: tag} + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + api.HandleError(w, r, err) + return + } +} + +type GetTagInfoRequest struct { + ID int64 `json:"id"` +} + +type GetTagInfoResponse struct { + Tag *database.Tag `json:"tag"` +} + +func (api *API) HandleGetTagInfo(w http.ResponseWriter, r *http.Request) { + var req GetTagInfoRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + api.HandleError(w, r, err) + return + } + + tag, err := api.Db.GetTag(req.ID) + if err != nil { + api.HandleError(w, r, err) + return + } + + resp := &GetTagInfoResponse{Tag: tag} + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + api.HandleError(w, r, err) + return + } +} diff --git a/pkg/database/method_tag.go b/pkg/database/method_tag.go new file mode 100644 index 0000000..e2737ff --- /dev/null +++ b/pkg/database/method_tag.go @@ -0,0 +1,40 @@ +package database + +func (database *Database) InsertTag(tag string, description string) (*Tag, error) { + result, err := database.stmt.insertTag.Exec(tag, description) + if err != nil { + return nil, err + } + id, err := result.LastInsertId() + if err != nil { + return nil, err + } + return database.GetTag(id) +} + +func (database *Database) GetTag(id int64) (*Tag, error) { + tag := &Tag{} + err := database.stmt.getTag.QueryRow(id).Scan(&tag.ID, &tag.Name, &tag.Description) + if err != nil { + return nil, err + } + return tag, nil +} + +func (database *Database) GetTags() ([]Tag, error) { + tags := []Tag{} + rows, err := database.stmt.getTags.Query() + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + tag := Tag{} + err := rows.Scan(&tag.ID, &tag.Name, &tag.Description) + if err != nil { + return nil, err + } + tags = append(tags, tag) + } + return tags, nil +} diff --git a/pkg/database/sql_stmt.go b/pkg/database/sql_stmt.go index a04b2ef..496f3fb 100644 --- a/pkg/database/sql_stmt.go +++ b/pkg/database/sql_stmt.go @@ -43,8 +43,9 @@ var initAvatarsTableQuery = `CREATE TABLE IF NOT EXISTS avatars ( );` var initTagsTableQuery = `CREATE TABLE IF NOT EXISTS tags ( - id INTEGER PRIMARY KEY, - tag TEXT NOT NULL + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL UNIQUE, + description TEXT NOT NULL );` var initFileHasTagTableQuery = `CREATE TABLE IF NOT EXISTS file_has_tag ( @@ -169,6 +170,12 @@ var getUserByIdQuery = `SELECT id, username, role, avatar_id FROM users WHERE id var getAnonymousUserQuery = `SELECT id, username, role, avatar_id FROM users WHERE role = 0 LIMIT 1;` +var insertTagQuery = `INSERT INTO tags (name, description) VALUES (?, ?);` + +var getTagQuery = `SELECT id, name, description FROM tags WHERE id = ? LIMIT 1;` + +var getTagsQuery = `SELECT id, name, description FROM tags;` + type Stmt struct { initFilesTable *sql.Stmt initFoldersTable *sql.Stmt @@ -201,6 +208,9 @@ type Stmt struct { getUser *sql.Stmt getUserById *sql.Stmt getAnonymousUser *sql.Stmt + insertTag *sql.Stmt + getTag *sql.Stmt + getTags *sql.Stmt } func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { @@ -457,5 +467,23 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { } } + // init insertTag + stmt.insertTag, err = sqlConn.Prepare(insertTagQuery) + if err != nil { + return nil, err + } + + // init getTag + stmt.getTag, err = sqlConn.Prepare(getTagQuery) + if err != nil { + return nil, err + } + + // init getTags + stmt.getTags, err = sqlConn.Prepare(getTagsQuery) + if err != nil { + return nil, err + } + return stmt, err } diff --git a/pkg/database/struct.go b/pkg/database/struct.go index c7d92ee..13aab35 100644 --- a/pkg/database/struct.go +++ b/pkg/database/struct.go @@ -28,10 +28,16 @@ type User struct { AvatarId int64 `json:"avatar_id"` } +type Tag struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` +} + var ( RoleAnonymous = int64(0) - RoleAdmin = int64(1) - RoleUser = int64(2) + RoleAdmin = int64(1) + RoleUser = int64(2) ) func (f *File) Path() (string, error) { diff --git a/web/src/App.js b/web/src/App.js index afc4b5a..a51c6d0 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -9,6 +9,8 @@ import Manage from "./component/Manage"; import Share from "./component/Share"; import Login from "./component/Login"; import Register from "./component/Register"; +import Tags from "./component/Tags"; +import EditTag from "./component/EditTag"; import AudioPlayer from "./component/AudioPlayer"; import UserStatus from "./component/UserStatus"; import { useState } from "react"; @@ -59,9 +61,26 @@ function App() { path="/folders/:id" element={} /> - } /> - } /> - } /> + } + /> + } + /> + } + /> + } + /> + } + /> } diff --git a/web/src/component/EditTag.js b/web/src/component/EditTag.js new file mode 100644 index 0000000..e339f7b --- /dev/null +++ b/web/src/component/EditTag.js @@ -0,0 +1,62 @@ +import { useState, useEffect } from "react"; +import { useParams } from "react-router"; + +function EditTag() { + let params = useParams(); + const [tag, setTag] = useState({}); + + useEffect(() => { + fetch("/api/v1/get_tag_info", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + id: parseInt(params.id), + }), + }) + .then((res) => res.json()) + .then((data) => { + if (data.error) { + alert(data.error); + } else { + setTag(data.tag); + } + }); + }, []); + + return ( +
+

Edit Tag

+
+ + setTag({ ...tag, id: e.target.value })} + /> + + setTag({ ...tag, name: e.target.value })} + /> + +