summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2022-05-20 14:30:09 -0600
committerBrian Picciano <mediocregopher@gmail.com>2022-05-20 14:30:26 -0600
commitaf434077ef3a971494fb0bc69ec9617c3b365abd (patch)
tree2a7c47c9450c2a6b5ac5bcae5c17b33f9a326db9
parent16cfbd19157df76e7296dddb287412f1099feb33 (diff)
Implement image macro for rendering images
-rw-r--r--srv/default.nix6
-rw-r--r--srv/src/cmd/mediocre-blog/main.go9
-rw-r--r--srv/src/http/api.go10
-rw-r--r--srv/src/http/assets.go36
-rw-r--r--srv/src/http/posts.go14
-rw-r--r--srv/src/http/tpl.go41
-rw-r--r--srv/src/http/tpl/image.html5
7 files changed, 88 insertions, 33 deletions
diff --git a/srv/default.nix b/srv/default.nix
index 7aa11b8..6f93f2f 100644
--- a/srv/default.nix
+++ b/srv/default.nix
@@ -25,12 +25,10 @@
# pow
export MEDIOCRE_BLOG_POW_SECRET="${config.powSecret}"
- # listening
+ # http
export MEDIOCRE_BLOG_LISTEN_PROTO="${config.listenProto}"
export MEDIOCRE_BLOG_LISTEN_ADDR="${config.listenAddr}"
-
- # api
- export MEDIOCRE_BLOG_API_AUTH_USERS='${builtins.toJSON config.httpAuthUsers}'
+ export MEDIOCRE_BLOG_HTTP_AUTH_USERS='${builtins.toJSON config.httpAuthUsers}'
'';
build = buildGoModule {
diff --git a/srv/src/cmd/mediocre-blog/main.go b/srv/src/cmd/mediocre-blog/main.go
index f76188b..ce43c61 100644
--- a/srv/src/cmd/mediocre-blog/main.go
+++ b/srv/src/cmd/mediocre-blog/main.go
@@ -2,7 +2,6 @@ package main
import (
"context"
- "encoding/json"
"os"
"os/signal"
"syscall"
@@ -56,8 +55,6 @@ func main() {
pathPrefix := cfg.String("path-prefix", "", "Prefix which is optionally applied to all URL paths rendered by the blog")
- 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")
-
// initialization
err := cfg.Init(ctx)
@@ -131,11 +128,6 @@ func main() {
postStore := post.NewStore(postSQLDB)
postAssetStore := post.NewAssetStore(postSQLDB)
- var httpAuthUsers map[string]string
- if err := json.Unmarshal([]byte(*httpAuthUsersStr), &httpAuthUsers); err != nil {
- logger.Fatal(ctx, "unmarshaling -http-auth-users", err)
- }
-
httpParams.Logger = logger.WithNamespace("http")
httpParams.PowManager = powMgr
httpParams.PathPrefix = *pathPrefix
@@ -144,7 +136,6 @@ func main() {
httpParams.MailingList = ml
httpParams.GlobalRoom = chatGlobalRoom
httpParams.UserIDCalculator = chatUserIDCalc
- httpParams.AuthUsers = httpAuthUsers
logger.Info(ctx, "listening")
httpAPI, err := http.New(httpParams)
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 @@
+<div style="text-align: center;">
+ <a href="{{ AssetURL .ID }}" target="_blank">
+ <img src="{{ AssetURL .ID }}{{ if .Resizable }}?w=800{{ end }}" />
+ </a>
+</div>