review mentions and quality

This commit is contained in:
Erik Winter 2024-01-06 14:22:22 +01:00
parent 8c1dcfa396
commit 0a8b4ca6c8
5 changed files with 103 additions and 20 deletions

View File

@ -0,0 +1,50 @@
package handler
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"ewintr.nl/emdb/cmd/api-service/moviestore"
)
type MovieReviewAPI struct {
repo *moviestore.ReviewRepository
logger *slog.Logger
}
func NewMovieReviewAPI(repo *moviestore.ReviewRepository, logger *slog.Logger) *MovieReviewAPI {
return &MovieReviewAPI{
repo: repo,
logger: logger.With("api", "moviereview"),
}
}
func (reviewAPI *MovieReviewAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger := reviewAPI.logger.With("method", "serveHTTP")
subPath, _ := ShiftPath(r.URL.Path)
switch {
case r.Method == http.MethodGet && subPath == "":
reviewAPI.List(w, r)
default:
Error(w, http.StatusNotFound, "unregistered path", fmt.Errorf("method %q with subpath %q was not registered in /review", r.Method, subPath), logger)
}
}
func (reviewAPI *MovieReviewAPI) List(w http.ResponseWriter, r *http.Request) {
logger := reviewAPI.logger.With("method", "list")
movieID := r.Context().Value(MovieKey).(string)
reviews, err := reviewAPI.repo.FindByMovieID(movieID)
if err != nil {
Error(w, http.StatusInternalServerError, "could not get reviews", err, logger)
return
}
if err := json.NewEncoder(w).Encode(reviews); err != nil {
Error(w, http.StatusInternalServerError, "could not encode reviews", err, logger)
return
}
}

View File

@ -26,18 +26,17 @@ func (reviewAPI *ReviewAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
subPath, _ := ShiftPath(r.URL.Path)
switch {
case r.Method == http.MethodGet && subPath == "":
reviewAPI.List(w, r)
case r.Method == http.MethodGet && subPath == "unrated":
reviewAPI.ListUnrated(w, r)
default:
Error(w, http.StatusNotFound, "unregistered path", fmt.Errorf("method %q with subpath %q was not registered in /review", r.Method, subPath), logger)
}
}
func (reviewAPI *ReviewAPI) List(w http.ResponseWriter, r *http.Request) {
logger := reviewAPI.logger.With("method", "list")
func (reviewAPI *ReviewAPI) ListUnrated(w http.ResponseWriter, r *http.Request) {
logger := reviewAPI.logger.With("method", "listUnrated")
movieID := r.Context().Value(MovieKey).(string)
reviews, err := reviewAPI.repo.FindByMovieID(movieID)
reviews, err := reviewAPI.repo.FindUnrated()
if err != nil {
Error(w, http.StatusInternalServerError, "could not get reviews", err, logger)
return

View File

@ -1,5 +1,7 @@
package moviestore
import "strings"
const (
ReviewSourceIMDB = "imdb"
)
@ -12,6 +14,8 @@ type Review struct {
Source ReviewSource
URL string
Review string
Quality int
Mentions []string
}
type ReviewRepository struct {
@ -25,8 +29,8 @@ func NewReviewRepository(db *SQLite) *ReviewRepository {
}
func (rr *ReviewRepository) Store(r Review) error {
if _, err := rr.db.Exec(`REPLACE INTO review (id, movie_id, source, url, review) VALUES (?, ?, ?, ?, ?)`,
r.ID, r.MovieID, r.Source, r.URL, r.Review); err != nil {
if _, err := rr.db.Exec(`REPLACE INTO review (id, movie_id, source, url, review, quality, mentions) VALUES (?, ?, ?, ?, ?, ?, ?)`,
r.ID, r.MovieID, r.Source, r.URL, r.Review, r.Quality, strings.Join(r.Mentions, ",")); err != nil {
return err
}
@ -34,31 +38,56 @@ func (rr *ReviewRepository) Store(r Review) error {
}
func (rr *ReviewRepository) FindOne(id string) (Review, error) {
row := rr.db.QueryRow(`SELECT id, movie_id, source, url, review FROM review WHERE id=?`, id)
row := rr.db.QueryRow(`SELECT id, movie_id, source, url, review, quality, mentions FROM review WHERE id=?`, id)
if row.Err() != nil {
return Review{}, row.Err()
}
review := Review{}
if err := row.Scan(&review.ID, &review.MovieID, &review.Source, &review.URL, &review.Review); err != nil {
r := Review{}
var mentions string
if err := row.Scan(&r.ID, &r.MovieID, &r.Source, &r.URL, &r.Review, &r.Quality, &mentions); err != nil {
return Review{}, err
}
r.Mentions = strings.Split(mentions, ",")
return review, nil
return r, nil
}
func (rr *ReviewRepository) FindByMovieID(movieID string) ([]Review, error) {
rows, err := rr.db.Query(`SELECT id, movie_id, source, url, review FROM review WHERE movie_id=?`, movieID)
rows, err := rr.db.Query(`SELECT id, movie_id, source, url, review, quality, mentions FROM review WHERE movie_id=?`, movieID)
if err != nil {
return nil, err
}
reviews := make([]Review, 0)
var mentions string
for rows.Next() {
r := Review{}
if err := rows.Scan(&r.ID, &r.MovieID, &r.Source, &r.URL, &r.Review); err != nil {
if err := rows.Scan(&r.ID, &r.MovieID, &r.Source, &r.URL, &r.Review, &r.Quality, &mentions); err != nil {
return nil, err
}
r.Mentions = strings.Split(mentions, ",")
reviews = append(reviews, r)
}
rows.Close()
return reviews, nil
}
func (rr *ReviewRepository) FindUnrated() ([]Review, error) {
rows, err := rr.db.Query(`SELECT id, movie_id, source, url, review, quality, mentions FROM review WHERE quality=0`)
if err != nil {
return nil, err
}
reviews := make([]Review, 0)
var mentions string
for rows.Next() {
r := Review{}
if err := rows.Scan(&r.ID, &r.MovieID, &r.Source, &r.URL, &r.Review, &r.Quality, &mentions); err != nil {
return nil, err
}
r.Mentions = strings.Split(mentions, ",")
reviews = append(reviews, r)
}
rows.Close()

View File

@ -63,6 +63,10 @@ var sqliteMigrations = []sqliteMigration{
`INSERT INTO job_queue (movie_id, action, status)
SELECT id, 'fetch-imdb-reviews', 'todo'
FROM movie`,
`AlTER TABLE review ADD COLUMN "references" TEXT NOT NULL DEFAULT ""`,
`ALTER TABLE review ADD COLUMN "quality" INTEGER NOT NULL DEFAULT 0`,
`ALTER TABLE review DROP COLUMN "references"`,
`ALTER TABLE review ADD COLUMN "mentions" TEXT NOT NULL DEFAULT ""`,
}
var (

View File

@ -40,8 +40,9 @@ func main() {
apis := handler.APIIndex{
"admin": handler.NewAdminAPI(jobQueue, logger),
"movie": handler.NewMovieAPI(handler.APIIndex{
"review": handler.NewReviewAPI(moviestore.NewReviewRepository(db), logger),
"review": handler.NewMovieReviewAPI(moviestore.NewReviewRepository(db), logger),
}, moviestore.NewMovieRepository(db), jobQueue, logger),
"review": handler.NewReviewAPI(moviestore.NewReviewRepository(db), logger),
}
go http.ListenAndServe(fmt.Sprintf(":%d", *port), handler.NewServer(*apiKey, apis, logger))