diff --git a/pkg/api/api.go b/pkg/api/api.go index 0935b6a..0a3e45c 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -89,6 +89,7 @@ func NewAPI(config Config) (*API, error) { apiMux.HandleFunc("/update_tag", api.HandleUpdateTag) apiMux.HandleFunc("/put_tag_on_file", api.HandlePutTagOnFile) apiMux.HandleFunc("/get_tags_on_file", api.HandleGetTagsOnFile) + apiMux.HandleFunc("/delete_tag_on_file", api.HandleDeleteTagOnFile) // below needs token apiMux.HandleFunc("/walk", api.HandleWalk) apiMux.HandleFunc("/reset", api.HandleReset) diff --git a/pkg/api/handle_tag_and_file.go b/pkg/api/handle_tag_and_file.go index da8343f..814d0cb 100644 --- a/pkg/api/handle_tag_and_file.go +++ b/pkg/api/handle_tag_and_file.go @@ -80,3 +80,40 @@ func (api *API) HandleGetTagsOnFile(w http.ResponseWriter, r *http.Request) { return } } + +type DeleteTagOnFileRequest struct { + TagID int64 `json:"tag_id"` + FileID int64 `json:"file_id"` +} + +func (api *API) HandleDeleteTagOnFile(w http.ResponseWriter, r *http.Request) { + // check if the user is admin + err := api.CheckAdmin(w, r) + if err != nil { + api.HandleError(w, r, err) + return + } + + req := &DeleteTagOnFileRequest{} + err = json.NewDecoder(r.Body).Decode(req) + if err != nil { + api.HandleError(w, r, err) + return + } + + // check empty + if req.TagID == 0 || req.FileID == 0 { + api.HandleError(w, r, ErrEmpty) + return + } + + log.Println("Delete tag on file request:", req) + + err = api.Db.DeleteTagOnFile(req.TagID, req.FileID) + if err != nil { + api.HandleError(w, r, err) + return + } + + api.HandleOK(w, r) +} diff --git a/pkg/database/error.go b/pkg/database/error.go new file mode 100644 index 0000000..f298618 --- /dev/null +++ b/pkg/database/error.go @@ -0,0 +1,10 @@ +package database + +import ( + "errors" +) + +var ( + ErrNotFound = errors.New("object not found") + ErrTagNotFound = errors.New("tag not found") +) diff --git a/pkg/database/method_tag_and_file.go b/pkg/database/method_tag_and_file.go index 1a7f3a2..2715bbe 100644 --- a/pkg/database/method_tag_and_file.go +++ b/pkg/database/method_tag_and_file.go @@ -1,8 +1,14 @@ package database func (database *Database) PutTagOnFile(tagID, fileID, userID int64) error { - _, err := database.stmt.putTagOnFile.Exec(tagID, fileID, userID) - return err + result, err := database.stmt.putTagOnFile.Exec(tagID, fileID, userID) + if err != nil { + return err + } + if rows, _ := result.RowsAffected(); rows == 0 { + return ErrTagNotFound + } + return nil } func (database *Database) GetTagsOnFile(fileID int64) ([]*Tag, error) { @@ -23,3 +29,14 @@ func (database *Database) GetTagsOnFile(fileID int64) ([]*Tag, error) { } return tags, nil } + +func (database *Database) DeleteTagOnFile(tagID, fileID int64) error { + result, err := database.stmt.deleteTagOnFile.Exec(tagID, fileID) + if err != nil { + return err + } + if rows, _ := result.RowsAffected(); rows == 0 { + return ErrTagNotFound + } + return nil +} diff --git a/pkg/database/sql_stmt.go b/pkg/database/sql_stmt.go index 7d83d20..1004073 100644 --- a/pkg/database/sql_stmt.go +++ b/pkg/database/sql_stmt.go @@ -198,6 +198,8 @@ FROM file_has_tag JOIN tags ON file_has_tag.tag_id = tags.id WHERE file_has_tag.file_id = ?;` +var deleteTagOnFileQuery = `DELETE FROM file_has_tag WHERE tag_id = ? AND file_id = ?;` + type Stmt struct { initFilesTable *sql.Stmt initFoldersTable *sql.Stmt @@ -236,6 +238,7 @@ type Stmt struct { updateTag *sql.Stmt putTagOnFile *sql.Stmt getTagsOnFile *sql.Stmt + deleteTagOnFile *sql.Stmt } func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { @@ -528,5 +531,11 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { return nil, err } + // init deleteTagOnFile + stmt.deleteTagOnFile, err = sqlConn.Prepare(deleteTagOnFileQuery) + if err != nil { + return nil, err + } + return stmt, err } diff --git a/web/src/component/FileInfo.js b/web/src/component/FileInfo.js index 6eace3b..f1b5523 100644 --- a/web/src/component/FileInfo.js +++ b/web/src/component/FileInfo.js @@ -67,6 +67,27 @@ function FileInfo(props) { }); } + function removeTagOnFile(tag_id) { + fetch(`/api/v1/delete_tag_on_file`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + file_id: parseInt(params.id), + tag_id: tag_id, + }), + }) + .then((res) => res.json()) + .then((data) => { + if (data.error) { + alert(data.error); + } else { + getTagsOnFile(); + } + }); + } + useEffect(() => { refresh(); getTags(); @@ -116,7 +137,13 @@ function FileInfo(props) { return (