From af434077ef3a971494fb0bc69ec9617c3b365abd Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Fri, 20 May 2022 14:30:09 -0600 Subject: Implement image macro for rendering images --- srv/src/http/api.go | 10 ++++++++++ srv/src/http/assets.go | 36 +++++++++++++++++++++--------------- srv/src/http/posts.go | 14 +++++++++++++- srv/src/http/tpl.go | 41 +++++++++++++++++++++++++++++++++++++---- srv/src/http/tpl/image.html | 5 +++++ 5 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 srv/src/http/tpl/image.html (limited to 'srv/src/http') diff --git a/srv/src/http/api.go b/srv/src/http/api.go index abf08e7..8e89c4e 100644 --- a/srv/src/http/api.go +++ b/srv/src/http/api.go @@ -4,6 +4,7 @@ package http import ( "context" "embed" + "encoding/json" "errors" "fmt" "html/template" @@ -57,6 +58,15 @@ type Params struct { func (p *Params) SetupCfg(cfg *cfg.Cfg) { cfg.StringVar(&p.ListenProto, "listen-proto", "tcp", "Protocol to listen for HTTP requests with") cfg.StringVar(&p.ListenAddr, "listen-addr", ":4000", "Address/path to listen for HTTP requests on") + + httpAuthUsersStr := cfg.String("http-auth-users", "{}", "JSON object with usernames as values and password hashes (produced by the hash-password binary) as values. Denotes users which are able to edit server-side data") + + cfg.OnInit(func(context.Context) error { + if err := json.Unmarshal([]byte(*httpAuthUsersStr), &p.AuthUsers); err != nil { + return fmt.Errorf("unmarshaling -http-auth-users: %w", err) + } + return nil + }) } // Annotate implements mctx.Annotator interface. diff --git a/srv/src/http/assets.go b/srv/src/http/assets.go index f782c69..aacef96 100644 --- a/srv/src/http/assets.go +++ b/srv/src/http/assets.go @@ -17,6 +17,15 @@ import ( "golang.org/x/image/draw" ) +func isImgResizable(id string) bool { + switch strings.ToLower(filepath.Ext(id)) { + case ".jpg", ".jpeg", ".png": + return true + default: + return false + } +} + func resizeImage(out io.Writer, in io.Reader, maxWidth float64) error { img, format, err := image.Decode(in) @@ -123,24 +132,21 @@ func (a *api) getPostAssetHandler() http.Handler { return } - switch ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(id), ".")); ext { - case "jpg", "jpeg", "png": - - if err := resizeImage(rw, buf, float64(maxWidth)); err != nil { - apiutil.InternalServerError( - rw, r, - fmt.Errorf( - "resizing image with id %q to size %d: %w", - id, maxWidth, err, - ), - ) - } - - default: - apiutil.BadRequest(rw, r, fmt.Errorf("cannot resize file with extension %q", ext)) + if !isImgResizable(id) { + apiutil.BadRequest(rw, r, fmt.Errorf("cannot resize file %q", id)) return } + if err := resizeImage(rw, buf, float64(maxWidth)); err != nil { + apiutil.InternalServerError( + rw, r, + fmt.Errorf( + "resizing image with id %q to size %d: %w", + id, maxWidth, err, + ), + ) + } + }) } diff --git a/srv/src/http/posts.go b/srv/src/http/posts.go index fd583ea..0aea3e3 100644 --- a/srv/src/http/posts.go +++ b/srv/src/http/posts.go @@ -1,6 +1,7 @@ package http import ( + "bytes" "errors" "fmt" "html/template" @@ -23,13 +24,24 @@ type postTplPayload struct { } func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload, error) { + + bodyTpl, err := a.parseTpl(storedPost.Body) + if err != nil { + return postTplPayload{}, fmt.Errorf("parsing post body as template: %w", err) + } + + bodyBuf := new(bytes.Buffer) + if err := bodyTpl.Execute(bodyBuf, nil); err != nil { + return postTplPayload{}, fmt.Errorf("executing post body as template: %w", err) + } + parserExt := parser.CommonExtensions | parser.AutoHeadingIDs parser := parser.NewWithExtensions(parserExt) htmlFlags := html.CommonFlags | html.HrefTargetBlank htmlRenderer := html.NewRenderer(html.RendererOptions{Flags: htmlFlags}) - renderedBody := markdown.ToHTML([]byte(storedPost.Body), parser, htmlRenderer) + renderedBody := markdown.ToHTML(bodyBuf.Bytes(), parser, htmlRenderer) tplPayload := postTplPayload{ StoredPost: storedPost, diff --git a/srv/src/http/tpl.go b/srv/src/http/tpl.go index 65f23a7..62a4d06 100644 --- a/srv/src/http/tpl.go +++ b/srv/src/http/tpl.go @@ -1,6 +1,7 @@ package http import ( + "bytes" "embed" "fmt" "html/template" @@ -27,7 +28,7 @@ func mustReadTplFile(fileName string) string { return string(b) } -func (a *api) mustParseTpl(name string) *template.Template { +func (a *api) parseTpl(tplBody string) (*template.Template, error) { blogURL := func(path string) string { @@ -43,7 +44,9 @@ func (a *api) mustParseTpl(name string) *template.Template { return path } - tpl := template.New("").Funcs(template.FuncMap{ + tpl := template.New("root") + + tpl = tpl.Funcs(template.FuncMap{ "BlogURL": blogURL, "StaticURL": func(path string) string { path = filepath.Join("static", path) @@ -62,9 +65,39 @@ func (a *api) mustParseTpl(name string) *template.Template { }, }) - tpl = template.Must(tpl.Parse(mustReadTplFile(name))) + tpl = template.Must(tpl.New("image.html").Parse(mustReadTplFile("image.html"))) - return tpl + tpl = tpl.Funcs(template.FuncMap{ + "Image": func(id string) (template.HTML, 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 + } + + return template.HTML(buf.Bytes()), nil + }, + }) + + var err error + + if tpl, err = tpl.New("").Parse(tplBody); err != nil { + return nil, err + } + + return tpl, nil +} + +func (a *api) mustParseTpl(name string) *template.Template { + return template.Must(a.parseTpl(mustReadTplFile(name))) } func (a *api) mustParseBasedTpl(name string) *template.Template { diff --git a/srv/src/http/tpl/image.html b/srv/src/http/tpl/image.html new file mode 100644 index 0000000..ba9b75d --- /dev/null +++ b/srv/src/http/tpl/image.html @@ -0,0 +1,5 @@ +
+ + + +
-- cgit v1.2.3