summaryrefslogtreecommitdiff
path: root/src/http
diff options
context:
space:
mode:
Diffstat (limited to 'src/http')
-rw-r--r--src/http/assets.go2
-rw-r--r--src/http/drafts.go2
-rw-r--r--src/http/http.go2
-rw-r--r--src/http/index.go2
-rw-r--r--src/http/posts.go129
-rw-r--r--src/http/tpl.go84
-rw-r--r--src/http/tpl/post.html30
7 files changed, 77 insertions, 174 deletions
diff --git a/src/http/assets.go b/src/http/assets.go
index 79ab98c..5a47152 100644
--- a/src/http/assets.go
+++ b/src/http/assets.go
@@ -34,7 +34,7 @@ func (a *api) managePostAssetsHandler() http.Handler {
IDs: ids,
}
- executeTemplate(rw, r, tpl, tplPayload)
+ a.executeTemplate(rw, r, tpl, tplPayload)
})
}
diff --git a/src/http/drafts.go b/src/http/drafts.go
index f8e4c8a..b0550ce 100644
--- a/src/http/drafts.go
+++ b/src/http/drafts.go
@@ -48,7 +48,7 @@ func (a *api) manageDraftPostsHandler() http.Handler {
tplPayload.NextPage = page + 1
}
- executeTemplate(rw, r, tpl, tplPayload)
+ a.executeTemplate(rw, r, tpl, tplPayload)
})
}
diff --git a/src/http/http.go b/src/http/http.go
index fd0ea16..9bfed59 100644
--- a/src/http/http.go
+++ b/src/http/http.go
@@ -146,7 +146,7 @@ func New(params Params) (API, error) {
auther: NewAuther(params.AuthUsers, params.AuthRatelimit),
}
- a.redirectTpl = a.mustParseTpl("redirect.html")
+ a.redirectTpl = mustParseTpl(a.emptyTpl(), "redirect.html")
a.srv = &http.Server{Handler: a.handler()}
diff --git a/src/http/index.go b/src/http/index.go
index 21c6c16..48d0d33 100644
--- a/src/http/index.go
+++ b/src/http/index.go
@@ -31,6 +31,6 @@ func (a *api) renderIndexHandler() http.Handler {
return
}
- executeTemplate(rw, r, tpl, nil)
+ a.executeTemplate(rw, r, tpl, nil)
})
}
diff --git a/src/http/posts.go b/src/http/posts.go
index ab3a18a..939b811 100644
--- a/src/http/posts.go
+++ b/src/http/posts.go
@@ -12,13 +12,10 @@ import (
txttpl "text/template"
"time"
- "github.com/gomarkdown/markdown"
- "github.com/gomarkdown/markdown/html"
- "github.com/gomarkdown/markdown/parser"
- "dev.mediocregopher.com/mediocre-blog.git/src/gmi"
"dev.mediocregopher.com/mediocre-blog.git/src/http/apiutil"
"dev.mediocregopher.com/mediocre-blog.git/src/post"
"dev.mediocregopher.com/mediocre-blog.git/src/post/asset"
+ "dev.mediocregopher.com/mediocre-blog.git/src/render"
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
)
@@ -92,80 +89,6 @@ func (a *api) postPreprocessFuncs() post.PreprocessFunctions {
}
}
-func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload, error) {
-
- preprocessFuncs := a.postPreprocessFuncs()
-
- bodyBuf := new(bytes.Buffer)
-
- if err := storedPost.PreprocessBody(bodyBuf, preprocessFuncs); err != nil {
- return postTplPayload{}, fmt.Errorf("preprocessing post body: %w", err)
- }
-
- if storedPost.Format == post.FormatGemtext {
-
- prevBodyBuf := bodyBuf
- bodyBuf = new(bytes.Buffer)
-
- err := gmi.GemtextToMarkdown(
- bodyBuf, prevBodyBuf, a.params.GeminiGatewayURL,
- )
-
- if err != nil {
- return postTplPayload{}, fmt.Errorf("converting gemtext to markdown: %w", err)
- }
- }
-
- // this helps the markdown renderer properly parse pages which end in a
- // `</script>` tag... I don't know why.
- _, _ = bodyBuf.WriteString("\n")
-
- parserExt := parser.CommonExtensions | parser.AutoHeadingIDs
- parser := parser.NewWithExtensions(parserExt)
-
- htmlFlags := html.HrefTargetBlank
- htmlRenderer := html.NewRenderer(html.RendererOptions{Flags: htmlFlags})
-
- renderedBody := markdown.ToHTML(bodyBuf.Bytes(), parser, htmlRenderer)
-
- tplPayload := postTplPayload{
- StoredPost: storedPost,
- Body: template.HTML(renderedBody),
- }
-
- if series := storedPost.Series; series != "" {
-
- seriesPosts, err := a.params.PostStore.GetBySeries(series)
- if err != nil {
- return postTplPayload{}, fmt.Errorf(
- "fetching posts for series %q: %w", series, err,
- )
- }
-
- var foundThis bool
-
- for i := range seriesPosts {
-
- seriesPost := seriesPosts[i]
-
- if seriesPost.ID == storedPost.ID {
- foundThis = true
- continue
- }
-
- if !foundThis {
- tplPayload.SeriesNext = &seriesPost
- continue
- }
-
- tplPayload.SeriesPrevious = &seriesPost
- break
- }
- }
-
- return tplPayload, nil
-}
-
func (a *api) getPostsHandler() http.Handler {
tpl := a.mustParseBasedTpl("posts.html")
@@ -236,7 +159,7 @@ func (a *api) getPostsHandler() http.Handler {
tplPayload.NextPage = page + 1
}
- executeTemplate(rw, r, tpl, tplPayload)
+ a.executeTemplate(rw, r, tpl, tplPayload)
})
}
@@ -245,37 +168,7 @@ func (a *api) getPostHandler() http.Handler {
tpl := a.mustParseBasedTpl("post.html")
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-
- id := strings.TrimSuffix(filepath.Base(r.URL.Path), ".html")
-
- storedPost, err := a.params.PostStore.GetByID(id)
-
- if errors.Is(err, post.ErrPostNotFound) {
- http.Error(rw, "Post not found", 404)
- return
- } else if err != nil {
- apiutil.InternalServerError(
- rw, r, fmt.Errorf("fetching post with id %q: %w", id, err),
- )
- return
- }
-
- tplPayload, err := a.postToPostTplPayload(storedPost)
-
- if err != nil {
- apiutil.InternalServerError(
- rw, r, fmt.Errorf(
- "generating template payload for post with id %q: %w",
- id, err,
- ),
- )
- return
- }
-
- executeTemplate(
- rw, r, tpl, tplPayload,
- executeTemplateWithTitlePrefix(storedPost.Title),
- )
+ a.executeTemplate(rw, r, tpl, nil)
})
}
@@ -319,7 +212,7 @@ func (a *api) managePostsHandler() http.Handler {
tplPayload.NextPage = page + 1
}
- executeTemplate(rw, r, tpl, tplPayload)
+ a.executeTemplate(rw, r, tpl, tplPayload)
})
}
@@ -378,7 +271,7 @@ func (a *api) editPostHandler(isDraft bool) http.Handler {
Formats: post.Formats,
}
- executeTemplate(rw, r, tpl, tplPayload)
+ a.executeTemplate(rw, r, tpl, tplPayload)
})
}
@@ -516,15 +409,7 @@ func (a *api) previewPostHandler() http.Handler {
PublishedAt: time.Now(),
}
- tplPayload, err := a.postToPostTplPayload(storedPost)
-
- if err != nil {
- apiutil.InternalServerError(
- rw, r, fmt.Errorf("generating template payload: %w", err),
- )
- return
- }
-
- executeTemplate(rw, r, tpl, tplPayload)
+ r = r.WithContext(render.WithPost(r.Context(), storedPost))
+ a.executeTemplate(rw, r, tpl, nil)
})
}
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(
diff --git a/src/http/tpl/post.html b/src/http/tpl/post.html
index db69302..0cf3622 100644
--- a/src/http/tpl/post.html
+++ b/src/http/tpl/post.html
@@ -1,45 +1,51 @@
{{ define "body" }}
+{{ $post := .GetThisPost -}}
<h1 id="post-headline">
- {{ .Payload.Title }}
+ {{ $post.Title }}
</h1>
-{{ if ne .Payload.Description "" }}
+{{ if ne $post.Description "" }}
<p>
- <em>- {{ .Payload.Description }}</em>
+ <em>- {{ $post.Description }}</em>
</p>
{{ end }}
<hr/>
-{{ .Payload.Body }}
+{{ .PostHTMLBody $post }}
<p><em>
- Published {{ DateTimeFormat .Payload.PublishedAt }}
+ Published {{ DateTimeFormat $post.PublishedAt }}
</em></p>
-{{ if (or .Payload.SeriesPrevious .Payload.SeriesNext) }}
+{{- if $post.Series }}
+{{ $seriesNextPrev := .GetPostSeriesNextPrevious $post -}}
+{{ if or $seriesNextPrev.Next $seriesNextPrev.Previous }}
<hr/>
<p><em>
This post is part of a series.<br/>
- {{ if .Payload.SeriesPrevious }}
- Previously: <a href="{{ PostURL .Payload.SeriesPrevious.ID }}">{{ .Payload.SeriesPrevious.Title }}</a>
+ {{ if $seriesNextPrev.Next }}
+ Next: <a href="{{ PostURL $seriesNextPrev.Next.ID }}">{{ $seriesNextPrev.Next.Title }}</a>
{{ end }}
- {{ if (and .Payload.SeriesNext .Payload.SeriesPrevious) }}
+ {{ if and $seriesNextPrev.Next $seriesNextPrev.Previous }}
</br>
{{ end }}
- {{ if .Payload.SeriesNext }}
- Next: <a href="{{ PostURL .Payload.SeriesNext.ID }}">{{ .Payload.SeriesNext.Title }}</a></br>
+ {{ if $seriesNextPrev.Previous }}
+ Previously: <a href="{{ PostURL $seriesNextPrev.Previous.ID }}">{{ $seriesNextPrev.Previous.Title }}</a>
+ <br/>
{{ end }}
</em></p>
{{ end }}
+{{ end }}
{{ template "gemini-cta.html" . }}
{{ end }}
-{{ template "base.html" . }}
+{{ $post := .GetThisPost -}}
+{{ template "base.html" (.WithTitlePrefix $post.Title) }}