diff --git a/editor.go b/editor.go new file mode 100644 index 0000000..1676f9f --- /dev/null +++ b/editor.go @@ -0,0 +1,85 @@ +package main + +import ( + "bytes" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" +) + +const editorPath = "/editor" + +func serveEditor(w http.ResponseWriter, r *http.Request) { + render(w, templateEditor, &renderData{}) +} + +func serveEditorPost(w http.ResponseWriter, r *http.Request) { + if action := r.FormValue("editoraction"); action != "" { + if action == "loadupdate" { + parsedURL, err := url.Parse(r.FormValue("url")) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + post, err := getPost(parsedURL.Path) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + mf := post.toMfItem() + render(w, templateEditor, &renderData{ + Data: map[string]interface{}{ + "UpdatePostURL": parsedURL.String(), + "UpdatePostContent": mf.Properties.Content[0], + }, + }) + return + } else if action == "updatepost" { + urlValue := r.FormValue("url") + content := r.FormValue("content") + mf := map[string]interface{}{ + "action": actionUpdate, + "url": urlValue, + "replace": map[string][]string{ + "content": { + content, + }, + }, + } + jsonBytes, err := json.Marshal(mf) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + req, err := http.NewRequest(http.MethodPost, "", bytes.NewReader(jsonBytes)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + req.Header.Set(contentType, contentTypeJSON) + editorMicropubPost(w, req) + return + } + http.Error(w, "unknown editoraction", http.StatusBadRequest) + return + } + editorMicropubPost(w, r) +} + +func editorMicropubPost(w http.ResponseWriter, r *http.Request) { + recorder := httptest.NewRecorder() + addAllScopes(http.HandlerFunc(serveMicropubPost)).ServeHTTP(recorder, r) + result := recorder.Result() + if location := result.Header.Get("Location"); location != "" { + http.Redirect(w, r, result.Header.Get("Location"), http.StatusFound) + return + } + if result.StatusCode >= 200 && result.StatusCode <= 400 { + http.Redirect(w, r, editorPath, http.StatusFound) + return + } + w.WriteHeader(result.StatusCode) + body, _ := ioutil.ReadAll(result.Body) + w.Write(body) +} diff --git a/http.go b/http.go index 81a2c06..bd5d3ab 100644 --- a/http.go +++ b/http.go @@ -106,6 +106,13 @@ func buildHandler() (http.Handler, error) { } }) + // Editor + r.Route("/editor", func(mpRouter chi.Router) { + mpRouter.Use(authMiddleware) + mpRouter.Get("/", serveEditor) + mpRouter.Post("/", serveEditorPost) + }) + // IndieAuth r.Route("/indieauth", func(indieauthRouter chi.Router) { indieauthRouter.Use(middleware.NoCache) diff --git a/indieAuth.go b/indieAuth.go index 08e1fd7..826d3a5 100644 --- a/indieAuth.go +++ b/indieAuth.go @@ -21,3 +21,10 @@ func checkIndieAuth(next http.Handler) http.Handler { return }) } + +func addAllScopes(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + next.ServeHTTP(rw, r.WithContext(context.WithValue(r.Context(), "scope", "create update delete media"))) + return + }) +} diff --git a/micropub.go b/micropub.go index 7e771af..c33d391 100644 --- a/micropub.go +++ b/micropub.go @@ -90,6 +90,8 @@ func (p *post) toMfItem() *microformatItem { params["path"] = []string{p.Path} params["section"] = []string{p.Section} params["blog"] = []string{p.Blog} + params["published"] = []string{p.Published} + params["updated"] = []string{p.Updated} pb, _ := yaml.Marshal(p.Parameters) content := fmt.Sprintf("---\n%s---\n%s", string(pb), p.Content) return µformatItem{ @@ -185,8 +187,7 @@ func serveMicropubPost(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } - w.Header().Add("Location", p.fullURL()) - w.WriteHeader(http.StatusAccepted) + http.Redirect(w, r, p.fullURL(), http.StatusAccepted) return } @@ -424,7 +425,7 @@ func micropubDelete(w http.ResponseWriter, r *http.Request, u *url.URL) { http.Error(w, err.Error(), http.StatusBadRequest) return } - w.WriteHeader(http.StatusNoContent) + http.Redirect(w, r, u.String(), http.StatusNoContent) return } @@ -557,4 +558,5 @@ func micropubUpdate(w http.ResponseWriter, r *http.Request, u *url.URL, mf *micr http.Error(w, err.Error(), http.StatusInternalServerError) return } + http.Redirect(w, r, p.fullURL(), http.StatusNoContent) } diff --git a/postsDb.go b/postsDb.go index 84fab05..cacef44 100644 --- a/postsDb.go +++ b/postsDb.go @@ -56,6 +56,13 @@ func (p *post) checkPost() error { if p.Blog == "" { p.Blog = appConfig.DefaultBlog } + if _, ok := appConfig.Blogs[p.Blog]; !ok { + return errors.New("blog doesn't exist") + } + // Check if section exists + if _, ok := appConfig.Blogs[p.Blog].Sections[p.Section]; p.Section != "" && !ok { + return errors.New("section doesn't exist") + } // Check path p.Path = strings.TrimSuffix(p.Path, "/") if p.Path == "" { diff --git a/render.go b/render.go index 511a714..bf903aa 100644 --- a/render.go +++ b/render.go @@ -30,6 +30,7 @@ const templateTaxonomy = "taxonomy" const templateSearch = "search" const templateSummary = "summary" const templatePhotosSummary = "photosummary" +const templateEditor = "editor" var templates map[string]*template.Template var templateFunctions template.FuncMap @@ -229,6 +230,9 @@ func render(w http.ResponseWriter, template string, data *renderData) { } data.Blog = appConfig.Blogs[data.blogString] } + if data.Data == nil { + data.Data = map[string]interface{}{} + } // We need to use a buffer here to enable minification var buffer bytes.Buffer err := templates[template].ExecuteTemplate(&buffer, template, data) diff --git a/templates/editor.gohtml b/templates/editor.gohtml new file mode 100644 index 0000000..85ea3f8 --- /dev/null +++ b/templates/editor.gohtml @@ -0,0 +1,37 @@ +{{ define "title" }} + {{ string .Blog.Lang "editor" }} - {{ .Blog.Title }} +{{ end }} + +{{ define "main" }} +
+

{{ string .Blog.Lang "editor" }}

+

{{ string .Blog.Lang "create" }}

+
+ + + +
+

{{ string .Blog.Lang "update" }}

+
+ {{ if .Data.UpdatePostURL }} + + + + {{ else }} + + + {{ end }} + +
+

{{ string .Blog.Lang "delete" }}

+
+ + + +
+
+{{ end }} + +{{ define "editor" }} + {{ template "base" . }} +{{ end }} \ No newline at end of file diff --git a/templates/strings/default.yaml b/templates/strings/default.yaml index 049e588..8b06520 100644 --- a/templates/strings/default.yaml +++ b/templates/strings/default.yaml @@ -22,4 +22,7 @@ anoncomment: "You can also create an anonymous comment." interactions: "Interactions" send: "Send" interactionslabel: "Have you published a response to this? Paste the URL here." -search: "Search" \ No newline at end of file +search: "Search" +editor: "Editor" +create: "Create" +update: "Update" \ No newline at end of file