Add: support feedback

This commit is contained in:
2021-12-13 23:18:46 +08:00
parent 22f7ea8476
commit 0c9048072f
9 changed files with 190 additions and 15 deletions

View File

@@ -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)

View File

@@ -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
}
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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={<Manage user={user} setUser={setUser} />}
/>
<Route
path="/manage/feedbacks"
element={<FeedbackPage user={user} />}
/>
<Route
path="/manage/login"
element={<Login user={user} setUser={setUser} />}

View File

@@ -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 (
<div className="page">
<h3>Feedback</h3>
<textarea value={content} onChange={(e) => setContext(e.target.value)} />
<button onClick={() => submitFeedback()}>Submit</button>
<div>
<table>
<thead>
<tr>
<th>User</th>
<th>Feedback</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{feedbacks.map((feedback) => (
<tr key={feedback._id}>
<td>
<Link to={`/manage/users/${feedback.user.id}`}>
@{feedback.user.username}
</Link>
</td>
<td>{feedback.content}</td>
<td>{convertIntToDateTime(feedback.time)}</td>
<td>
<button onClick={() => {}}>Delete</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
export default FeedbackPage;

View File

@@ -46,6 +46,7 @@ function Manage(props) {
<hr />
<button onClick={() => navigate("/manage/tags")}>Tags</button>
<button onClick={() => navigate("/manage/users")}>Users</button>
<button onClick={() => navigate("/manage/feedbacks")}>Feedbacks</button>
<Database />
</div>
);