From 0c9048072fd25c8cb879c8bb6125103ed853b775 Mon Sep 17 00:00:00 2001 From: heimoshuiyu Date: Mon, 13 Dec 2021 23:18:46 +0800 Subject: [PATCH] Add: support feedback --- pkg/api/api.go | 1 + pkg/api/handle_feedback.go | 44 ++++++++++++++-- pkg/database/method.go | 8 --- pkg/database/method_feedback.go | 32 ++++++++++++ pkg/database/sql_stmt.go | 22 ++++++-- pkg/database/struct.go | 9 ++++ web/src/App.js | 5 ++ web/src/component/FeedbackPage.js | 83 +++++++++++++++++++++++++++++++ web/src/component/Manage.js | 1 + 9 files changed, 190 insertions(+), 15 deletions(-) create mode 100644 pkg/database/method_feedback.go create mode 100644 web/src/component/FeedbackPage.js diff --git a/pkg/api/api.go b/pkg/api/api.go index ebfedc5..2522f0b 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -76,6 +76,7 @@ func NewAPI(config Config) (*API, error) { apiMux.HandleFunc("/get_file_stream", api.HandleGetFileStream) apiMux.HandleFunc("/get_ffmpeg_config_list", api.HandleGetFfmpegConfigs) apiMux.HandleFunc("/feedback", api.HandleFeedback) + apiMux.HandleFunc("/get_feedbacks", api.HandleGetFeedbacks) apiMux.HandleFunc("/get_file_info", api.HandleGetFileInfo) apiMux.HandleFunc("/get_file_stream_direct", api.HandleGetFileStreamDirect) apiMux.HandleFunc("/prepare_file_stream_direct", api.HandlePrepareFileStreamDirect) diff --git a/pkg/api/handle_feedback.go b/pkg/api/handle_feedback.go index f9375dd..018b666 100644 --- a/pkg/api/handle_feedback.go +++ b/pkg/api/handle_feedback.go @@ -4,12 +4,13 @@ import ( "bytes" "encoding/json" "log" + "msw-open-music/pkg/database" "net/http" "time" ) type FeedbackRequest struct { - Feedback string `json:"feedback"` + Content string `json:"content"` } func (api *API) HandleFeedback(w http.ResponseWriter, r *http.Request) { @@ -21,12 +22,12 @@ func (api *API) HandleFeedback(w http.ResponseWriter, r *http.Request) { } // check empty feedback - if feedbackRequest.Feedback == "" { + if feedbackRequest.Content == "" { api.HandleErrorString(w, r, `"feedback" can't be empty`) return } - log.Println("[api] Feedback", feedbackRequest.Feedback) + log.Println("[api] Feedback", feedbackRequest.Content) headerBuff := &bytes.Buffer{} err = r.Header.Write(headerBuff) @@ -36,10 +37,45 @@ func (api *API) HandleFeedback(w http.ResponseWriter, r *http.Request) { } header := headerBuff.String() - err = api.Db.InsertFeedback(time.Now().Unix(), feedbackRequest.Feedback, header) + userID, err := api.GetUserID(w, r) + if err != nil { + api.HandleError(w, r, err) + return + } + + err = api.Db.InsertFeedback(time.Now().Unix(), feedbackRequest.Content, userID, header) if err != nil { api.HandleError(w, r, err) return } api.HandleOK(w, r) } + +type GetFeedbacksResponse struct { + Feedbacks []*database.Feedback `json:"feedbacks"` +} + +func (api *API) HandleGetFeedbacks(w http.ResponseWriter, r *http.Request) { + // check if admin + err := api.CheckAdmin(w, r) + if err != nil { + api.HandleError(w, r, err) + return + } + + feedbacks, err := api.Db.GetFeedbacks() + if err != nil { + api.HandleError(w, r, err) + return + } + + resp := &GetFeedbacksResponse{ + Feedbacks: feedbacks, + } + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + api.HandleError(w, r, err) + return + } +} diff --git a/pkg/database/method.go b/pkg/database/method.go index 8db719a..febe89f 100644 --- a/pkg/database/method.go +++ b/pkg/database/method.go @@ -7,14 +7,6 @@ import ( "path/filepath" ) -func (database *Database) InsertFeedback(time int64, feedback string, header string) error { - _, err := database.stmt.insertFeedback.Exec(time, feedback, header) - if err != nil { - return err - } - return nil -} - func (database *Database) GetRandomFiles(limit int64) ([]File, error) { rows, err := database.stmt.getRandomFiles.Query(limit) if err != nil { diff --git a/pkg/database/method_feedback.go b/pkg/database/method_feedback.go new file mode 100644 index 0000000..4c4f5d9 --- /dev/null +++ b/pkg/database/method_feedback.go @@ -0,0 +1,32 @@ +package database + +func (database *Database) InsertFeedback(time int64, content string, userID int64, header string) error { + _, err := database.stmt.insertFeedback.Exec(time, content, userID, header) + if err != nil { + return err + } + return nil +} + +func (database *Database) GetFeedbacks() ([]*Feedback, error) { + rows, err := database.stmt.getFeedbacks.Query() + if err != nil { + return nil, err + } + defer rows.Close() + + feedbacks := make([]*Feedback, 0) + for rows.Next() { + feedback := &Feedback{ + User: &User{}, + } + err := rows.Scan( + &feedback.ID, &feedback.Time, &feedback.Content, &feedback.Header, + &feedback.User.ID, &feedback.User.Username, &feedback.User.Role, &feedback.User.Active, &feedback.User.AvatarId) + if err != nil { + return nil, err + } + feedbacks = append(feedbacks, feedback) + } + return feedbacks, nil +} diff --git a/pkg/database/sql_stmt.go b/pkg/database/sql_stmt.go index dfb36f6..98ba6c1 100644 --- a/pkg/database/sql_stmt.go +++ b/pkg/database/sql_stmt.go @@ -21,7 +21,8 @@ var initFoldersTableQuery = `CREATE TABLE IF NOT EXISTS folders ( var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks ( id INTEGER PRIMARY KEY, time INTEGER NOT NULL, - feedback TEXT NOT NULL, + content TEXT NOT NULL, + user_id INTEGER NOT NULL, header TEXT NOT NULL );` @@ -168,8 +169,16 @@ WHERE file_has_tag.tag_id = ? ORDER BY RANDOM() LIMIT ?;` -var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback, header) -VALUES (?, ?, ?);` +var insertFeedbackQuery = `INSERT INTO feedbacks (time, content, user_id, header) +VALUES (?, ?, ?, ?);` + +var getFeedbacksQuery = `SELECT +feedbacks.id, feedbacks.time, feedbacks.content, feedbacks.header, +users.id, users.username, users.role, users.active, users.avatar_id +FROM feedbacks +JOIN users ON feedbacks.user_id = users.id +ORDER BY feedbacks.time +;` var insertUserQuery = `INSERT INTO users (username, password, role, active, avatar_id) VALUES (?, ?, ?, ?, ?);` @@ -280,6 +289,7 @@ type Stmt struct { getRandomFiles *sql.Stmt getRandomFilesWithTag *sql.Stmt insertFeedback *sql.Stmt + getFeedbacks *sql.Stmt insertUser *sql.Stmt countUser *sql.Stmt countAdmin *sql.Stmt @@ -517,6 +527,12 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { return nil, err } + // init getFeedbacks + stmt.getFeedbacks, err = sqlConn.Prepare(getFeedbacksQuery) + if err != nil { + return nil, err + } + // init insertUser stmt.insertUser, err = sqlConn.Prepare(insertUserQuery) if err != nil { diff --git a/pkg/database/struct.go b/pkg/database/struct.go index f02455c..fa8afce 100644 --- a/pkg/database/struct.go +++ b/pkg/database/struct.go @@ -48,6 +48,15 @@ type Review struct { Content string `json:"content"` } +type Feedback struct { + ID int64 `json:"id"` + UserId int64 `json:"user_id"` + User *User `json:"user"` + Content string `json:"content"` + Header string `json:"header"` + Time int64 `json:"time"` +} + var ( RoleAnonymous = int64(0) RoleAdmin = int64(1) diff --git a/web/src/App.js b/web/src/App.js index 6a961ad..6b0b011 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -18,6 +18,7 @@ import AudioPlayer from "./component/AudioPlayer"; import UserStatus from "./component/UserStatus"; import ReviewPage from "./component/ReviewPage"; import UserProfile from "./component/UserProfile"; +import FeedbackPage from "./component/FeedbackPage"; import { useState } from "react"; function App() { @@ -70,6 +71,10 @@ function App() { path="/manage" element={} /> + } + /> } diff --git a/web/src/component/FeedbackPage.js b/web/src/component/FeedbackPage.js new file mode 100644 index 0000000..f92fdb1 --- /dev/null +++ b/web/src/component/FeedbackPage.js @@ -0,0 +1,83 @@ +import { useState, useEffect } from "react"; +import { Link } from "react-router-dom"; +import { convertIntToDateTime } from "./Common"; + +function FeedbackPage() { + const [content, setContext] = useState(""); + const [feedbacks, setFeedbacks] = useState([]); + + function getFeedbacks() { + fetch("/api/v1/get_feedbacks") + .then((res) => res.json()) + .then((data) => { + if (data.error) { + console.log(data.error); + } else { + setFeedbacks(data.feedbacks); + } + }); + } + + function submitFeedback() { + fetch("/api/v1/feedback", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + content: content, + }), + }) + .then((res) => res.json()) + .then((data) => { + if (data.error) { + alert(data.error); + } else { + setContext(""); + getFeedbacks(); + } + }); + } + + useEffect(() => { + getFeedbacks(); + }, []); + + return ( +
+

Feedback

+