brawlset/backend/routes.go
2025-06-09 22:51:16 +02:00

268 lines
7.4 KiB
Go

package main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"slices"
"strings"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)
const frontEndDevPort = "5173"
const frontEndProdPort = "3000"
type DeckImportCard struct {
Name string `json:"name"`
Amount int `json:"amount"`
}
type DeckImport struct {
Name string `json:"name"`
Url string `json:"url"`
SelectedBset string `json:"selected_bset"`
Commander string `json:"commander_name"`
Cards []DeckImportCard `json:"cards"`
}
type DeckAnswerCard struct {
Carte Carte `json:"carte"`
Amount int `json:"amount"`
}
type DeckAnswer struct {
Name string `json:"name"`
Commander Carte `json:"commander"`
Cartes []DeckAnswerCard `json:"cartes"`
}
func (app *application) SetupRoutes() {
app.pb.OnServe().BindFunc(func(se *core.ServeEvent) error {
mode := os.Getenv("GO_ENV")
path := ""
if mode == "" {
log.Fatal("You must the env variable GO_ENV to either 'dev' or 'production'")
}
if mode == "dev" {
path = fmt.Sprintf("http://localhost:%s", frontEndDevPort)
} else if mode == "production" {
path = fmt.Sprintf("http://localhost:%s", frontEndProdPort)
} else {
log.Fatal(fmt.Sprintf("Error, unrecognized GO_ENV : %s\nSet it to either 'dev' or 'production'", mode))
}
target, err := url.Parse(path)
if err != nil {
log.Println("[ERROR] failed to parse proxy target URL: %w", err)
}
proxy := httputil.NewSingleHostReverseProxy(target)
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, fmt.Sprintf("proxy error: %v", err), http.StatusBadGateway)
}
// Cache Route - GET "/json/{...}"
GET_Cache(se, app)
// Search API - GET "/api/search"
GET_Search(se, app)
// Create deck API - POST "api/deck/create"
POST_CreateDeck(se, app)
// Get deck list API - GET "/api/deck"
GET_AllDeck(se, app)
// Proxy to svelte app
se.Router.Any("/{path...}", func(re *core.RequestEvent) error {
proxy.ServeHTTP(re.Response, re.Request)
return nil
})
return se.Next()
})
}
func GET_Cache(se *core.ServeEvent, app *application) {
se.Router.GET("/json/{path...}", func(re *core.RequestEvent) error {
path := fmt.Sprintf("json/%s",re.Request.PathValue("path"))
cacheVal := app.pb.Store().Get(path)
if cacheVal != nil {
return re.JSON(http.StatusOK, cacheVal)
} else {
return re.JSON(http.StatusNotFound, map[string]string{"message": "json not found in cache"})
}
})
}
func GET_Search(se *core.ServeEvent, app *application) {
se.Router.GET("/api/search", func(re *core.RequestEvent) error {
searchData := app.pb.Store().Get("searchData").([]CacheCarteSearch)
search := re.Request.URL.Query().Get("q")
resultData := filter(searchData, func(card CacheCarteSearch) bool { return strings.Contains(strings.ToLower(card.Name), strings.ToLower(search)) })
return re.JSON(http.StatusOK, resultData)
})
}
func GET_AllDeck(se *core.ServeEvent, app *application) {
se.Router.GET("/api/deck", func(re *core.RequestEvent) error {
authRecord := re.Auth
deckList := []Deck{}
err := app.pb.DB().
NewQuery(fmt.Sprintf("SELECT name, url, commander, cartes FROM deck WHERE owner = '%v'", authRecord.Id)).
All(&deckList)
if err != nil {
return re.BadRequestError("Problem with " + err.Error(), err)
}
answer := []DeckAnswer{}
cardsIds := []string{}
for _, v := range deckList {
if !slices.Contains(cardsIds, v.Commander) {
cardsIds = append(cardsIds, fmt.Sprintf("id = '%s'",v.Commander))
}
for _, c := range v.Cards {
if !slices.Contains(cardsIds, c.ID) {
cardsIds = append(cardsIds, fmt.Sprintf("id = '%s'",c.ID))
}
}
}
cardsData := []Carte{}
err = app.pb.DB().
NewQuery(fmt.Sprintf("SELECT * FROM carte WHERE %s", strings.Join(cardsIds, " OR "))).
All(&cardsData)
if err != nil {
return re.BadRequestError("Problem with " + err.Error(), err)
}
for _, v := range deckList {
tempDeck := DeckAnswer{
Name: v.Name,
}
tempDeck.Commander = filter(cardsData, func(carte Carte) bool { return carte.ID == v.Commander })[0]
for _, c := range v.Cards {
cardData := filter(cardsData, func(carte Carte) bool { return carte.ID == c.ID})[0]
tempDeck.Cartes = append(tempDeck.Cartes, DeckAnswerCard{
Amount: c.Amount,
Carte: cardData,
})
}
answer = append(answer, tempDeck)
}
return re.JSON(http.StatusOK, answer)
}).Bind(apis.RequireAuth())
}
func POST_CreateDeck(se *core.ServeEvent, app *application) {
se.Router.POST("/api/deck/create", func(re *core.RequestEvent) error {
authRecord := re.Auth
data := DeckImport{}
if err := re.BindBody(&data); err != nil {
log.Println(err)
return re.BadRequestError("Failed to read request data", err)
}
selectedBrawlset := Brawlset{}
err := app.pb.DB().
NewQuery(fmt.Sprintf("SELECT id, sets FROM brawlset WHERE sanitized_name = '%v'", data.SelectedBset)).
One(&selectedBrawlset)
if err != nil {
log.Println(err)
return re.BadRequestError("No brawlsets with this id", err)
}
possibleCards := []Carte{}
setsIds := []string{}
for _, v := range selectedBrawlset.Sets {
setsIds = append(setsIds, fmt.Sprintf("'%s'", v))
}
query := ""
if len(selectedBrawlset.Sets) > 1 {
query = fmt.Sprintf("SELECT id, name, color_identity FROM carte WHERE mtg_set IN (%s)", strings.Join(setsIds, ", "))
} else {
query = fmt.Sprintf("SELECT id, name, color_identity FROM carte WHERE mtg_set = %s", setsIds[0])
}
err = app.pb.DB().
NewQuery(query).
All(&possibleCards)
if err != nil {
log.Println(err)
return re.BadRequestError("Error with cards query", err)
}
collection, err := app.pb.FindCollectionByNameOrId("deck")
if err != nil {
return err
}
record := core.NewRecord(collection)
record.Set("name", data.Name)
record.Set("url", data.Url)
record.Set("brawlset", selectedBrawlset.ID)
record.Set("owner", authRecord.Id)
for _, c := range possibleCards {
if data.Commander == strings.Split(c.Name, " // ")[0] {
record.Set("commander", c.ID)
record.Set("color_identity", c.ColorIdentity)
}
}
cardInDeck := []DeckCard{}
cardsNotFound := []string{}
for _, v := range data.Cards {
cardId := ""
for _, c := range possibleCards {
if v.Name == strings.Split(c.Name, " // ")[0] {
cardId = c.ID
}
}
if cardId == "" {
log.Println(fmt.Sprintf("Card not found : %s",v.Name))
cardsNotFound = append(cardsNotFound, v.Name)
} else {
cardInDeck = append(cardInDeck, DeckCard{ID: cardId, Amount: v.Amount})
}
}
if len(cardsNotFound) > 0 {
return re.BadRequestError("Cards not found : " + strings.Join(cardsNotFound, ", "), err)
}
record.Set("cartes", cardInDeck)
err = app.pb.Save(record)
if err != nil {
log.Println(err)
re.BadRequestError("Problem with creating deck", err)
}
log.Println("Deck created")
return re.JSON(http.StatusOK, map[string]string{"message": "deck created"})
}).Bind(apis.RequireAuth())
}
func filter[T any](ss []T, test func(T) bool) (ret []T) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}