diff --git a/pkg/api/api.go b/pkg/api/api.go index 6e1c457..0a41ce9 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -94,6 +94,7 @@ func NewAPI(config Config) (*API, error) { apiMux.HandleFunc("/update_foldername", api.HandleUpdateFoldername) // review apiMux.HandleFunc("/insert_review", api.HandleInsertReview) + apiMux.HandleFunc("/get_reviews_on_file", api.HandleGetReviewsOnFile) // below needs token apiMux.HandleFunc("/walk", api.HandleWalk) apiMux.HandleFunc("/reset", api.HandleReset) diff --git a/pkg/api/handle_review.go b/pkg/api/handle_review.go index d0c506d..8760e72 100644 --- a/pkg/api/handle_review.go +++ b/pkg/api/handle_review.go @@ -1,9 +1,9 @@ package api import ( - "net/http" - "msw-open-music/pkg/database" "encoding/json" + "msw-open-music/pkg/database" + "net/http" "time" ) @@ -17,13 +17,6 @@ func (api *API) HandleInsertReview(w http.ResponseWriter, r *http.Request) { return } - // check not anonymous - err = api.CheckNotAnonymous(w, r) - if err != nil { - api.HandleError(w, r, err) - return - } - review.UserId, err = api.GetUserID(w, r) if err != nil { api.HandleError(w, r, err) @@ -40,3 +33,37 @@ func (api *API) HandleInsertReview(w http.ResponseWriter, r *http.Request) { api.HandleOK(w, r) } + +type GetReviewsOnFileRequest struct { + ID int64 `json:"id"` +} + +type GetReviewsOnFileResponse struct { + Reviews []*database.Review `json:"reviews"` +} + +func (api *API) HandleGetReviewsOnFile(w http.ResponseWriter, r *http.Request) { + req := &GetReviewsOnFileRequest{} + + err := json.NewDecoder(r.Body).Decode(req) + if err != nil { + api.HandleError(w, r, err) + return + } + + reviews, err := api.Db.GetReviewsOnFile(req.ID) + if err != nil { + api.HandleError(w, r, err) + return + } + + resp := &GetReviewsOnFileResponse{ + Reviews: reviews, + } + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + api.HandleError(w, r, err) + return + } +} diff --git a/pkg/database/method_review.go b/pkg/database/method_review.go index e8ce405..571684c 100644 --- a/pkg/database/method_review.go +++ b/pkg/database/method_review.go @@ -8,3 +8,35 @@ func (database *Database) InsertReview(review *Review) error { review.Content) return err } + +func (database *Database) GetReviewsOnFile(fileId int64) ([]*Review, error) { + rows, err := database.stmt.getReviewsOnFile.Query(fileId) + if err != nil { + return nil, err + } + defer rows.Close() + + reviews := make([]*Review, 0) + for rows.Next() { + review := &Review{ + User: &User{}, + File: &File{}, + } + err := rows.Scan( + &review.ID, + &review.CreatedAt, + &review.UpdatedAt, + &review.Content, + &review.User.ID, + &review.User.Username, + &review.User.Role, + &review.User.AvatarId, + &review.File.ID, + &review.File.Filename) + if err != nil { + return nil, err + } + reviews = append(reviews, review) + } + return reviews, nil +} diff --git a/pkg/database/sql_stmt.go b/pkg/database/sql_stmt.go index d132666..6beae4c 100644 --- a/pkg/database/sql_stmt.go +++ b/pkg/database/sql_stmt.go @@ -207,6 +207,17 @@ var updateFoldernameQuery = `UPDATE folders SET foldername = ? WHERE id = ?;` var insertReviewQuery = `INSERT INTO reviews (user_id, file_id, created_at, content) VALUES (?, ?, ?, ?);` +var getReviewsOnFileQuery = `SELECT +reviews.id, reviews.created_at, reviews.updated_at, reviews.content, +users.id, users.username, users.role, users.avatar_id, +files.id, files.filename +FROM reviews +JOIN users ON reviews.user_id = users.id +JOIN files ON reviews.file_id = files.id +WHERE reviews.file_id = ? +ORDER BY reviews.created_at +;` + type Stmt struct { initFilesTable *sql.Stmt initFoldersTable *sql.Stmt @@ -248,6 +259,7 @@ type Stmt struct { deleteTagOnFile *sql.Stmt updateFoldername *sql.Stmt insertReview *sql.Stmt + getReviewsOnFile *sql.Stmt } func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { @@ -558,5 +570,11 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { return nil, err } + // init getReviewsOnFile + stmt.getReviewsOnFile, err = sqlConn.Prepare(getReviewsOnFileQuery) + if err != nil { + return nil, err + } + return stmt, err } diff --git a/web/src/component/Common.js b/web/src/component/Common.js index 2f11179..e79cb0f 100644 --- a/web/src/component/Common.js +++ b/web/src/component/Common.js @@ -35,6 +35,30 @@ function numberWithCommas(x) { return x; } +// convert unix timestamp to %Y-%m-%d %H:%M:%S +export function convertIntToDateTime(timestamp) { + var date = new Date(timestamp * 1000); + var year = date.getFullYear(); + var month = date.getMonth() + 1; + var day = date.getDate(); + var hour = date.getHours(); + var minute = date.getMinutes(); + var second = date.getSeconds(); + var time = + year + + "-" + + (month < 10 ? "0" + month : month) + + "-" + + (day < 10 ? "0" + day : day) + + " " + + (hour < 10 ? "0" + hour : hour) + + ":" + + (minute < 10 ? "0" + minute : minute) + + ":" + + (second < 10 ? "0" + second : second); + return time; +} + export function SayHello() { return "Hello"; } diff --git a/web/src/component/ReviewPage.js b/web/src/component/ReviewPage.js index 93f3b89..2e3d74c 100644 --- a/web/src/component/ReviewPage.js +++ b/web/src/component/ReviewPage.js @@ -1,9 +1,36 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useParams } from "react-router"; +import { Link } from "react-router-dom"; +import { convertIntToDateTime } from "./Common"; function ReviewPage() { let params = useParams(); const [newReview, setNewReview] = useState(""); + const [reviews, setReviews] = useState([]); + + function refresh() { + fetch("/api/v1/get_reviews_on_file", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + id: parseInt(params.id), + }), + }) + .then((response) => response.json()) + .then((data) => { + if (data.error) { + alert(data.error); + } else { + setReviews(data.reviews); + } + }); + } + + useEffect(() => { + refresh(); + }, []); function submitReview() { fetch("/api/v1/insert_review", { @@ -22,6 +49,7 @@ function ReviewPage() { alert(data.error); } else { setNewReview(""); + refresh(); } }); } @@ -29,6 +57,17 @@ function ReviewPage() { return (

Review Page

+
+ {reviews.map((review) => ( +
+

+ @{review.user.username} wrote on{" "} + {convertIntToDateTime(review.created_at)}{" "} +

+

{review.content}

+
+ ))} +