1package main
2
3import (
4 "bytes"
5 "embed"
6 "errors"
7 "fmt"
8 "io"
9 "path/filepath"
10
11 "github.com/flosch/pongo2/v6"
12 "github.com/labstack/echo/v4"
13)
14
15//go:embed templates/*
16var TemplateFS embed.FS
17
18type RendererLoader struct {
19 prefix string
20 fs *embed.FS
21}
22
23func NewRendererLoader(prefix string, fs *embed.FS) pongo2.TemplateLoader {
24 return &RendererLoader{
25 prefix: prefix,
26 fs: fs,
27 }
28}
29func (l *RendererLoader) Abs(_, name string) string {
30 // TODO: remove this workaround
31 // Figure out why this method is being called
32 // twice on template names resulting in a failure to resolve
33 // the template name.
34 if filepath.HasPrefix(name, l.prefix) {
35 return name
36 }
37 return filepath.Join(l.prefix, name)
38}
39
40func (l *RendererLoader) Get(path string) (io.Reader, error) {
41 b, err := l.fs.ReadFile(path)
42 if err != nil {
43 return nil, fmt.Errorf("reading template %q failed: %w", path, err)
44 }
45 return bytes.NewReader(b), nil
46}
47
48type Renderer struct {
49 TemplateSet *pongo2.TemplateSet
50 Debug bool
51}
52
53func NewRenderer(prefix string, fs *embed.FS, debug bool) *Renderer {
54 return &Renderer{
55 TemplateSet: pongo2.NewSet(prefix, NewRendererLoader(prefix, fs)),
56 Debug: debug,
57 }
58}
59
60func (r Renderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
61 var ctx pongo2.Context
62
63 if data != nil {
64 var ok bool
65 ctx, ok = data.(pongo2.Context)
66 if !ok {
67 return errors.New("no pongo2.Context data was passed")
68 }
69 }
70
71 var t *pongo2.Template
72 var err error
73
74 if r.Debug {
75 t, err = pongo2.FromFile(name)
76 } else {
77 t, err = r.TemplateSet.FromFile(name)
78 }
79
80 if err != nil {
81 return err
82 }
83
84 return t.ExecuteWriter(ctx, w)
85}