From 83ab1a91b2bbce11a46b1ed320deff6dbf7e8086 Mon Sep 17 00:00:00 2001 From: heimoshuiyu Date: Tue, 14 Dec 2021 00:33:31 +0800 Subject: [PATCH] Add: support delete tag and its references --- pkg/api/api.go | 1 + pkg/api/handle_tag.go | 31 +++++++++ pkg/database/method_tag.go | 30 +++++++++ pkg/database/sql_stmt.go | 123 ++++++++++++++++++++--------------- web/src/component/EditTag.js | 26 +++++++- 5 files changed, 158 insertions(+), 53 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 25759b2..42527bb 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -99,6 +99,7 @@ func NewAPI(config Config) (*API, error) { apiMux.HandleFunc("/put_tag_on_file", api.HandlePutTagOnFile) apiMux.HandleFunc("/get_tags_on_file", api.HandleGetTagsOnFile) apiMux.HandleFunc("/delete_tag_on_file", api.HandleDeleteTagOnFile) + apiMux.HandleFunc("/delete_tag", api.HandleDeleteTag) // folder apiMux.HandleFunc("/update_foldername", api.HandleUpdateFoldername) // review diff --git a/pkg/api/handle_tag.go b/pkg/api/handle_tag.go index 79838e4..2070e7c 100644 --- a/pkg/api/handle_tag.go +++ b/pkg/api/handle_tag.go @@ -125,3 +125,34 @@ func (api *API) HandleUpdateTag(w http.ResponseWriter, r *http.Request) { return } } + +type DeleteTagRequest struct { + ID int64 `json:"id"` +} + +func (api *API) HandleDeleteTag(w http.ResponseWriter, r *http.Request) { + // check if user is admin + err := api.CheckAdmin(w, r) + if err != nil { + api.HandleError(w, r, err) + return + } + + req := &DeleteTagRequest{} + err = json.NewDecoder(r.Body).Decode(req) + if err != nil { + api.HandleError(w, r, err) + return + } + + err = api.Db.DeleteTag(req.ID) + if err != nil { + api.HandleError(w, r, err) + return + } + + log.Println("Successfully deleted tag and its references", req.ID) + + api.HandleOK(w, r) +} + diff --git a/pkg/database/method_tag.go b/pkg/database/method_tag.go index a07bc4e..dde1226 100644 --- a/pkg/database/method_tag.go +++ b/pkg/database/method_tag.go @@ -60,3 +60,33 @@ func (database *Database) UpdateTag(tag *Tag) (*Tag, error) { } return database.GetTag(tag.ID) } + +// delete tag and all its references in file_has_tag +func (database *Database) DeleteTag(id int64) error { + // begin transaction + tx, err := database.sqlConn.Begin() + if err != nil { + return err + } + + // delete tag + _, err = tx.Stmt(database.stmt.deleteTag).Exec(id) + if err != nil { + tx.Rollback() + return err + } + + // delete file_has_tag + _, err = tx.Stmt(database.stmt.deleteTagReferenceInFileHasTag).Exec(id) + if err != nil { + tx.Rollback() + return err + } + + // commit transaction + err = tx.Commit() + if err != nil { + return err + } + return nil +} diff --git a/pkg/database/sql_stmt.go b/pkg/database/sql_stmt.go index 4719db0..d2b4c25 100644 --- a/pkg/database/sql_stmt.go +++ b/pkg/database/sql_stmt.go @@ -205,6 +205,8 @@ var getAnonymousUserQuery = `SELECT id, username, role, avatar_id FROM users WHE var insertTagQuery = `INSERT INTO tags (name, description, created_by_user_id) VALUES (?, ?, ?);` +var deleteTagQuery = `DELETE FROM tags WHERE id = ?;` + var getTagQuery = `SELECT tags.id, tags.name, tags.description, users.id, users.username, users.role, users.avatar_id @@ -231,6 +233,8 @@ WHERE file_has_tag.file_id = ?;` var deleteTagOnFileQuery = `DELETE FROM file_has_tag WHERE tag_id = ? AND file_id = ?;` +var deleteTagReferenceInFileHasTagQuery = `DELETE FROM file_has_tag WHERE tag_id = ?;` + var updateFoldernameQuery = `UPDATE folders SET foldername = ? WHERE id = ?;` var insertReviewQuery = `INSERT INTO reviews (user_id, file_id, created_at, content) @@ -265,58 +269,60 @@ ORDER BY reviews.created_at ;` type Stmt struct { - initFilesTable *sql.Stmt - initFoldersTable *sql.Stmt - initFeedbacksTable *sql.Stmt - initUsersTable *sql.Stmt - initAvatarsTable *sql.Stmt - initTagsTable *sql.Stmt - initFileHasTag *sql.Stmt - initLikesTable *sql.Stmt - initReviewsTable *sql.Stmt - initPlaybacksTable *sql.Stmt - initLogsTable *sql.Stmt - initTmpfsTable *sql.Stmt - insertFolder *sql.Stmt - insertFile *sql.Stmt - findFolder *sql.Stmt - findFile *sql.Stmt - searchFiles *sql.Stmt - getFolder *sql.Stmt - dropFiles *sql.Stmt - dropFolder *sql.Stmt - getFile *sql.Stmt - searchFolders *sql.Stmt - getFilesInFolder *sql.Stmt - getRandomFiles *sql.Stmt - getRandomFilesWithTag *sql.Stmt - insertFeedback *sql.Stmt - getFeedbacks *sql.Stmt - deleteFeedback *sql.Stmt - insertUser *sql.Stmt - countUser *sql.Stmt - countAdmin *sql.Stmt - getUser *sql.Stmt - getUsers *sql.Stmt - getUserById *sql.Stmt - updateUserActive *sql.Stmt - updateUsername *sql.Stmt - updateUserPassword *sql.Stmt - getAnonymousUser *sql.Stmt - insertTag *sql.Stmt - getTag *sql.Stmt - getTags *sql.Stmt - updateTag *sql.Stmt - putTagOnFile *sql.Stmt - getTagsOnFile *sql.Stmt - deleteTagOnFile *sql.Stmt - updateFoldername *sql.Stmt - insertReview *sql.Stmt - getReviewsOnFile *sql.Stmt - getReview *sql.Stmt - updateReview *sql.Stmt - deleteReview *sql.Stmt - getReviewsByUser *sql.Stmt + initFilesTable *sql.Stmt + initFoldersTable *sql.Stmt + initFeedbacksTable *sql.Stmt + initUsersTable *sql.Stmt + initAvatarsTable *sql.Stmt + initTagsTable *sql.Stmt + initFileHasTag *sql.Stmt + initLikesTable *sql.Stmt + initReviewsTable *sql.Stmt + initPlaybacksTable *sql.Stmt + initLogsTable *sql.Stmt + initTmpfsTable *sql.Stmt + insertFolder *sql.Stmt + insertFile *sql.Stmt + findFolder *sql.Stmt + findFile *sql.Stmt + searchFiles *sql.Stmt + getFolder *sql.Stmt + dropFiles *sql.Stmt + dropFolder *sql.Stmt + getFile *sql.Stmt + searchFolders *sql.Stmt + getFilesInFolder *sql.Stmt + getRandomFiles *sql.Stmt + getRandomFilesWithTag *sql.Stmt + insertFeedback *sql.Stmt + getFeedbacks *sql.Stmt + deleteFeedback *sql.Stmt + insertUser *sql.Stmt + countUser *sql.Stmt + countAdmin *sql.Stmt + getUser *sql.Stmt + getUsers *sql.Stmt + getUserById *sql.Stmt + updateUserActive *sql.Stmt + updateUsername *sql.Stmt + updateUserPassword *sql.Stmt + getAnonymousUser *sql.Stmt + insertTag *sql.Stmt + deleteTag *sql.Stmt + getTag *sql.Stmt + getTags *sql.Stmt + updateTag *sql.Stmt + putTagOnFile *sql.Stmt + getTagsOnFile *sql.Stmt + deleteTagOnFile *sql.Stmt + deleteTagReferenceInFileHasTag *sql.Stmt + updateFoldername *sql.Stmt + insertReview *sql.Stmt + getReviewsOnFile *sql.Stmt + getReview *sql.Stmt + updateReview *sql.Stmt + deleteReview *sql.Stmt + getReviewsByUser *sql.Stmt } func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { @@ -621,6 +627,12 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { return nil, err } + // init deleteTag + stmt.deleteTag, err = sqlConn.Prepare(deleteTagQuery) + if err != nil { + return nil, err + } + // init getTag stmt.getTag, err = sqlConn.Prepare(getTagQuery) if err != nil { @@ -657,6 +669,13 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { return nil, err } + // init deleteTagReferenceInFileHasTag + stmt.deleteTagReferenceInFileHasTag, err = sqlConn.Prepare( + deleteTagReferenceInFileHasTagQuery) + if err != nil { + return nil, err + } + // init updateFoldername stmt.updateFoldername, err = sqlConn.Prepare(updateFoldernameQuery) if err != nil { diff --git a/web/src/component/EditTag.js b/web/src/component/EditTag.js index 6674a39..02ece18 100644 --- a/web/src/component/EditTag.js +++ b/web/src/component/EditTag.js @@ -1,8 +1,10 @@ import { useState, useEffect } from "react"; -import { useParams } from "react-router"; +import { useParams, useNavigate } from "react-router"; function EditTag() { let params = useParams(); + let navigate = useNavigate(); + const [tag, setTag] = useState({ id: "", name: "", @@ -62,6 +64,27 @@ function EditTag() { refreshTagInfo(); }, []); + function deleteTag() { + fetch("/api/v1/delete_tag", { + 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 { + alert("Tag deleted successfully"); + navigate(-1); + } + }); + } + return (

Edit Tag

@@ -107,6 +130,7 @@ function EditTag() { value={tag.description} onChange={(e) => setTag({ ...tag, description: e.target.value })} /> +