summaryrefslogtreecommitdiff
path: root/src/http
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2023-01-19 16:02:27 +0100
committerBrian Picciano <mediocregopher@gmail.com>2023-01-19 16:02:27 +0100
commitc23030733fe4cba578b14ad2c1d1292891202562 (patch)
tree05e200767b1a99e686dfcd18455e08fa977ebb56 /src/http
parente7b5b55f6718b25a437a891a06a26c21384b6818 (diff)
Add support for gemtext posts
Diffstat (limited to 'src/http')
-rw-r--r--src/http/posts.go94
-rw-r--r--src/http/tpl.go8
-rw-r--r--src/http/tpl/image.html5
-rw-r--r--src/http/tpl/post-edit.html25
4 files changed, 109 insertions, 23 deletions
diff --git a/src/http/posts.go b/src/http/posts.go
index 0f8924a..eff0eaa 100644
--- a/src/http/posts.go
+++ b/src/http/posts.go
@@ -15,37 +15,68 @@ import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
+ "github.com/mediocregopher/blog.mediocregopher.com/srv/gmi"
"github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
"github.com/mediocregopher/blog.mediocregopher.com/srv/post"
"github.com/mediocregopher/mediocre-go-lib/v2/mctx"
)
-func (a *api) parsePostBody(post post.Post) (*txttpl.Template, error) {
+func (a *api) parsePostBody(p post.Post) (*txttpl.Template, error) {
tpl := txttpl.New("root")
tpl = tpl.Funcs(txttpl.FuncMap(a.tplFuncs()))
tpl = txttpl.Must(tpl.New("image.html").Parse(mustReadTplFile("image.html")))
- tpl = tpl.Funcs(txttpl.FuncMap{
- "Image": func(id string) (string, error) {
-
- tplPayload := struct {
- ID string
- Resizable bool
- }{
- ID: id,
- Resizable: isImgResizable(id),
- }
- buf := new(bytes.Buffer)
- if err := tpl.ExecuteTemplate(buf, "image.html", tplPayload); err != nil {
- return "", err
- }
+ if p.Format == post.FormatMarkdown {
+ tpl = tpl.Funcs(txttpl.FuncMap{
+ "Image": func(id string) (string, error) {
+
+ tplPayload := struct {
+ ID string
+ Descr string
+ Resizable bool
+ }{
+ ID: id,
+ // I could use variadic args to make this work, I think
+ Descr: "TODO: proper alt text",
+ Resizable: isImgResizable(id),
+ }
+
+ buf := new(bytes.Buffer)
+ if err := tpl.ExecuteTemplate(buf, "image.html", tplPayload); err != nil {
+ return "", err
+ }
+
+ return buf.String(), nil
+ },
+ })
+ }
- return buf.String(), nil
- },
- })
+ if p.Format == post.FormatGemtext {
+ tpl = tpl.Funcs(txttpl.FuncMap{
+ "Image": func(id, descr string) (string, error) {
+
+ tplPayload := struct {
+ ID string
+ Descr string
+ Resizable bool
+ }{
+ ID: id,
+ Descr: descr,
+ Resizable: isImgResizable(id),
+ }
+
+ buf := new(bytes.Buffer)
+ if err := tpl.ExecuteTemplate(buf, "image.html", tplPayload); err != nil {
+ return "", err
+ }
+
+ return buf.String(), nil
+ },
+ })
+ }
- tpl, err := tpl.New(post.ID + "-body.html").Parse(post.Body)
+ tpl, err := tpl.New(p.ID + "-body.html").Parse(p.Body)
if err != nil {
return nil, err
@@ -73,6 +104,16 @@ func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload,
return postTplPayload{}, fmt.Errorf("executing post body as template: %w", err)
}
+ if storedPost.Format == post.FormatGemtext {
+
+ prevBodyBuf := bodyBuf
+ bodyBuf = new(bytes.Buffer)
+
+ if err := gmi.GemtextToMarkdown(bodyBuf, prevBodyBuf); 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")
@@ -324,10 +365,12 @@ func (a *api) editPostHandler(isDraft bool) http.Handler {
Post post.StoredPost
Tags []string
IsDraft bool
+ Formats []post.Format
}{
Post: storedPost,
Tags: tags,
IsDraft: isDraft,
+ Formats: post.Formats,
}
executeTemplate(rw, r, tpl, tplPayload)
@@ -336,12 +379,23 @@ func (a *api) editPostHandler(isDraft bool) http.Handler {
func postFromPostReq(r *http.Request) (post.Post, error) {
+ formatStr := r.PostFormValue("format")
+ if formatStr == "" {
+ return post.Post{}, errors.New("format is required")
+ }
+
+ format, err := post.FormatFromString(formatStr)
+ if err != nil {
+ return post.Post{}, fmt.Errorf("parsing format: %w", err)
+ }
+
p := post.Post{
ID: r.PostFormValue("id"),
Title: r.PostFormValue("title"),
Description: r.PostFormValue("description"),
Tags: strings.Fields(r.PostFormValue("tags")),
Series: r.PostFormValue("series"),
+ Format: format,
}
// textareas encode newlines as CRLF for historical reasons
@@ -353,7 +407,7 @@ func postFromPostReq(r *http.Request) (post.Post, error) {
p.Title == "" ||
p.Body == "" ||
len(p.Tags) == 0 {
- return post.Post{}, errors.New("ID, Title, Tags, and Body are all required")
+ return post.Post{}, errors.New("id, ritle, tags, and body are all required")
}
return p, nil
diff --git a/src/http/tpl.go b/src/http/tpl.go
index a9f89d7..f49232a 100644
--- a/src/http/tpl.go
+++ b/src/http/tpl.go
@@ -61,6 +61,11 @@ func (a *api) manageAssetsURL(abs bool) string {
return a.blogURL("assets?method=manage", abs)
}
+func (a *api) assetURL(id string, abs bool) string {
+ path := filepath.Join("assets", id)
+ return a.blogURL(path, false)
+}
+
func (a *api) draftPostURL(id string, abs bool) string {
path := filepath.Join("drafts", id)
return a.blogURL(path, abs)
@@ -96,8 +101,7 @@ func (a *api) tplFuncs() template.FuncMap {
return a.postURL(id, false)
},
"AssetURL": func(id string) string {
- path := filepath.Join("assets", id)
- return a.blogURL(path, false)
+ return a.assetURL(id, false)
},
"DraftURL": func(id string) string {
return a.draftPostURL(id, false)
diff --git a/src/http/tpl/image.html b/src/http/tpl/image.html
index ba9b75d..c6c19b3 100644
--- a/src/http/tpl/image.html
+++ b/src/http/tpl/image.html
@@ -1,5 +1,8 @@
<div style="text-align: center;">
<a href="{{ AssetURL .ID }}" target="_blank">
- <img src="{{ AssetURL .ID }}{{ if .Resizable }}?w=800{{ end }}" />
+ <img
+ src="{{ AssetURL .ID }}{{ if .Resizable }}?w=800{{ end }}"
+ alt="{{ .Descr }}"
+ />
</a>
</div>
diff --git a/src/http/tpl/post-edit.html b/src/http/tpl/post-edit.html
index 4c08744..c66b60a 100644
--- a/src/http/tpl/post-edit.html
+++ b/src/http/tpl/post-edit.html
@@ -25,6 +25,7 @@
<input
name="id"
type="text"
+ required
placeholder="e.g. how-to-fly-a-kite"
value="{{ .Payload.Post.ID }}" />
{{ else if .Payload.IsDraft }}
@@ -43,6 +44,7 @@
<input
name="tags"
type="text"
+ required
value="{{- range $i, $tag := .Payload.Post.Tags -}}
{{- if ne $i 0 }} {{ end }}{{ $tag -}}
{{- end -}}
@@ -75,6 +77,7 @@
<input
name="title"
type="text"
+ required
value="{{ .Payload.Post.Title }}" />
</td>
</tr>
@@ -89,11 +92,33 @@
</td>
</tr>
+ <tr>
+ <td>Format</td>
+ <td>
+ <select name="format" required>
+ <option value=""></option>
+
+ {{ $format := .Payload.Post.Format }}
+ {{ range .Payload.Formats -}}
+ <option
+ {{- if eq . $format }}
+ selected
+ {{- end }}
+ value="{{ . }}" >
+ {{ . }}
+ </option>
+ {{- end }}
+
+ </select>
+ </td>
+ </tr>
+
</table>
<p>
<textarea
name="body"
+ required
placeholder="Post body"
style="width:100%;height: 75vh;"
>