package templates import ( "bytes" "errors" "io" "io/fs" "net/http" "path/filepath" "github.com/flosch/pongo2/v4" "github.com/gin-gonic/gin/render" "github.com/phuslu/log" ) var ( _ pongo2.TemplateLoader = &FSLoader{} _ render.Render = &renderer{} _ pongo2.TemplateLoader = &EmptyLoader{} ) //TemplateSite is an interface that is for storing templates. type TemplateSite interface { Templates() pongo2.TemplateLoader } // FSLoader is an interim until pongo merges the pullrequest for fs.FS type FSLoader struct { fs.FS } // Abs return the join of base and name func (e *FSLoader) Abs(base, name string) string { return filepath.Join(filepath.Dir(base), name) } // Get returns an io.Reader where the template's content can be read from. func (e *FSLoader) Get(path string) (reader io.Reader, err error) { f, err := e.FS.Open(path) if err != nil { return nil, err } defer f.Close() bt, err := io.ReadAll(f) if err != nil { return nil, err } return bytes.NewBuffer(bt), nil } // Pongo2Renderer is an simple wrapper for gin to use pongo2 templates type Pongo2Renderer struct { ts *pongo2.TemplateSet } // NewPongo2Renderer creates an wrapper for gin func NewPongo2Renderer(ts *pongo2.TemplateSet) render.HTMLRender { return &Pongo2Renderer{ts: ts} } // Instance create an new instance of an REnder object func (p2r *Pongo2Renderer) Instance(name string, data interface{}) render.Render { tmpl, err := p2r.ts.FromFile(name) r := &renderer{ tmpl: tmpl, err: err, } if data != nil { switch data.(type) { case pongo2.Context: r.data = data.(pongo2.Context) case map[string]interface{}: r.data = data.(map[string]interface{}) default: r.err = errors.New("Failed to detect possible format for pongo2. It needs to be map[string]interface{} or pongo2.Context") } } log.Debug().Msg("Returning an instance") return r } type renderer struct { tmpl *pongo2.Template err error data pongo2.Context } // Render renders the template func (r *renderer) Render(rw http.ResponseWriter) error { if r.err != nil { log.Debug().Msg("rendering failed") return r.err } log.Debug().Msg("wirting template") return r.tmpl.ExecuteWriter(r.data, rw) } // WriteContentType is an static function that always writes text/html as the Contenttype into the response func (*renderer) WriteContentType(rw http.ResponseWriter) { rw.Header().Set("Content-Type", "text/html") } // EmptyLoader is an Empty Loader type EmptyLoader struct{} // Abs return the join of base and name func (*EmptyLoader) Abs(base, name string) string { return filepath.Join(filepath.Dir(base), name) } // Get returns always errors func (*EmptyLoader) Get(string) (io.Reader, error) { return nil, errors.New("This Loader has no templates") }