Compare commits

...

4 Commits

Author SHA1 Message Date
Brian Picciano 3f97311514 Add notice atop md->gmi translated pages 1 year ago
Brian Picciano b766eefe7c Add gemini CTA to HTTP pages 1 year ago
Brian Picciano 6b3933282e Refactor URL construction a bit 1 year ago
Brian Picciano 63cc6cb217 Fix squished manage post edit button 1 year ago
  1. 1
      src/cmd/mediocre-blog/main.go
  2. 12
      src/gmi/tpl.go
  3. 4
      src/gmi/tpl/feed.xml
  4. 8
      src/gmi/tpl/posts/post.gmi
  5. 3
      src/http/feed.go
  6. 4
      src/http/http.go
  7. 19
      src/http/posts.go
  8. 69
      src/http/tpl.go
  9. 4
      src/http/tpl/follow.html
  10. 12
      src/http/tpl/gemini-cta.html
  11. 2
      src/http/tpl/index.html
  12. 2
      src/http/tpl/post.html
  13. 6
      src/http/tpl/posts-manage.html
  14. 2
      src/http/tpl/posts.html
  15. 28
      src/post/preprocess.go

@ -112,6 +112,7 @@ func main() {
httpParams.PostAssetStore = postAssetStore httpParams.PostAssetStore = postAssetStore
httpParams.PostDraftStore = postDraftStore httpParams.PostDraftStore = postDraftStore
httpParams.MailingList = ml httpParams.MailingList = ml
httpParams.GeminiPublicURL = gmiParams.PublicURL
logger.Info(ctx, "starting http api") logger.Info(ctx, "starting http api")
httpAPI, err := http.New(httpParams) httpAPI, err := http.New(httpParams)

@ -161,6 +161,9 @@ func (a *api) tplHandler() (gemini.Handler, error) {
BlogHTTPURL: func(path string) string { BlogHTTPURL: func(path string) string {
return blogURL(a.params.HTTPPublicURL, path, true) return blogURL(a.params.HTTPPublicURL, path, true)
}, },
BlogGeminiURL: func(path string) string {
return blogURL(a.params.PublicURL, path, true)
},
AssetURL: func(id string) string { AssetURL: func(id string) string {
path := filepath.Join("assets", id) path := filepath.Join("assets", id)
return blogURL(a.params.PublicURL, path, false) return blogURL(a.params.PublicURL, path, false)
@ -193,16 +196,17 @@ func (a *api) tplHandler() (gemini.Handler, error) {
allTpls := template.New("") allTpls := template.New("")
allTpls.Funcs(preprocessFuncs.ToFuncsMap()) allTpls.Funcs(preprocessFuncs.ToFuncMap())
allTpls.Funcs(template.FuncMap{ allTpls.Funcs(template.FuncMap{
"BlogURLAbs": func(path string) string {
return blogURL(a.params.PublicURL, path, true)
},
"PostURLAbs": func(id string) string { "PostURLAbs": func(id string) string {
path := filepath.Join("posts", id) + ".gmi" path := filepath.Join("posts", id) + ".gmi"
return blogURL(a.params.PublicURL, path, true) return blogURL(a.params.PublicURL, path, true)
}, },
"PostHTTPURL": func(id string) string {
path := filepath.Join("posts", id)
return preprocessFuncs.BlogHTTPURL(path)
},
}) })
err := fs.WalkDir(tplFS, "tpl", func(path string, d fs.DirEntry, err error) error { err := fs.WalkDir(tplFS, "tpl", func(path string, d fs.DirEntry, err error) error {

@ -3,11 +3,11 @@
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"> <?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">
<title>mediocregopher's lil web corner</title> <title>mediocregopher's lil web corner</title>
<id>{{ BlogURLAbs "/" }}</id> <id>{{ BlogGeminiURL "/" }}</id>
{{ if gt (len $posts) 0 -}} {{ if gt (len $posts) 0 -}}
<updated>{{ (index $posts 0).PublishedAt.Format "2006-01-02T15:04:05Z07:00" }}</updated> <updated>{{ (index $posts 0).PublishedAt.Format "2006-01-02T15:04:05Z07:00" }}</updated>
{{ end -}} {{ end -}}
<link href="{{ BlogURLAbs "/" }}"></link> <link href="{{ BlogGeminiURL "/" }}"></link>
<author> <author>
<name>mediocregopher</name> <name>mediocregopher</name>
</author> </author>

@ -1,5 +1,13 @@
{{ $post := .GetPostByID (.GetQueryValue "id" "") -}} {{ $post := .GetPostByID (.GetQueryValue "id" "") -}}
{{ 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 }}
{{ end -}}
# {{ $post.Title }} # {{ $post.Title }}
{{ if ne $post.Description "" -}} {{ if ne $post.Description "" -}}

@ -3,7 +3,6 @@ package http
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"path/filepath"
"github.com/gorilla/feeds" "github.com/gorilla/feeds"
"github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil" "github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
@ -54,7 +53,7 @@ func (a *api) renderFeedHandler() http.Handler {
feed.Updated = post.LastUpdatedAt feed.Updated = post.LastUpdatedAt
} }
postURL := publicURL + filepath.Join("/posts", post.ID) postURL := a.postURL(post.ID, true)
item := &feeds.Item{ item := &feeds.Item{
Title: post.Title, Title: post.Title,

@ -44,6 +44,10 @@ type Params struct {
// PublicURL is the base URL which site visitors can navigate to. // PublicURL is the base URL which site visitors can navigate to.
PublicURL *url.URL PublicURL *url.URL
// GeminiPublicURL is the base URL which gemini site visitors can navigate
// to.
GeminiPublicURL *url.URL
// ListenProto and ListenAddr are passed into net.Listen to create the // ListenProto and ListenAddr are passed into net.Listen to create the
// API's listener. Both "tcp" and "unix" protocols are explicitly // API's listener. Both "tcp" and "unix" protocols are explicitly
// supported. // supported.

@ -66,14 +66,16 @@ type postTplPayload struct {
Body template.HTML Body template.HTML
} }
func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload, error) { func (a *api) postPreprocessFuncs() post.PreprocessFunctions {
return post.PreprocessFunctions{
preprocessFuncs := post.PreprocessFunctions{
BlogURL: func(path string) string { BlogURL: func(path string) string {
return a.blogURL(path, false) return a.blogURL(a.params.PublicURL, path, false)
}, },
BlogHTTPURL: func(path string) string { BlogHTTPURL: func(path string) string {
return a.blogURL(path, false) return a.blogURL(a.params.PublicURL, path, true)
},
BlogGeminiURL: func(path string) string {
return a.blogURL(a.params.GeminiPublicURL, path, true)
}, },
AssetURL: func(id string) string { AssetURL: func(id string) string {
return a.assetURL(id, false) return a.assetURL(id, false)
@ -83,10 +85,15 @@ func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload,
}, },
StaticURL: func(path string) string { StaticURL: func(path string) string {
path = filepath.Join("static", path) path = filepath.Join("static", path)
return a.blogURL(path, false) return a.blogURL(a.params.PublicURL, path, false)
}, },
Image: a.postPreprocessFuncImage, Image: a.postPreprocessFuncImage,
} }
}
func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload, error) {
preprocessFuncs := a.postPreprocessFuncs()
bodyBuf := new(bytes.Buffer) bodyBuf := new(bytes.Buffer)

@ -6,6 +6,7 @@ import (
"html/template" "html/template"
"io/fs" "io/fs"
"net/http" "net/http"
"net/url"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
@ -27,28 +28,28 @@ func mustReadTplFile(fileName string) string {
return string(b) return string(b)
} }
func (a *api) blogURL(path string, abs bool) string { func (a *api) blogURL(base *url.URL, path string, abs bool) string {
// filepath.Join strips trailing slash, but we want to keep it // filepath.Join strips trailing slash, but we want to keep it
trailingSlash := strings.HasSuffix(path, "/") trailingSlash := strings.HasSuffix(path, "/")
res := filepath.Join("/", a.params.PublicURL.Path, path) path = filepath.Join("/", base.Path, path)
if trailingSlash && res != "/" { if trailingSlash && path != "/" {
res += "/" path += "/"
} }
if abs { if !abs {
u := *a.params.PublicURL return path
u.Path = res
res = u.String()
} }
return res u := *base
u.Path = path
return u.String()
} }
func (a *api) postURL(id string, abs bool) string { func (a *api) postURL(id string, abs bool) string {
path := filepath.Join("posts", id) path := filepath.Join("posts", id)
return a.blogURL(path, abs) return a.blogURL(a.params.PublicURL, path, abs)
} }
func (a *api) editPostURL(id string, abs bool) string { func (a *api) editPostURL(id string, abs bool) string {
@ -56,21 +57,21 @@ func (a *api) editPostURL(id string, abs bool) string {
} }
func (a *api) managePostsURL(abs bool) string { func (a *api) managePostsURL(abs bool) string {
return a.blogURL("posts?method=manage", abs) return a.blogURL(a.params.PublicURL, "posts?method=manage", abs)
} }
func (a *api) manageAssetsURL(abs bool) string { func (a *api) manageAssetsURL(abs bool) string {
return a.blogURL("assets?method=manage", abs) return a.blogURL(a.params.PublicURL, "assets?method=manage", abs)
} }
func (a *api) assetURL(id string, abs bool) string { func (a *api) assetURL(id string, abs bool) string {
path := filepath.Join("assets", id) path := filepath.Join("assets", id)
return a.blogURL(path, false) return a.blogURL(a.params.PublicURL, path, false)
} }
func (a *api) draftPostURL(id string, abs bool) string { func (a *api) draftPostURL(id string, abs bool) string {
path := filepath.Join("drafts", id) path := filepath.Join("drafts", id)
return a.blogURL(path, abs) return a.blogURL(a.params.PublicURL, path, abs)
} }
func (a *api) editDraftPostURL(id string, abs bool) string { func (a *api) editDraftPostURL(id string, abs bool) string {
@ -78,42 +79,29 @@ func (a *api) editDraftPostURL(id string, abs bool) string {
} }
func (a *api) manageDraftPostsURL(abs bool) string { func (a *api) manageDraftPostsURL(abs bool) string {
return a.blogURL("drafts", abs) + "?method=manage" return a.blogURL(a.params.PublicURL, "drafts", abs) + "?method=manage"
} }
func (a *api) draftsURL(abs bool) string { func (a *api) draftsURL(abs bool) string {
return a.blogURL("drafts", abs) return a.blogURL(a.params.PublicURL, "drafts", abs)
} }
func (a *api) tplFuncs() template.FuncMap { func (a *api) tplFuncs() template.FuncMap {
return template.FuncMap{ return template.FuncMap{
"BlogURL": func(path string) string {
return a.blogURL(path, false)
},
"BlogURLAbs": func(path string) string {
return a.blogURL(path, true)
},
"StaticURL": func(path string) string {
path = filepath.Join("static", path)
return a.blogURL(path, false)
},
"StaticInlineCSS": func(path string) (template.CSS, error) { "StaticInlineCSS": func(path string) (template.CSS, error) {
path = filepath.Join("static", path) path = filepath.Join("static", path)
b, err := staticFS.ReadFile(path) b, err := staticFS.ReadFile(path)
return template.CSS(b), err return template.CSS(b), err
}, },
"PostURL": func(id string) string {
return a.postURL(id, false)
},
"AssetURL": func(id string) string {
return a.assetURL(id, false)
},
"DraftURL": func(id string) string { "DraftURL": func(id string) string {
return a.draftPostURL(id, false) return a.draftPostURL(id, false)
}, },
"DateTimeFormat": func(t time.Time) string { "DateTimeFormat": func(t time.Time) string {
return t.Format("2006-01-02") return t.Format("2006-01-02")
}, },
"SafeURL": func(u string) template.URL {
return template.URL(u)
},
} }
} }
@ -121,6 +109,7 @@ func (a *api) parseTpl(name, tplBody string) (*template.Template, error) {
tpl := template.New(name) tpl := template.New(name)
tpl = tpl.Funcs(a.tplFuncs()) tpl = tpl.Funcs(a.tplFuncs())
tpl = tpl.Funcs(template.FuncMap(a.postPreprocessFuncs().ToFuncMap()))
var err error var err error
@ -137,6 +126,7 @@ func (a *api) mustParseTpl(name string) *template.Template {
func (a *api) mustParseBasedTpl(name string) *template.Template { func (a *api) mustParseBasedTpl(name string) *template.Template {
tpl := a.mustParseTpl(name) 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 = template.Must(tpl.New("base.html").Parse(mustReadTplFile("base.html")))
return tpl return tpl
} }
@ -145,15 +135,19 @@ type tplData struct {
Payload interface{} Payload interface{}
} }
func newTPLData(r *http.Request, payload interface{}) tplData {
return tplData{
Payload: payload,
}
}
// executeTemplate expects to be the final action in an http.Handler // executeTemplate expects to be the final action in an http.Handler
func executeTemplate( func executeTemplate(
rw http.ResponseWriter, r *http.Request, rw http.ResponseWriter, r *http.Request,
tpl *template.Template, payload interface{}, tpl *template.Template, payload interface{},
) { ) {
tplData := tplData{ tplData := newTPLData(r, payload)
Payload: payload,
}
if err := tpl.Execute(rw, tplData); err != nil { if err := tpl.Execute(rw, tplData); err != nil {
apiutil.InternalServerError( apiutil.InternalServerError(
@ -178,7 +172,10 @@ func (a *api) renderDumbTplHandler(tplName string) http.Handler {
tpl := a.mustParseBasedTpl(tplName) tpl := a.mustParseBasedTpl(tplName)
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if err := tpl.Execute(rw, nil); err != nil {
tplData := newTPLData(r, nil)
if err := tpl.Execute(rw, tplData); err != nil {
apiutil.InternalServerError( apiutil.InternalServerError(
rw, r, fmt.Errorf("rendering %q: %w", tplName, err), rw, r, fmt.Errorf("rendering %q: %w", tplName, err),
) )

@ -114,7 +114,7 @@ emailSubscribe.onclick = async () => {
</p> </p>
<p> <p>
<a href="{{ BlogURLAbs "feed.xml" }}">{{ BlogURLAbs "feed.xml" }}</a> <a href="{{ BlogHTTPURL "feed.xml" }}">{{ BlogHTTPURL "feed.xml" }}</a>
</p> </p>
<p> <p>
@ -145,6 +145,8 @@ emailSubscribe.onclick = async () => {
</li> </li>
</ul> </ul>
{{ template "gemini-cta.html" . }}
{{ end }} {{ end }}
{{ template "base.html" . }} {{ template "base.html" . }}

@ -0,0 +1,12 @@
<hr/>
<p>
This site can also be accessed via the gemini protocol:
<a href="{{ BlogGeminiURL "/" | SafeURL }}">
{{ BlogGeminiURL "/" }}
</a>
</p>
<p>
<a href="{{ PostURL "gemspace-tour" }}">What is gemini?</a>
</p>

@ -50,6 +50,8 @@
<li><a href="https://yamakan.place/palestine/#">Radio alHara</a> is another great internet radio station.</li> <li><a href="https://yamakan.place/palestine/#">Radio alHara</a> is another great internet radio station.</li>
</ul> </ul>
{{ template "gemini-cta.html" . }}
{{ end }} {{ end }}
{{ template "base.html" . }} {{ template "base.html" . }}

@ -38,6 +38,8 @@
</em></p> </em></p>
{{ end }} {{ end }}
{{ template "gemini-cta.html" . }}
{{ end }} {{ end }}
{{ template "base.html" . }} {{ template "base.html" . }}

@ -13,6 +13,12 @@
{{ end }} {{ end }}
<table> <table>
<colgroup>
<col span="1" style="width: auto;">
<col span="1" style="width: auto;">
<col span="1" style="width: 5rem;">
<col span="1" style="width: auto;">
</colgroup>
{{ range .Payload.Posts }} {{ range .Payload.Posts }}
<tr> <tr>

@ -30,6 +30,8 @@
</p> </p>
{{ end }} {{ end }}
{{ template "gemini-cta.html" . }}
{{ end }} {{ end }}
{{ template "base.html" . }} {{ template "base.html" . }}

@ -17,12 +17,19 @@ type PreprocessFunctions struct {
// The given path should not have a leading slash. // The given path should not have a leading slash.
BlogURL func(path string) string BlogURL func(path string) string
// BlogURL returns the given string, rooted to the base URL of the blog's // BlogHTTPURL returns the given string, rooted to the base URL of the
// HTTP server (which may or may not include path components itself). // blog's HTTP server (which may or may not include path components itself).
// //
// The given path should not have a leading slash. // The given path should not have a leading slash.
BlogHTTPURL func(path string) string BlogHTTPURL func(path string) string
// BlogGeminiURL returns the given string, rooted to the base URL of the
// blog's gemini server (which may or may not include path components
// itself).
//
// The given path should not have a leading slash.
BlogGeminiURL func(path string) string
// AssetURL returns the URL of the asset with the given ID. // AssetURL returns the URL of the asset with the given ID.
AssetURL func(id string) string AssetURL func(id string) string
@ -43,14 +50,15 @@ type PreprocessFunctions struct {
Image func(args ...string) (string, error) Image func(args ...string) (string, error)
} }
func (funcs PreprocessFunctions) ToFuncsMap() template.FuncMap { func (funcs PreprocessFunctions) ToFuncMap() template.FuncMap {
return template.FuncMap{ return template.FuncMap{
"BlogURL": funcs.BlogURL, "BlogURL": funcs.BlogURL,
"BlogHTTPURL": funcs.BlogHTTPURL, "BlogHTTPURL": funcs.BlogHTTPURL,
"AssetURL": funcs.AssetURL, "BlogGeminiURL": funcs.BlogGeminiURL,
"PostURL": funcs.PostURL, "AssetURL": funcs.AssetURL,
"StaticURL": funcs.StaticURL, "PostURL": funcs.PostURL,
"Image": funcs.Image, "StaticURL": funcs.StaticURL,
"Image": funcs.Image,
} }
} }
@ -61,7 +69,7 @@ func (p Post) PreprocessBody(into io.Writer, funcs PreprocessFunctions) error {
tpl := template.New("") tpl := template.New("")
tpl.Funcs(funcs.ToFuncsMap()) tpl.Funcs(funcs.ToFuncMap())
tpl, err := tpl.Parse(p.Body) tpl, err := tpl.Parse(p.Body)

Loading…
Cancel
Save