From 0665d0c65974533fbd313f4e0b062b5103057aeb Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Sat, 18 May 2024 18:29:19 +0200 Subject: Replace all URL rendering within templates by a URLConstructor --- src/gmi/gmi.go | 4 +- src/gmi/tpl.go | 2 + src/gmi/tpl/feed.xml | 8 +- src/gmi/tpl/footer.gmi | 4 +- src/gmi/tpl/index.gmi | 8 +- src/gmi/tpl/posts/index.gmi | 11 ++- src/gmi/tpl/posts/post.gmi | 10 +-- src/http/http.go | 5 +- src/http/posts.go | 6 ++ src/http/tpl.go | 2 + src/http/tpl/admin.html | 6 +- src/http/tpl/base.html | 22 ++--- src/http/tpl/draft-posts-manage.html | 14 +-- src/http/tpl/follow.html | 2 +- src/http/tpl/gemini-cta.html | 6 +- src/http/tpl/image.html | 4 +- src/http/tpl/index.html | 6 +- src/http/tpl/post-assets-manage.html | 8 +- src/http/tpl/post-edit.html | 16 ++-- src/http/tpl/post.html | 4 +- src/http/tpl/posts-manage.html | 14 +-- src/http/tpl/posts.html | 8 +- src/render/methods.go | 14 ++- src/render/url.go | 168 +++++++++++++++++++++++++++++++++++ 24 files changed, 269 insertions(+), 83 deletions(-) create mode 100644 src/render/url.go diff --git a/src/gmi/gmi.go b/src/gmi/gmi.go index e37ca74..89c35bc 100644 --- a/src/gmi/gmi.go +++ b/src/gmi/gmi.go @@ -58,7 +58,9 @@ func (p *Params) SetupCfg(cfg *cfg.Cfg) { var err error - *publicURLStr = strings.TrimSuffix(*publicURLStr, "/") + if !strings.HasSuffix(*publicURLStr, "/") { + *publicURLStr += "/" + } if p.PublicURL, err = url.Parse(*publicURLStr); err != nil { return fmt.Errorf("parsing -gemini-public-url: %w", err) diff --git a/src/gmi/tpl.go b/src/gmi/tpl.go index f6c1754..cdf9535 100644 --- a/src/gmi/tpl.go +++ b/src/gmi/tpl.go @@ -175,6 +175,8 @@ func (a *api) tplHandler() (gemini.Handler, error) { ctx, r.URL, a.params.PublicURL, + a.params.HTTPPublicURL, + a.params.PublicURL, // geminiURL a.params.HTTPGeminiGatewayURL, a.params.PostStore, nil, // asset.Store, not supported by gemini endpoint diff --git a/src/gmi/tpl/feed.xml b/src/gmi/tpl/feed.xml index aa596b7..2935327 100644 --- a/src/gmi/tpl/feed.xml +++ b/src/gmi/tpl/feed.xml @@ -3,11 +3,11 @@ mediocregopher's lil web corner - {{ BlogGeminiURL "/" }} + {{ .RootURL.Absolute }} {{ if gt (len $posts) 0 -}} {{ (index $posts 0).PublishedAt.Format "2006-01-02T15:04:05Z07:00" }} {{ end -}} - + mediocregopher @@ -15,8 +15,8 @@ {{ .Title }} {{ .PublishedAt.Format "2006-01-02T15:04:05Z07:00" }} - {{ PostURLAbs .ID }} - + {{ $.RootURL.Absolute.Post .ID }} + {{ if .Description -}} {{ .Description }} {{ end -}} diff --git a/src/gmi/tpl/footer.gmi b/src/gmi/tpl/footer.gmi index 15ee7b6..04a6562 100644 --- a/src/gmi/tpl/footer.gmi +++ b/src/gmi/tpl/footer.gmi @@ -1,10 +1,10 @@ ======================================== {{ if ne .GetPath "index.gmi" -}} -=> {{ BlogURL "/" }} Home +=> {{ .RootURL }} Home {{ end -}} => https://dev.mediocregopher.com/mediocre-blog.git Source -=> {{ BlogURL "wtfpl.txt" }} License for all content, if you must have one +=> {{ .RootURL.Path "wtfpl.txt" }} License for all content, if you must have one diff --git a/src/gmi/tpl/index.gmi b/src/gmi/tpl/index.gmi index b854481..6a70607 100644 --- a/src/gmi/tpl/index.gmi +++ b/src/gmi/tpl/index.gmi @@ -2,16 +2,16 @@ This here's my little corner of the web, where I publish posts about projects I'm working on and things that interest me (which you can follow, if you like). -=> {{ BlogURL "posts/" }} Browse all posts +=> {{ .RootURL.Posts }} Browse all posts {{ $getPostsRes := .GetPosts 0 1 -}} {{ if gt (len $getPostsRes.Posts) 0 -}} {{ $post := index $getPostsRes.Posts 0 -}} -=> {{ PostURL $post.ID }} (Latest post: {{ $post.Title }}) +=> {{ .RootURL.Post $post.ID }} (Latest post: {{ $post.Title }}) {{ end -}} -=> {{ BlogURL "feed.xml" }} RSS feed +=> {{ .RootURL.Path "feed.xml" }} RSS feed Below you'll find other information and links related to me. @@ -21,7 +21,7 @@ Feel free to hmu over email or Signal if you'd like to get in touch. => mailto:me@mediocregopher Email: me@mediocregopher.com -=> {{ BlogURL "me@mediocregopher.com.gpg" }} GPG Key +=> {{ .RootURL.Path "me@mediocregopher.com.gpg" }} GPG Key => https://signal.me/#eu/x5psueq2E3WfFwwEgFDoWeSZx9k4u8vFBaiMSa4Lo0cvluHkb-dIpJp1wfdJsdie Signal: mediocregopher.01 diff --git a/src/gmi/tpl/posts/index.gmi b/src/gmi/tpl/posts/index.gmi index 2ff296a..873222b 100644 --- a/src/gmi/tpl/posts/index.gmi +++ b/src/gmi/tpl/posts/index.gmi @@ -1,29 +1,28 @@ # 👻 mediocregopher's Posts {{ $page := .GetQueryIntValue "page" 0 -}} +{{ $getPostsRes := .GetPosts $page 20 -}} {{ if eq $page 0 -}} Here you'll find an archive of all published posts. The content varies almost as much as the quality! {{ end -}} -{{ $getPostsRes := .GetPosts $page 20 -}} - {{ if gt $page 0 -}} -=> {{ BlogURL "posts" }}/?page={{ .Add $page -1 }} Previous Page +=> {{ .RootURL.Posts.Page (.Add $page -1) }} Previous Page {{ end -}} {{ range $getPostsRes.Posts -}} -=> {{ PostURL .ID }} {{ .PublishedAt.Format "2006-01-02" }} - {{ .Title }} +=> {{ $.RootURL.Post .ID }} {{ .PublishedAt.Format "2006-01-02" }} - {{ .Title }} {{ end -}} {{ if $getPostsRes.HasMore -}} -=> {{ BlogURL "posts" }}/?page={{ .Add $page 1 }} Next page +=> {{ .RootURL.Posts.Page (.Add $page 1) }} Next page {{ end }} ======================================== -=> {{ BlogURL "feed.xml" }} RSS feed +=> {{ .RootURL.Path "feed.xml" }} RSS feed {{ template "footer.gmi" . }} diff --git a/src/gmi/tpl/posts/post.gmi b/src/gmi/tpl/posts/post.gmi index b568044..eafa76c 100644 --- a/src/gmi/tpl/posts/post.gmi +++ b/src/gmi/tpl/posts/post.gmi @@ -3,7 +3,7 @@ {{ if eq $post.Format "md" -}} This post has been translated from it's original markdown format, if it seems busted it might appear better over HTTP: -=> {{ PostHTTPURL $post.ID }} +=> {{ .RootURL.HTTP.Post $post.ID }} {{ end -}} @@ -26,18 +26,18 @@ Published {{ $post.PublishedAt.Format "2006-01-02" }} by mediocregopher This post is part of a series! {{ if $seriesNextPrev.Next -}} -=> {{ BlogURL "posts" }}/{{ $seriesNextPrev.Next.ID }}.gmi Next in the series: {{ $seriesNextPrev.Next.Title }} +=> {{ .RootURL.Post $seriesNextPrev.Next.ID }} Next in the series: {{ $seriesNextPrev.Next.Title }} {{ end -}} {{ if $seriesNextPrev.Previous -}} -=> {{ BlogURL "posts" }}/{{ $seriesNextPrev.Previous.ID }}.gmi Prevous in the series: {{ $seriesNextPrev.Previous.Title }} +=> {{ .RootURL.Post $seriesNextPrev.Previous.ID }} Prevous in the series: {{ $seriesNextPrev.Previous.Title }} {{ end -}} {{ end -}} {{ else }}{{/* newline */}} {{ end }} -=> {{ BlogURL "posts/" }} Browse all posts +=> {{ .RootURL.Posts }} Browse all posts -=> {{ BlogURL "feed.xml" }} RSS feed +=> {{ .RootURL.Path "feed.xml" }} RSS feed {{ template "footer.gmi" . }} diff --git a/src/http/http.go b/src/http/http.go index 9bfed59..93cc043 100644 --- a/src/http/http.go +++ b/src/http/http.go @@ -89,7 +89,10 @@ func (p *Params) SetupCfg(cfg *cfg.Cfg) { return fmt.Errorf("unmarshaling -http-auth-ratelimit: %w", err) } - *publicURLStr = strings.TrimSuffix(*publicURLStr, "/") + if !strings.HasSuffix(*publicURLStr, "/") { + *publicURLStr += "/" + } + if p.PublicURL, err = url.Parse(*publicURLStr); err != nil { return fmt.Errorf("parsing -http-public-url: %w", err) } diff --git a/src/http/posts.go b/src/http/posts.go index 14224f2..42e5b4a 100644 --- a/src/http/posts.go +++ b/src/http/posts.go @@ -40,10 +40,16 @@ func (a *api) postPreprocessFuncImage(args ...string) (string, error) { tpl = txttpl.Must(tpl.Parse(mustReadTplFile("image.html"))) tplPayload := struct { + RootURL render.URLBuilder ID string Descr string Resizable bool }{ + RootURL: render.NewURLBuilder( + a.params.PublicURL, + a.params.PublicURL, // httpURL + a.params.GeminiPublicURL, + ), ID: id, Descr: descr, Resizable: asset.IsImageResizable(id), diff --git a/src/http/tpl.go b/src/http/tpl.go index 2711259..c4afbdc 100644 --- a/src/http/tpl.go +++ b/src/http/tpl.go @@ -135,6 +135,8 @@ func (a *api) newTPLData(r *http.Request, payload interface{}) tplData { r.Context(), r.URL, a.params.PublicURL, + a.params.PublicURL, // httpURL + a.params.GeminiPublicURL, a.params.GeminiGatewayURL, a.params.PostStore, a.params.PostAssetStore, diff --git a/src/http/tpl/admin.html b/src/http/tpl/admin.html index 0b4b4e3..2dfab0f 100644 --- a/src/http/tpl/admin.html +++ b/src/http/tpl/admin.html @@ -7,9 +7,9 @@ mostly left open to inspection, but you will not able to change anything without providing credentials. {{ end }} diff --git a/src/http/tpl/base.html b/src/http/tpl/base.html index 47644f7..f0419d5 100644 --- a/src/http/tpl/base.html +++ b/src/http/tpl/base.html @@ -3,12 +3,12 @@ {{ .Title }} - - - - - - + + + + + + @@ -105,17 +105,17 @@ mediocregopher's lil web corner

- Home + Home  //  - Posts + Posts  /  - Follow + Follow  /  - RSS + RSS  //  Source  /  - License + License {{ template "body" . }} diff --git a/src/http/tpl/draft-posts-manage.html b/src/http/tpl/draft-posts-manage.html index b1b4362..417f716 100644 --- a/src/http/tpl/draft-posts-manage.html +++ b/src/http/tpl/draft-posts-manage.html @@ -1,6 +1,6 @@ {{ define "body" }} - {{ $page := .GetQueryIntValue "p" 0 -}} + {{ $page := .GetQueryIntValue "page" 0 -}} {{ $getPostsRes := .GetDraftPosts $page 20 -}}

- Back to Admin + Back to Admin

Drafts

- New Draft + New Draft

{{ if gt $page 0 }}

- < < Previous Page + < < Previous Page

{{ end }} @@ -32,13 +32,13 @@ {{ .Title }} - + Edit
- Next Page > > + Next Page > >

{{ end }} diff --git a/src/http/tpl/follow.html b/src/http/tpl/follow.html index 1958f95..091af49 100644 --- a/src/http/tpl/follow.html +++ b/src/http/tpl/follow.html @@ -6,7 +6,7 @@

- {{ BlogHTTPURL "feed.xml" }} + {{ .RootURL.Absolute.Path "feed.xml" }}

diff --git a/src/http/tpl/gemini-cta.html b/src/http/tpl/gemini-cta.html index 89b8e8b..77c1114 100644 --- a/src/http/tpl/gemini-cta.html +++ b/src/http/tpl/gemini-cta.html @@ -2,11 +2,9 @@

This site can also be accessed via the gemini protocol: - - {{ BlogGeminiURL "/" }} - + {{ .RootURL.Gemini.HTMLSafe }}

- What is gemini? + What is gemini?

diff --git a/src/http/tpl/image.html b/src/http/tpl/image.html index c6c19b3..7778625 100644 --- a/src/http/tpl/image.html +++ b/src/http/tpl/image.html @@ -1,7 +1,7 @@
- + {{ .Descr }} diff --git a/src/http/tpl/index.html b/src/http/tpl/index.html index 7f6399a..2685f4f 100644 --- a/src/http/tpl/index.html +++ b/src/http/tpl/index.html @@ -2,9 +2,9 @@

This here's my little corner of the web, where I publish - posts + posts about projects I'm working on and things that interest me (which you can - follow, + follow, if you like).

@@ -12,7 +12,7 @@

Feel free to hmu over email or Signal if you'd like to get in touch.

  • Email: me@mediocregopher.com
  • -
  • GPG Key
  • +
  • GPG Key
  • Signal: mediocregopher.01 diff --git a/src/http/tpl/post-assets-manage.html b/src/http/tpl/post-assets-manage.html index a0b0da0..7e01ff4 100644 --- a/src/http/tpl/post-assets-manage.html +++ b/src/http/tpl/post-assets-manage.html @@ -3,7 +3,7 @@ {{ $assetIDs := .GetPostAssetIDs }}

    - Back to Admin + Back to Admin

    Assets

    @@ -15,7 +15,7 @@ overwritten.

    - +
    @@ -37,10 +37,10 @@ {{ range $assetIDs }} - {{ . }} + {{ . }} diff --git a/src/http/tpl/post-edit.html b/src/http/tpl/post-edit.html index 28dcd0e..1c40a3a 100644 --- a/src/http/tpl/post-edit.html +++ b/src/http/tpl/post-edit.html @@ -6,17 +6,17 @@

    {{ if .Payload.IsDraft }} - + Back to Drafts {{ else }} - + Back to Posts {{ end }}

    - + @@ -36,7 +36,7 @@ {{ $post.ID }} {{ else }} - {{ $post.ID }} + {{ $post.ID }} {{ end }} @@ -135,12 +135,12 @@ {{ if .Payload.IsDraft }} - +

    - Back to Admin + Back to Admin

    Posts

    {{ if gt $page 0 }}

    - < < Previous Page + < < Previous Page

    {{ end }} @@ -33,15 +33,15 @@ {{ range $getPostsRes.Posts }} - +
    {{ .PublishedAt.Local.Format "2006-01-02 15:04:05 MST" }}{{ .Title }}{{ .Title }} - + Edit - Next Page > > + Next Page > >

    {{ end }} diff --git a/src/http/tpl/posts.html b/src/http/tpl/posts.html index 2fa336d..0df166a 100644 --- a/src/http/tpl/posts.html +++ b/src/http/tpl/posts.html @@ -1,11 +1,11 @@ {{ define "body" }} - {{ $page := .GetQueryIntValue "p" 0 -}} + {{ $page := .GetQueryIntValue "page" 0 -}} {{ $getPostsRes := .GetPosts $page 20 -}} {{ if gt $page 0 }}

    - < < Previous Page + < < Previous Page

    {{ else }}

    @@ -17,7 +17,7 @@

      {{ range $getPostsRes.Posts }}
    • - + {{ .PublishedAt.Format "2006-01-02" }} - {{ .Title }} {{ if .Description }} @@ -29,7 +29,7 @@ {{ if $getPostsRes.HasMore }}

      - Next Page > > + Next Page > >

      {{ end }} diff --git a/src/render/methods.go b/src/render/methods.go index 9b5a41e..ee22dfd 100644 --- a/src/render/methods.go +++ b/src/render/methods.go @@ -56,6 +56,8 @@ type Methods struct { ctx context.Context url *url.URL publicURL *url.URL + httpURL *url.URL + geminiURL *url.URL geminiGatewayURL *url.URL postStore post.Store postAssetStore asset.Store @@ -71,6 +73,8 @@ func NewMethods( ctx context.Context, url *url.URL, publicURL *url.URL, + httpURL *url.URL, + geminiURL *url.URL, geminiGatewayURL *url.URL, postStore post.Store, postAssetStore asset.Store, @@ -81,6 +85,8 @@ func NewMethods( ctx, url, publicURL, + httpURL, + geminiURL, geminiGatewayURL, postStore, postAssetStore, @@ -91,6 +97,10 @@ func NewMethods( } } +func (m *Methods) RootURL() URLBuilder { + return NewURLBuilder(m.publicURL, m.httpURL, m.geminiURL) +} + func (m *Methods) GetTags() ([]string, error) { return m.postStore.GetTags() } @@ -263,7 +273,3 @@ func (m *Methods) GetPath() (string, error) { } func (m *Methods) Add(a, b int) int { return a + b } - -func (m *Methods) URLIsSafe(s string) template.URL { - return template.URL(s) -} diff --git a/src/render/url.go b/src/render/url.go new file mode 100644 index 0000000..eb9756b --- /dev/null +++ b/src/render/url.go @@ -0,0 +1,168 @@ +package render + +import ( + "html/template" + "net/url" + "path" + "strconv" + "strings" +) + +const ( + urlBasePublic = iota + urlBaseHTTP + urlBaseGemini +) + +// URLBuilder is used to construct a URL for the site. The API of URLBuilder is +// designed to be convenient to used from a go template. +type URLBuilder struct { + publicURL, httpURL, geminiURL *url.URL + + abs bool + base int + path, method string + page int +} + +func NewURLBuilder(publicURL, httpURL, geminiURL *url.URL) URLBuilder { + return URLBuilder{ + publicURL: publicURL, + httpURL: httpURL, + geminiURL: geminiURL, + } +} + +func (b URLBuilder) String() string { + var u *url.URL + switch b.base { + case urlBasePublic: + u = b.publicURL + case urlBaseHTTP: + u = b.httpURL + case urlBaseGemini: + u = b.geminiURL + } + + u = u.JoinPath(b.path) + + if u.Scheme == "gemini" && + u.Host == b.geminiURL.Host && + !strings.HasSuffix(u.Path, "/") && + path.Ext(u.Path) == "" { + u.Path += ".gmi" + } + + { + query := url.Values{} + if b.method != "" { + query.Set("method", b.method) + } + if b.page > 0 { + query.Set("page", strconv.Itoa(b.page)) + } + if len(query) > 0 { + u.RawQuery = query.Encode() + } + } + + if abs := b.abs || u.Scheme != b.publicURL.Scheme; !abs { + u.Scheme = "" + u.Host = "" + } + + return u.String() +} + +func (b URLBuilder) HTMLSafe() template.URL { + return template.URL(b.String()) +} + +// Absolute returns a URLBuilder which will always construct a URL containing +// scheme and host. +func (b URLBuilder) Absolute() URLBuilder { + b.abs = true + return b +} + +func (b URLBuilder) Gemini() URLBuilder { + b.base = urlBaseGemini + return b +} + +func (b URLBuilder) HTTP() URLBuilder { + b.base = urlBaseHTTP + return b +} + +func (b URLBuilder) Assets() URLBuilder { + b.path = "assets/" + return b +} + +func (b URLBuilder) Asset(id string) URLBuilder { + b.path = "assets/" + id + return b +} + +func (b URLBuilder) Posts() URLBuilder { + b.path = "posts/" + return b +} + +func (b URLBuilder) Post(id string) URLBuilder { + b.path = "posts/" + id + return b +} + +func (b URLBuilder) Drafts() URLBuilder { + b.base = urlBaseHTTP + b.path = "drafts/" + return b +} + +func (b URLBuilder) Draft(id string) URLBuilder { + b.base = urlBaseHTTP + b.path = "drafts/" + id + return b +} + +func (b URLBuilder) Static(staticPath string) URLBuilder { + b.base = urlBaseHTTP + b.path = path.Join("static", staticPath) + return b +} + +func (b URLBuilder) Path(p string) URLBuilder { + b.path = p + return b +} + +func (b URLBuilder) Page(page int) URLBuilder { + b.page = page + return b +} + +func (b URLBuilder) MethodEdit() URLBuilder { + b.base = urlBaseHTTP + b.method = "edit" + return b +} + +func (b URLBuilder) MethodManage() URLBuilder { + b.base = urlBaseHTTP + b.method = "manage" + return b +} + +func (b URLBuilder) MethodDelete() URLBuilder { + b.base = urlBaseHTTP + b.method = "delete" + return b +} + +func (b URLBuilder) MethodPreview() URLBuilder { + b.base = urlBaseHTTP + b.method = "preview" + return b +} -- cgit v1.2.3