aboutsummaryrefslogtreecommitdiff
path: root/echo/controller/generic_template.go
diff options
context:
space:
mode:
Diffstat (limited to 'echo/controller/generic_template.go')
-rw-r--r--echo/controller/generic_template.go124
1 files changed, 124 insertions, 0 deletions
diff --git a/echo/controller/generic_template.go b/echo/controller/generic_template.go
new file mode 100644
index 0000000..190182b
--- /dev/null
+++ b/echo/controller/generic_template.go
@@ -0,0 +1,124 @@
1package controller
2
3import (
4 "fmt"
5 "net/http"
6 "net/url"
7 "strconv"
8 "strings"
9 "sync"
10 "time"
11
12 glecho "code.crute.us/mcrute/golib/echo"
13
14 "github.com/labstack/echo/v4"
15)
16
17type FeatureFlags struct {
18 flags map[string]bool
19}
20
21func NewFeatureFlags() *FeatureFlags {
22 return &FeatureFlags{map[string]bool{}}
23}
24
25func (f *FeatureFlags) Need(feature string) string {
26 f.flags[feature] = true
27 return ""
28}
29
30func (f *FeatureFlags) Needs(feature string) bool {
31 v, ok := f.flags[feature]
32 return ok && v
33}
34
35type PageContext struct {
36 c map[string]string
37}
38
39func NewPageContext() *PageContext {
40 return &PageContext{map[string]string{}}
41}
42
43func (c *PageContext) HasKey(key string) bool {
44 _, ok := c.c[key]
45 return ok
46}
47
48func (c *PageContext) Set(key, value string) string {
49 c.c[key] = value
50 return ""
51}
52
53func (c *PageContext) Get(key string) string {
54 return c.c[key]
55}
56
57type GenericTemplateHandler struct {
58 Render func(echo.Context) (interface{}, error)
59 cb string
60 init sync.Once
61 cbm sync.Mutex // Should only be used in Debug
62}
63
64func (h *GenericTemplateHandler) TmplMakeCacheBustUrl(su string) (string, error) {
65 u, err := url.Parse(su)
66 if err != nil {
67 return "", err
68 }
69
70 q := u.Query()
71 q.Add("cb", h.cb)
72 u.RawQuery = q.Encode()
73
74 return u.String(), nil
75}
76
77func (h *GenericTemplateHandler) canonicalizeUrl(c echo.Context, tr glecho.TemplateChecker) string {
78 path := strings.Trim(c.Request().URL.Path, "/")
79 if path == "" {
80 path = "index.tpl"
81 } else if !strings.HasSuffix(path, ".html") {
82 p := fmt.Sprintf("%s.tpl", path)
83 if !tr.HaveTemplate(c, p) {
84 path = fmt.Sprintf("%s/index.tpl", path)
85 } else {
86 path = p
87 }
88 } else {
89 path = strings.ReplaceAll(path, ".html", ".tpl")
90 }
91 return path
92}
93
94func (h *GenericTemplateHandler) Handle(c echo.Context) error {
95 // Generate the cache-buster only once at first request
96 h.init.Do(func() {
97 h.cb = strconv.FormatInt(time.Now().Unix(), 16)
98 })
99
100 // If in debug mode use a new cache buster every time to make reloading
101 // assets easier
102 if c.Echo().Debug {
103 h.cbm.Lock()
104 h.cb = strconv.FormatInt(time.Now().Unix(), 16)
105 h.cbm.Unlock()
106 }
107
108 tr, ok := c.Echo().Renderer.(glecho.TemplateChecker)
109 if !ok {
110 // The only reason this should happen is if the app is wired wrong
111 panic("Template renderer must implement TemplateChecker")
112 }
113
114 path := h.canonicalizeUrl(c, tr)
115
116 c.Set("CanonicalPath", path)
117
118 data, err := h.Render(c)
119 if err != nil {
120 return err
121 }
122
123 return c.Render(http.StatusOK, path, data)
124}