review mentions and quality
This commit is contained in:
parent
8c1dcfa396
commit
0a8b4ca6c8
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,18 +26,17 @@ func (reviewAPI *ReviewAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
subPath, _ := ShiftPath(r.URL.Path)
|
subPath, _ := ShiftPath(r.URL.Path)
|
||||||
switch {
|
switch {
|
||||||
case r.Method == http.MethodGet && subPath == "":
|
case r.Method == http.MethodGet && subPath == "unrated":
|
||||||
reviewAPI.List(w, r)
|
reviewAPI.ListUnrated(w, r)
|
||||||
default:
|
default:
|
||||||
Error(w, http.StatusNotFound, "unregistered path", fmt.Errorf("method %q with subpath %q was not registered in /review", r.Method, subPath), logger)
|
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) {
|
func (reviewAPI *ReviewAPI) ListUnrated(w http.ResponseWriter, r *http.Request) {
|
||||||
logger := reviewAPI.logger.With("method", "list")
|
logger := reviewAPI.logger.With("method", "listUnrated")
|
||||||
|
|
||||||
movieID := r.Context().Value(MovieKey).(string)
|
reviews, err := reviewAPI.repo.FindUnrated()
|
||||||
reviews, err := reviewAPI.repo.FindByMovieID(movieID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error(w, http.StatusInternalServerError, "could not get reviews", err, logger)
|
Error(w, http.StatusInternalServerError, "could not get reviews", err, logger)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package moviestore
|
package moviestore
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ReviewSourceIMDB = "imdb"
|
ReviewSourceIMDB = "imdb"
|
||||||
)
|
)
|
||||||
|
@ -7,11 +9,13 @@ const (
|
||||||
type ReviewSource string
|
type ReviewSource string
|
||||||
|
|
||||||
type Review struct {
|
type Review struct {
|
||||||
ID string
|
ID string
|
||||||
MovieID string
|
MovieID string
|
||||||
Source ReviewSource
|
Source ReviewSource
|
||||||
URL string
|
URL string
|
||||||
Review string
|
Review string
|
||||||
|
Quality int
|
||||||
|
Mentions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReviewRepository struct {
|
type ReviewRepository struct {
|
||||||
|
@ -25,8 +29,8 @@ func NewReviewRepository(db *SQLite) *ReviewRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *ReviewRepository) Store(r Review) error {
|
func (rr *ReviewRepository) Store(r Review) error {
|
||||||
if _, err := rr.db.Exec(`REPLACE INTO review (id, movie_id, source, url, review) VALUES (?, ?, ?, ?, ?)`,
|
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); err != nil {
|
r.ID, r.MovieID, r.Source, r.URL, r.Review, r.Quality, strings.Join(r.Mentions, ",")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,31 +38,56 @@ func (rr *ReviewRepository) Store(r Review) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *ReviewRepository) FindOne(id string) (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 {
|
if row.Err() != nil {
|
||||||
return Review{}, row.Err()
|
return Review{}, row.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
review := Review{}
|
r := Review{}
|
||||||
if err := row.Scan(&review.ID, &review.MovieID, &review.Source, &review.URL, &review.Review); err != nil {
|
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
|
return Review{}, err
|
||||||
}
|
}
|
||||||
|
r.Mentions = strings.Split(mentions, ",")
|
||||||
|
|
||||||
return review, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *ReviewRepository) FindByMovieID(movieID string) ([]Review, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
reviews := make([]Review, 0)
|
reviews := make([]Review, 0)
|
||||||
|
var mentions string
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
r := Review{}
|
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
|
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)
|
reviews = append(reviews, r)
|
||||||
}
|
}
|
||||||
rows.Close()
|
rows.Close()
|
||||||
|
|
|
@ -63,6 +63,10 @@ var sqliteMigrations = []sqliteMigration{
|
||||||
`INSERT INTO job_queue (movie_id, action, status)
|
`INSERT INTO job_queue (movie_id, action, status)
|
||||||
SELECT id, 'fetch-imdb-reviews', 'todo'
|
SELECT id, 'fetch-imdb-reviews', 'todo'
|
||||||
FROM movie`,
|
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 (
|
var (
|
||||||
|
|
|
@ -40,8 +40,9 @@ func main() {
|
||||||
apis := handler.APIIndex{
|
apis := handler.APIIndex{
|
||||||
"admin": handler.NewAdminAPI(jobQueue, logger),
|
"admin": handler.NewAdminAPI(jobQueue, logger),
|
||||||
"movie": handler.NewMovieAPI(handler.APIIndex{
|
"movie": handler.NewMovieAPI(handler.APIIndex{
|
||||||
"review": handler.NewReviewAPI(moviestore.NewReviewRepository(db), logger),
|
"review": handler.NewMovieReviewAPI(moviestore.NewReviewRepository(db), logger),
|
||||||
}, moviestore.NewMovieRepository(db), jobQueue, 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))
|
go http.ListenAndServe(fmt.Sprintf(":%d", *port), handler.NewServer(*apiKey, apis, logger))
|
||||||
|
|
Loading…
Reference in New Issue