Files
inventory-plus-plus/internal/site/templates.go
T

147 lines
3.4 KiB
Go

package site
import (
"fmt"
"net/http"
"net/url"
"path"
"path/filepath"
"strings"
"ruben/inventory2/internal/domains/accounts"
)
// GET /
func (s *Server) serveTemplates(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
name, pathParams := getPageTemplateNameForURL(r.URL)
var (
acct accounts.Account
userID string
)
claims, ok := s.getAccessTokenClaims(r)
if ok {
userID = claims.Subject
acct, _ = s.accts.GetAccountByUserID(ctx, userID)
}
b, err := s.templater.ExecutePage(
name,
"Request",
r,
// add services here
"RawEvents",
s.rawEvents.WithContext(ctx),
"URLCalc",
newURLCalculator(r.URL),
"PathParams",
pathParams,
"Accounts",
s.accts.WithContext(ctx),
"Etsy",
s.etsy.WithContext(ctx),
// claims
"Claims",
claims,
"UserID",
userID,
"Account",
acct,
)
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)
}
// TODO: clean this up...
// TODO: somehow tell what the path params are and pass them up.
// - then consider pushing this functionality into the template library.
//
// getPageTemplateNameForURL eliminate any trailing .html or /, and checks for any
// file with path parameters in the name, eg '{abc}.html.tmpl', prefering exact filename matches.
func getPageTemplateNameForURL(u *url.URL) (name string, params map[string]string) {
fp := strings.TrimPrefix(strings.TrimSuffix(strings.TrimSuffix(u.Path, ".html"), "/"), "/")
if fp == "" {
// "/" maps to "/index"
fp = "index"
}
fpParts := strings.Split(fp, "/")
res := getMatchingGlobPatternsCapturingFilepathIncludingParametrizedFilepaths(fpParts)
for _, combs := range res {
const pageBodiesPrefix = "internal/site/templates/page_bodies"
pattern := path.Join(pageBodiesPrefix, path.Join(combs...)) + ".html.tmpl"
matches, _ := filepath.Glob(pattern)
if len(matches) == 0 {
pattern := path.Join(pageBodiesPrefix, path.Join(combs...), "index") + ".html.tmpl"
matches, _ = filepath.Glob(pattern)
}
if len(matches) > 0 {
match := matches[0]
name = strings.TrimPrefix(strings.TrimSuffix(match, ".html.tmpl"), pageBodiesPrefix+"/")
patternParts := strings.Split(name, "/")
params = make(map[string]string)
for i, pp := range patternParts {
if strings.HasPrefix(pp, "{") && strings.HasSuffix(pp, "}") {
params[pp[1:len(pp)-1]] = fpParts[i]
}
}
return name, params
}
}
return fp, nil
}
func getMatchingGlobPatternsCapturingFilepathIncludingParametrizedFilepaths(filepathParts []string) [][]string {
switch len(filepathParts) {
case 0:
return nil
case 1:
return [][]string{
[]string{filepathParts[0]},
[]string{"{*}"},
}
default:
tailCombs := getMatchingGlobPatternsCapturingFilepathIncludingParametrizedFilepaths(filepathParts[1:])
combs := make([][]string, 2*len(tailCombs))
for i, c := range tailCombs {
combs[i*2] = append([]string{filepathParts[0]}, c...)
combs[i*2+1] = append([]string{"{*}"}, c...)
}
return combs
}
}
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()
}