diff options
Diffstat (limited to 'internal/web/handlers_design.go')
| -rw-r--r-- | internal/web/handlers_design.go | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/internal/web/handlers_design.go b/internal/web/handlers_design.go index 601ba34..0db66c2 100644 --- a/internal/web/handlers_design.go +++ b/internal/web/handlers_design.go @@ -2,12 +2,14 @@ package web import ( "bytes" + "encoding/json" "errors" "io" "mime/multipart" "net/http" "path/filepath" "strconv" + "strings" "github.com/google/uuid" "github.com/gramanas/blogspace/internal/store" @@ -89,6 +91,24 @@ func (s *Server) storeUpload(r *http.Request, fh *multipart.FileHeader) (*store. return s.st.CreateImage(r.Context(), currentBlog(r).ID, name, ct, buf.Bytes()) } +// imageMarkdown is the line the editor inserts for an uploaded image. +func imageMarkdown(img *store.Image) string { + return "![" + strings.NewReplacer("]", "", "\n", " ").Replace(img.Filename) + "](/media/" + img.ID.String() + ")" +} + +// appendImageMD is the no-JavaScript path of "Insert image": the file arrives +// with the form itself and is appended to the end of the text on save. +func appendImageMD(md string, img *store.Image) string { + if img == nil { + return md + } + md = strings.TrimRight(md, "\n") + if md != "" { + md += "\n\n" + } + return md + imageMarkdown(img) + "\n" +} + func kbString(n int64) string { if n >= 1<<20 { return strconv.FormatInt(n>>20, 10) + " MB" @@ -107,24 +127,45 @@ func (s *Server) handleImages(w http.ResponseWriter, r *http.Request) { s.render(w, r, "dashboard/images.html", map[string]any{"images": images}) } +// handleImageUpload serves the Images page form and, when the client asks for +// JSON, the editor's "Insert image" script. func (s *Server) handleImageUpload(w http.ResponseWriter, r *http.Request) { blog := currentBlog(r) + wantJSON := strings.Contains(r.Header.Get("Accept"), "application/json") + fail := func(msg string) { + if wantJSON { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": msg}) + return + } + s.plainError(w, http.StatusBadRequest, msg) + } if err := r.ParseMultipartForm(1 << 20); err != nil { - s.plainError(w, http.StatusBadRequest, "Upload too large or malformed form.") + fail("Upload too large or malformed form.") return } img, err := s.readUpload(r, "file") if err != nil { - s.plainError(w, http.StatusBadRequest, err.Error()) + fail(err.Error()) return } if img == nil { - s.plainError(w, http.StatusBadRequest, "Choose a file first.") + fail("Choose a file first.") + return + } + if wantJSON { + writeJSON(w, http.StatusOK, map[string]string{"id": img.ID.String(), "filename": img.Filename, "markdown": imageMarkdown(img)}) return } redirectOK(w, r, "/b/"+blog.Subdomain+"/images", "Uploaded "+img.Filename+".") } +func writeJSON(w http.ResponseWriter, status int, v any) { + w.Header().Set("Content-Type", "application/json") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(status) + _ = json.NewEncoder(w).Encode(v) +} + func (s *Server) handleImageDelete(w http.ResponseWriter, r *http.Request) { blog := currentBlog(r) id, err := uuid.Parse(r.PathValue("id")) |
