diff options
Diffstat (limited to 'src/http.go')
-rw-r--r-- | src/http.go | 138 |
1 files changed, 102 insertions, 36 deletions
diff --git a/src/http.go b/src/http.go index 3feda8c..fce82ba 100644 --- a/src/http.go +++ b/src/http.go @@ -1,4 +1,4 @@ -package src +package app import ( "cmp" @@ -8,14 +8,16 @@ import ( "log" "math" "net/http" - "os" - "path/filepath" "slices" "strconv" "strings" + "time" + . "git.thomasvoss.com/euro-cash.eu/pkg/try" + + "git.thomasvoss.com/euro-cash.eu/src/dbx" "git.thomasvoss.com/euro-cash.eu/src/email" - "git.thomasvoss.com/euro-cash.eu/src/mintage" + "git.thomasvoss.com/euro-cash.eu/src/i18n" ) type middleware = func(http.Handler) http.Handler @@ -29,11 +31,17 @@ func Run(port int) { mwareC := chain(mwareB, countryHandler) // [C]ountry mwareM := chain(mwareC, mintageHandler) // [M]intage + mux.Handle("GET /codes/", fs) mux.Handle("GET /designs/", fs) mux.Handle("GET /favicon.ico", fs) mux.Handle("GET /fonts/", fs) mux.Handle("GET /storage/", fs) - mux.Handle("GET /style.min.css", fs) + if Debugp { + mux.Handle("GET /style.css", fs) + mux.Handle("GET /style-2.css", fs) + } else { + mux.Handle("GET /style.min.css", fs) + } mux.Handle("GET /coins/designs", mwareC(final)) mux.Handle("GET /coins/mintages", mwareM(final)) mux.Handle("GET /collecting/crh", mwareC(final)) @@ -42,7 +50,7 @@ func Run(port int) { portStr := ":" + strconv.Itoa(port) log.Println("Listening on", portStr) - log.Fatal(http.ListenAndServe(portStr, mux)) + Try(http.ListenAndServe(portStr, mux)) } func chain(xs ...middleware) middleware { @@ -56,7 +64,10 @@ func chain(xs ...middleware) middleware { func firstHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := context.WithValue(r.Context(), "td", &templateData{}) + ctx := context.WithValue(r.Context(), "td", &templateData{ + Debugp: Debugp, + Printers: i18n.Printers, + }) next.ServeHTTP(w, r.WithContext(ctx)) }) } @@ -80,33 +91,37 @@ func finalHandler(w http.ResponseWriter, r *http.Request) { original page they came from. */ if path == "/language" { http.SetCookie(w, &http.Cookie{ - Name: "redirect", - Value: cmp.Or(r.Referer(), "/"), + Name: "redirect", + Value: cmp.Or(r.Referer(), "/"), + Expires: time.Now().Add(24 * time.Hour), }) } data := r.Context().Value("td").(*templateData) - t.Execute(w, data) + if err := t.Execute(w, data); err != nil { + log.Println(err) + } } func i18nHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var p, pZero Printer + var p, pZero i18n.Printer if c, err := r.Cookie("locale"); err == nil { - p = printers[strings.ToLower(c.Value)] + p = i18n.Printers[c.Value] } td := r.Context().Value("td").(*templateData) - td.Printer = cmp.Or(p, defaultPrinter) if p == pZero { + td.Printer = bestFitLanguage(r.Header.Get("Accept-Language")) http.SetCookie(w, &http.Cookie{ Name: "redirect", Value: r.URL.Path, }) templates["/language"].Execute(w, td) } else { + td.Printer = p next.ServeHTTP(w, r) } }) @@ -123,32 +138,50 @@ func countryHandler(next http.Handler) http.Handler { func mintageHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { td := r.Context().Value("td").(*templateData) - td.Code = strings.ToLower(r.FormValue("code")) - if !slices.ContainsFunc(td.Countries, func(c country) bool { - return c.Code == td.Code - }) { - td.Code = td.Countries[0].Code - } - td.Type = strings.ToLower(r.FormValue("type")) + td.Type = r.FormValue("type") switch td.Type { case "circ", "nifc", "proof": default: td.Type = "circ" } - path := filepath.Join("data", "mintages", td.Code) - f, err := os.Open(path) - if err != nil { - throwError(http.StatusInternalServerError, err, w, r) - return + td.FilterBy = r.FormValue("filter-by") + switch td.FilterBy { + case "country", "year": + default: + td.FilterBy = "country" } - defer f.Close() - td.Mintages, err = mintage.Parse(f, path) - if err != nil { - throwError(http.StatusInternalServerError, err, w, r) - return + mt := dbx.NewMintageType(td.Type) + + switch td.FilterBy { + case "country": + td.Code = r.FormValue("country") + if !slices.ContainsFunc(td.Countries, func(c country) bool { + return c.Code == td.Code + }) { + td.Code = td.Countries[0].Code + } + + m, err := dbx.GetMintagesByCountry(td.Code, mt) + if err != nil { + throwError(http.StatusInternalServerError, err, w, r) + return + } + td.CountryMintages = makeCountryMintageTable(m, td.Printer) + case "year": + var err error + td.Year, err = strconv.Atoi(r.FormValue("year")) + if err != nil || td.Year < 1999 { + td.Year = 1999 + } + m, err := dbx.GetMintagesByYear(td.Year, mt) + if err != nil { + throwError(http.StatusInternalServerError, err, w, r) + return + } + td.YearMintages = makeYearMintageTable(m, td.Printer) } next.ServeHTTP(w, r) @@ -157,8 +190,9 @@ func mintageHandler(next http.Handler) http.Handler { func setUserLanguage(w http.ResponseWriter, r *http.Request) { loc := r.FormValue("locale") - _, ok := printers[strings.ToLower(loc)] + _, ok := i18n.Printers[loc] if !ok { + /* TODO: Make this page pretty? */ w.WriteHeader(http.StatusUnprocessableEntity) fmt.Fprintf(w, "Locale ā%sā is invalid or unsupported", loc) return @@ -182,11 +216,7 @@ func setUserLanguage(w http.ResponseWriter, r *http.Request) { func throwError(status int, err error, w http.ResponseWriter, r *http.Request) { w.WriteHeader(status) - go func() { - if err := email.ServerError(err); err != nil { - log.Print(err) - } - }() + go email.Send("Server Error", err.Error()) errorTmpl.Execute(w, struct { Code int Msg string @@ -195,3 +225,39 @@ func throwError(status int, err error, w http.ResponseWriter, r *http.Request) { Msg: http.StatusText(status), }) } + +func bestFitLanguage(qry string) i18n.Printer { + type option struct { + bcp string + quality float64 + } + var xs []option + + for subqry := range strings.SplitSeq(qry, ",") { + var o option + subqry = strings.TrimSpace(subqry) + parts := strings.Split(subqry, ";") + o.bcp = strings.ToLower(parts[0]) + if len(parts) == 1 { + o.quality = 1 + } else { + n, err := fmt.Sscanf(parts[1], "q=%f", &o.quality) + if n != 1 || err != nil { + /* Malformed query string; just give up */ + return i18n.DefaultPrinter + } + } + xs = append(xs, o) + } + + slices.SortFunc(xs, func(x, y option) int { + return cmp.Compare(y.quality, x.quality) + }) + + for _, x := range xs { + if p, ok := i18n.Printers[x.bcp]; ok { + return p + } + } + return i18n.DefaultPrinter +} |