finish the frontend functionality; needs styling
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user