From c23030733fe4cba578b14ad2c1d1292891202562 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Thu, 19 Jan 2023 16:02:27 +0100 Subject: Add support for gemtext posts --- src/http/posts.go | 94 +++++++++++++++++++++++++++++++++++---------- src/http/tpl.go | 8 +++- src/http/tpl/image.html | 5 ++- src/http/tpl/post-edit.html | 25 ++++++++++++ 4 files changed, 109 insertions(+), 23 deletions(-) (limited to 'src/http') 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 // `` 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 @@
- + {{ .Descr }}
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 @@ {{ else if .Payload.IsDraft }} @@ -43,6 +44,7 @@ @@ -89,11 +92,33 @@ + + Format + + + + +