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 }