All checks were successful
Deploy to K8s / deploy (push) Successful in 8s
- GET /qr: Czech QR Platba PNG; ports Python qr_code() exactly
(account validation, amount clamping, * stripping, SPD format)
- GET /sync-bank: Fio sync → infer → cache flush with captured log
- GET+POST /flush-cache: form + action, shows deleted count
- GET /version: JSON alias of /api/version (Python parity)
- FlushCache() added to membership.Sources; wired through api.Handler
- web.ActionHandlers{BankSync} closure-based dep injection for sync
- New dep: github.com/skip2/go-qrcode
- TestQRBuildSPD (9 cases), TestServeQR, TestServeFlushCache{GET,POST},
TestServeSync, TestServeVersion added
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
80 lines
2.4 KiB
Go
80 lines
2.4 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"fuj-management/go/internal/config"
|
|
"fuj-management/go/internal/services/membership"
|
|
"fuj-management/go/internal/web/api"
|
|
"fuj-management/go/internal/web/middleware"
|
|
"io"
|
|
"io/fs"
|
|
"log/slog"
|
|
"net/http"
|
|
)
|
|
|
|
// BuildInfo carries the linker-injected build metadata.
|
|
type BuildInfo struct {
|
|
Version string
|
|
Commit string
|
|
BuildDate string
|
|
}
|
|
|
|
// ActionHandlers holds function closures for side-effectful operations that
|
|
// require dependencies (fio, sheets) not present on the core API handler.
|
|
type ActionHandlers struct {
|
|
// BankSync runs sync+infer and writes a human-readable log to out.
|
|
// nil disables the /sync-bank action (renders an error instead).
|
|
BankSync func(ctx context.Context, out io.Writer) error
|
|
}
|
|
|
|
// Run registers routes and starts the HTTP server on addr.
|
|
func Run(logger *slog.Logger, addr string, build BuildInfo, sources membership.Sources, cfg config.Config, actions ActionHandlers) error {
|
|
renderer, err := NewRenderer()
|
|
if err != nil {
|
|
return fmt.Errorf("init templates: %w", err)
|
|
}
|
|
|
|
ah := &api.Handler{
|
|
BuildVersion: build.Version,
|
|
BuildCommit: build.Commit,
|
|
BuildDate: build.BuildDate,
|
|
Sources: sources,
|
|
Config: cfg,
|
|
Logger: logger,
|
|
}
|
|
hh := NewHTMLHandler(renderer, build, ah, actions)
|
|
|
|
staticSubFS, err := fs.Sub(staticFS, "static")
|
|
if err != nil {
|
|
return fmt.Errorf("static subfs: %w", err)
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
// HTML routes
|
|
mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, "/adults", http.StatusFound)
|
|
})
|
|
mux.HandleFunc("GET /adults", hh.ServeAdults)
|
|
mux.HandleFunc("GET /juniors", hh.ServeJuniors)
|
|
mux.HandleFunc("GET /payments", hh.ServePayments)
|
|
mux.HandleFunc("GET /sync-bank", hh.ServeSync)
|
|
mux.HandleFunc("GET /flush-cache", hh.ServeFlushCacheGET)
|
|
mux.HandleFunc("POST /flush-cache", hh.ServeFlushCachePOST)
|
|
mux.HandleFunc("GET /qr", hh.ServeQR)
|
|
|
|
// Static files
|
|
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServerFS(staticSubFS)))
|
|
|
|
// JSON API routes
|
|
mux.HandleFunc("GET /api/version", ah.ServeVersion)
|
|
mux.HandleFunc("GET /version", ah.ServeVersion)
|
|
mux.HandleFunc("GET /api/adults", ah.ServeAdults)
|
|
mux.HandleFunc("GET /api/juniors", ah.ServeJuniors)
|
|
mux.HandleFunc("GET /api/payments", ah.ServePayments)
|
|
|
|
logger.Info("starting server", "addr", addr)
|
|
return http.ListenAndServe(addr, middleware.RequestTimer(logger, mux))
|
|
}
|