package site import ( "encoding/json" "fmt" "html/template" "net/http" "net/url" "path" "strings" "github.com/angelbeltran/templater" "ruben/inventory2/internal/domains/raw_events" ) func NewSiteHandler(dir string, db *raw_events.Store) http.Handler { mux := http.NewServeMux() // non-html routes scfs := http.FileServer(http.Dir(dir + "/scripts")) mux.Handle("/scripts/", http.StripPrefix("/scripts", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/javascript") if path.Ext(r.URL.Path) == ".gz" { w.Header().Set("Content-Encoding", "gzip") } scfs.ServeHTTP(w, r) }))) mux.Handle("/styles/", http.StripPrefix("/styles", http.FileServer(http.Dir(dir+"/styles")))) // html page routes tmplr := templater.NewTemplater( dir+"/templates", func() template.FuncMap { return template.FuncMap{ "buildSitePath": func(parts ...any) string { strParts := make([]string, len(parts)) for i, p := range parts { strParts[i] = fmt.Sprint(p) } // TODO: make "/site" dynamic somehow return path.Join(append([]string{"/site"}, strParts...)...) }, "prettyPrintJSON": func(j json.RawMessage) string { b, err := json.MarshalIndent(j, " ", "") if err != nil { return string(j) } return string(b) }, "addInt": func(a, b int) int { return a + b }, "subInt": func(a, b int) int { return a - b }, "multInt": func(a, b int) int { return a * b }, } }, ) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { b, err := tmplr.ExecutePage( getPageTemplateNameForURL(r.URL), "Request", r, // add services here "RawEvents", db.WithContext(r.Context()), "URLCalc", newURLCalculator(r.URL), ) if err != nil { // TODO: handle 'not found' as a 404? fmt.Println("[ERROR]: failed to load or parse layout template:", err) http.Redirect(w, r, "/", http.StatusTemporaryRedirect) return } w.Write(b) }) return mux } func getPageTemplateNameForURL(u *url.URL) string { filepath := strings.TrimPrefix(strings.TrimSuffix(u.Path, ".html"), "/") if filepath == "" { // "/" maps to "/home" filepath = "home" } return filepath } type URLCalculator struct { url *url.URL } func newURLCalculator(u *url.URL) URLCalculator { cpy := *u return URLCalculator{ url: &cpy, } } func (c URLCalculator) SetQueryParam(k string, v any) string { u := *c.url q := u.Query() q.Set(k, fmt.Sprint(v)) u.RawQuery = q.Encode() return u.String() }