summaryrefslogtreecommitdiff
path: root/src/http/tpl.go
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2024-05-17 23:37:43 +0200
committerBrian Picciano <mediocregopher@gmail.com>2024-05-18 14:47:09 +0200
commit8d7e708d98a3a46ba3ba08f9c8deeb4838bb8ca5 (patch)
tree6662c3e4c6c3baaea058a3deaba0d9cfc8e9cc40 /src/http/tpl.go
parentfac06df97a47cda6e8989bfc5f40f2a627279b92 (diff)
Render posts completely using common rendering methods
The aim is to reduce reliance on custom logic in the handlers for every protocol, eventually outsourcing all of it into `render.Methods`, leaving each protocol to simply direct calls to the correct template.
Diffstat (limited to 'src/http/tpl.go')
-rw-r--r--src/http/tpl.go84
1 files changed, 48 insertions, 36 deletions
diff --git a/src/http/tpl.go b/src/http/tpl.go
index 24f2453..c623f2e 100644
--- a/src/http/tpl.go
+++ b/src/http/tpl.go
@@ -1,9 +1,12 @@
package http
import (
+ "bytes"
"embed"
+ "errors"
"fmt"
"html/template"
+ "io"
"io/fs"
"net/http"
"net/url"
@@ -12,6 +15,8 @@ import (
"time"
"dev.mediocregopher.com/mediocre-blog.git/src/http/apiutil"
+ "dev.mediocregopher.com/mediocre-blog.git/src/post"
+ "dev.mediocregopher.com/mediocre-blog.git/src/render"
)
//go:embed tpl
@@ -105,77 +110,84 @@ func (a *api) tplFuncs() template.FuncMap {
}
}
-func (a *api) parseTpl(name, tplBody string) (*template.Template, error) {
-
- tpl := template.New(name)
+func (a *api) emptyTpl() *template.Template {
+ tpl := template.New("")
tpl = tpl.Funcs(a.tplFuncs())
tpl = tpl.Funcs(template.FuncMap(a.postPreprocessFuncs().ToFuncMap()))
-
- var err error
-
- if tpl, err = tpl.Parse(tplBody); err != nil {
- return nil, err
- }
-
- return tpl, nil
+ return tpl
}
-func (a *api) mustParseTpl(name string) *template.Template {
- return template.Must(a.parseTpl(name, mustReadTplFile(name)))
+func mustParseTpl(tpl *template.Template, name string) *template.Template {
+ return template.Must(tpl.New(name).Parse(mustReadTplFile(name)))
}
func (a *api) mustParseBasedTpl(name string) *template.Template {
- tpl := a.mustParseTpl(name)
- tpl = template.Must(tpl.New("gemini-cta.html").Parse(mustReadTplFile("gemini-cta.html")))
- tpl = template.Must(tpl.New("base.html").Parse(mustReadTplFile("base.html")))
+ tpl := a.emptyTpl()
+ tpl = mustParseTpl(tpl, "gemini-cta.html")
+ tpl = mustParseTpl(tpl, "base.html")
+ tpl = mustParseTpl(tpl, name)
return tpl
}
type tplData struct {
+ *render.Methods
Payload interface{}
Title string
}
-func newTPLData(r *http.Request, payload interface{}) tplData {
+// WithTitlePrefix returns a copy of tplData but with the given string prefixed
+// to the page title. This is intended for use within templates, when nesting
+// the base template.
+func (d tplData) WithTitlePrefix(prefix string) tplData {
+ d.Title = prefix + " - " + d.Title
+ return d
+}
+
+func (a *api) newTPLData(r *http.Request, payload interface{}) tplData {
return tplData{
+ Methods: render.NewMethods(
+ r.Context(),
+ r.URL,
+ a.params.PublicURL,
+ a.params.GeminiGatewayURL,
+ a.params.PostStore,
+ a.postPreprocessFuncs(),
+ ),
Payload: payload,
Title: "mediocregopher's lil web corner",
}
}
-type executeTemplateOpt func(*tplData)
-
-func executeTemplateWithTitlePrefix(prefix string) executeTemplateOpt {
- return func(d *tplData) {
- d.Title = prefix + " - " + d.Title
- }
-}
-
// executeTemplate expects to be the final action in an http.Handler
-func executeTemplate(
- rw http.ResponseWriter, r *http.Request,
- tpl *template.Template, payload interface{},
- opts ...executeTemplateOpt,
+func (a *api) executeTemplate(
+ rw http.ResponseWriter,
+ r *http.Request,
+ tpl *template.Template,
+ payload interface{},
) {
- tplData := newTPLData(r, payload)
+ tplData := a.newTPLData(r, payload)
- for _, opt := range opts {
- opt(&tplData)
- }
+ buf := new(bytes.Buffer)
- if err := tpl.Execute(rw, tplData); err != nil {
+ err := tpl.Execute(buf, tplData)
+ if errors.Is(err, post.ErrPostNotFound) {
+ http.Error(rw, "Post not found", 404)
+ return
+ } else if err != nil {
apiutil.InternalServerError(
rw, r, fmt.Errorf("rendering template: %w", err),
)
return
}
+
+ io.Copy(rw, buf)
}
func (a *api) executeRedirectTpl(
rw http.ResponseWriter, r *http.Request, url string,
) {
- executeTemplate(rw, r, a.redirectTpl, struct {
+ a.executeTemplate(rw, r, a.redirectTpl, struct {
URL string
}{
URL: url,
@@ -188,7 +200,7 @@ func (a *api) renderDumbTplHandler(tplName string) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- tplData := newTPLData(r, nil)
+ tplData := a.newTPLData(r, nil)
if err := tpl.Execute(rw, tplData); err != nil {
apiutil.InternalServerError(