finish the frontend functionality; needs styling
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2024-01-03 22:11:01 -05:00
parent b6119f320f
commit 7459117b12
5 changed files with 139 additions and 90 deletions

View File

@@ -2,8 +2,10 @@ package main
import (
"encoding/json"
"fmt"
"io"
"io/fs"
"log"
"net/http"
"git.yetaga.in/alazyreader/library/media"
@@ -30,6 +32,7 @@ func (h path) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func writeJSONerror(w http.ResponseWriter, err string, status int) {
log.Println(err)
writeJSON(w, struct{ Status, Reason string }{Status: "error", Reason: err}, status)
}
@@ -97,50 +100,26 @@ func getBooks(l Library, w http.ResponseWriter, r *http.Request) {
}
func addBook(l Library, w http.ResponseWriter, r *http.Request) {
if r.Body == nil {
writeJSONerror(w, "no body provided", http.StatusBadRequest)
book, err := ReadBody[media.Book](r.Body)
if err != nil {
writeJSONerror(w, err.Error(), http.StatusBadRequest)
return
}
defer r.Body.Close()
b, err := io.ReadAll(r.Body)
if err != nil {
writeJSONerror(w, "error reading body", http.StatusBadRequest)
return
}
book := &media.Book{}
err = json.Unmarshal(b, book)
if err != nil {
writeJSONerror(w, "error parsing body", http.StatusBadRequest)
return
}
err = l.AddBook(r.Context(), book)
if err != nil {
writeJSONerror(w, "error parsing body", http.StatusBadRequest)
if err = l.AddBook(r.Context(), book); err != nil {
writeJSONerror(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusAccepted)
}
func deleteBook(l Library, w http.ResponseWriter, r *http.Request) {
if r.Body == nil {
writeJSONerror(w, "no body provided", http.StatusBadRequest)
book, err := ReadBody[media.Book](r.Body)
if err != nil {
writeJSONerror(w, err.Error(), http.StatusBadRequest)
return
}
defer r.Body.Close()
b, err := io.ReadAll(r.Body)
if err != nil {
writeJSONerror(w, "error reading body", http.StatusBadRequest)
return
}
book := &media.Book{}
err = json.Unmarshal(b, book)
if err != nil {
writeJSONerror(w, "error parsing body", http.StatusBadRequest)
return
}
err = l.DeleteBook(r.Context(), book)
if err != nil {
writeJSONerror(w, "error deleting book", http.StatusInternalServerError)
if err = l.DeleteBook(r.Context(), book); err != nil {
writeJSONerror(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusAccepted)
@@ -165,12 +144,12 @@ func getWhoAmI(ts *tailscale.LocalClient, w http.ResponseWriter, r *http.Request
}
func lookupBook(query Query, w http.ResponseWriter, r *http.Request) {
isbn := r.FormValue("isbn")
if len(isbn) != 10 && len(isbn) != 13 {
writeJSONerror(w, "invalid isbn", http.StatusBadRequest)
req, err := ReadBody[media.Book](r.Body)
if err != nil {
writeJSONerror(w, err.Error(), http.StatusBadRequest)
return
}
book, err := query.GetByISBN(isbn)
book, err := query.GetByISBN(req.ISBN13)
if err != nil {
writeJSONerror(w, err.Error(), http.StatusInternalServerError)
return
@@ -181,3 +160,20 @@ func lookupBook(query Query, w http.ResponseWriter, r *http.Request) {
func static(f fs.FS) http.Handler {
return http.FileServer(http.FS(f))
}
func ReadBody[T any](r io.ReadCloser) (*T, error) {
t := new(T)
if r == nil {
return t, fmt.Errorf("no body provided")
}
defer r.Close()
b, err := io.ReadAll(r)
if err != nil {
return t, fmt.Errorf("error reading body: %w", err)
}
err = json.Unmarshal(b, t)
if err != nil {
return t, fmt.Errorf("error reading body: %w", err)
}
return t, nil
}

View File

@@ -45,50 +45,44 @@ func main() {
must.Do(envconfig.Process("library", &c))
var lib Library
var err error
if c.DBType == "memory" {
lib = &database.Memory{}
} else if c.DBType == "sql" {
var latest, run int
lib, latest, run, err = setupSQL(c)
sqllib, latest, run, err := setupSQL(c)
if err != nil {
log.Fatalf("err starting sql connection: %v", err)
log.Fatalf("sql connection err: %v", err)
}
log.Printf("latest migration: %d; migrations run: %d", latest, run)
lib = sqllib
}
discogsCache := must.Get(database.NewDiscogsCache(
c.DiscogsToken, time.Hour*24, c.DiscogsUser, c.DiscogsPersist, c.DiscogsCacheFile,
))
queryProvider := &query.GoogleBooks{}
staticRoot := must.Get(frontend.Root())
servers := make(chan (*http.Server), 3)
errGroup := errgroup.Group{}
errGroup.Go(func() error {
return start(servers)(
publicServer(8080, &Router{
static: staticRoot,
lib: lib,
rcol: discogsCache,
isAdmin: false,
}))
return start(servers)(publicServer(8080, &Router{
static: staticRoot,
lib: lib,
rcol: discogsCache,
isAdmin: false,
}))
})
errGroup.Go(func() error {
return start(servers)(
tailscaleListener("library-admin", &Router{
static: staticRoot,
lib: lib,
rcol: discogsCache,
query: queryProvider,
isAdmin: true,
}))
return start(servers)(tailscaleListener("library-admin", &Router{
static: staticRoot,
lib: lib,
rcol: discogsCache,
query: queryProvider,
isAdmin: true,
}))
})
errGroup.Go(func() error {
return shutdown(servers)
})
log.Println(errGroup.Wait())
}
@@ -172,6 +166,5 @@ func tailscaleListener(hostname string, handler *Router) (*http.Server, net.List
return nil, nil, err
}
log.Printf("management server: http://%s/", hostname)
server := &http.Server{Handler: handler}
return server, ln, nil
return &http.Server{Handler: handler}, ln, nil
}