mirror of https://github.com/jlelse/GoBlog
One editor per blog
This commit is contained in:
parent
f3744227e1
commit
89b48b1d37
|
@ -38,7 +38,7 @@ func serveBlogStats(blog, statsPath string) func(w http.ResponseWriter, r *http.
|
|||
counts = append(counts, count)
|
||||
}
|
||||
render(w, templateBlogStats, &renderData{
|
||||
blogString: blog,
|
||||
BlogString: blog,
|
||||
Canonical: statsPath,
|
||||
Data: map[string]interface{}{
|
||||
"total": totalCount,
|
||||
|
|
132
editor.go
132
editor.go
|
@ -10,72 +10,78 @@ import (
|
|||
|
||||
const editorPath = "/editor"
|
||||
|
||||
func serveEditor(w http.ResponseWriter, _ *http.Request) {
|
||||
render(w, templateEditor, &renderData{
|
||||
Data: map[string]interface{}{
|
||||
"Drafts": loadDrafts(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func serveEditorPost(w http.ResponseWriter, r *http.Request) {
|
||||
if action := r.FormValue("editoraction"); action != "" {
|
||||
switch action {
|
||||
case "loadupdate":
|
||||
parsedURL, err := url.Parse(r.FormValue("url"))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
post, err := getPost(parsedURL.Path)
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
mf := post.toMfItem()
|
||||
render(w, templateEditor, &renderData{
|
||||
Data: map[string]interface{}{
|
||||
"UpdatePostURL": parsedURL.String(),
|
||||
"UpdatePostContent": mf.Properties.Content[0],
|
||||
"Drafts": loadDrafts(),
|
||||
},
|
||||
})
|
||||
case "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 {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, "", bytes.NewReader(jsonBytes))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
req.Header.Set(contentType, contentTypeJSON)
|
||||
editorMicropubPost(w, req, false)
|
||||
case "upload":
|
||||
editorMicropubPost(w, r, true)
|
||||
default:
|
||||
serveError(w, r, "Unknown editoraction", http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
func serveEditor(blog string) func(w http.ResponseWriter, _ *http.Request) {
|
||||
return func(w http.ResponseWriter, _ *http.Request) {
|
||||
render(w, templateEditor, &renderData{
|
||||
BlogString: blog,
|
||||
Data: map[string]interface{}{
|
||||
"Drafts": loadDrafts(blog),
|
||||
},
|
||||
})
|
||||
}
|
||||
editorMicropubPost(w, r, false)
|
||||
}
|
||||
|
||||
func loadDrafts() []*post {
|
||||
ps, _ := getPosts(&postsRequestConfig{status: statusDraft})
|
||||
func serveEditorPost(blog string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if action := r.FormValue("editoraction"); action != "" {
|
||||
switch action {
|
||||
case "loadupdate":
|
||||
parsedURL, err := url.Parse(r.FormValue("url"))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
post, err := getPost(parsedURL.Path)
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
mf := post.toMfItem()
|
||||
render(w, templateEditor, &renderData{
|
||||
BlogString: blog,
|
||||
Data: map[string]interface{}{
|
||||
"UpdatePostURL": parsedURL.String(),
|
||||
"UpdatePostContent": mf.Properties.Content[0],
|
||||
"Drafts": loadDrafts(blog),
|
||||
},
|
||||
})
|
||||
case "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 {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, "", bytes.NewReader(jsonBytes))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
req.Header.Set(contentType, contentTypeJSON)
|
||||
editorMicropubPost(w, req, false)
|
||||
case "upload":
|
||||
editorMicropubPost(w, r, true)
|
||||
default:
|
||||
serveError(w, r, "Unknown editoraction", http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
editorMicropubPost(w, r, false)
|
||||
}
|
||||
}
|
||||
|
||||
func loadDrafts(blog string) []*post {
|
||||
ps, _ := getPosts(&postsRequestConfig{status: statusDraft, blog: blog})
|
||||
return ps
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -62,7 +62,7 @@ require (
|
|||
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
|
||||
golang.org/x/text v0.3.5 // indirect
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963 // indirect
|
||||
golang.org/x/tools v0.0.0-20210115202250-e0d201561e39 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -497,8 +497,8 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnf
|
|||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200609164405-eb789aa7ce50/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963 h1:K+NlvTLy0oONtRtkl1jRD9xIhnItbG2PiE7YOdjPb+k=
|
||||
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210115202250-e0d201561e39 h1:BTs2GMGSMWpgtCpv1CE7vkJTv7XcHdcLLnAMu7UbgTY=
|
||||
golang.org/x/tools v0.0.0-20210115202250-e0d201561e39/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
|
|
14
http.go
14
http.go
|
@ -106,13 +106,6 @@ func buildHandler() (http.Handler, error) {
|
|||
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia)
|
||||
})
|
||||
|
||||
// Editor
|
||||
r.Route("/editor", func(mpRouter chi.Router) {
|
||||
mpRouter.Use(middleware.NoCache, minifier.Middleware, authMiddleware)
|
||||
mpRouter.Get("/", serveEditor)
|
||||
mpRouter.Post("/", serveEditorPost)
|
||||
})
|
||||
|
||||
// IndieAuth
|
||||
r.Route("/indieauth", func(indieauthRouter chi.Router) {
|
||||
indieauthRouter.Use(middleware.NoCache, minifier.Middleware)
|
||||
|
@ -325,6 +318,13 @@ func buildHandler() (http.Handler, error) {
|
|||
r.With(minifier.Middleware).Get(cp.Path, handler)
|
||||
}
|
||||
}
|
||||
|
||||
// Editor
|
||||
r.Route(blogPath+"/editor", func(mpRouter chi.Router) {
|
||||
mpRouter.Use(middleware.NoCache, minifier.Middleware, authMiddleware)
|
||||
mpRouter.Get("/", serveEditor(blog))
|
||||
mpRouter.Post("/", serveEditorPost(blog))
|
||||
})
|
||||
}
|
||||
|
||||
// Sitemap
|
||||
|
|
4
posts.go
4
posts.go
|
@ -67,7 +67,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
w.Header().Add("Link", fmt.Sprintf("<%s>; rel=shortlink", p.shortURL()))
|
||||
render(w, template, &renderData{
|
||||
blogString: p.Blog,
|
||||
BlogString: p.Blog,
|
||||
Canonical: canonical,
|
||||
Data: p,
|
||||
})
|
||||
|
@ -279,7 +279,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
|
|||
summaryTemplate = templateSummary
|
||||
}
|
||||
render(w, templateIndex, &renderData{
|
||||
blogString: ic.blog,
|
||||
BlogString: ic.blog,
|
||||
Canonical: appConfig.Server.PublicAddress + path,
|
||||
Data: map[string]interface{}{
|
||||
"Title": title,
|
||||
|
|
16
render.go
16
render.go
|
@ -222,7 +222,7 @@ func initRendering() error {
|
|||
}
|
||||
|
||||
type renderData struct {
|
||||
blogString string
|
||||
BlogString string
|
||||
Canonical string
|
||||
Blog *configBlog
|
||||
Data interface{}
|
||||
|
@ -231,10 +231,18 @@ type renderData struct {
|
|||
func render(w http.ResponseWriter, template string, data *renderData) {
|
||||
// Check render data
|
||||
if data.Blog == nil {
|
||||
if len(data.blogString) == 0 {
|
||||
data.blogString = appConfig.DefaultBlog
|
||||
if len(data.BlogString) == 0 {
|
||||
data.BlogString = appConfig.DefaultBlog
|
||||
}
|
||||
data.Blog = appConfig.Blogs[data.BlogString]
|
||||
}
|
||||
if data.BlogString == "" {
|
||||
for s, b := range appConfig.Blogs {
|
||||
if b == data.Blog {
|
||||
data.BlogString = s
|
||||
break
|
||||
}
|
||||
}
|
||||
data.Blog = appConfig.Blogs[data.blogString]
|
||||
}
|
||||
if data.Data == nil {
|
||||
data.Data = map[string]interface{}{}
|
||||
|
|
|
@ -21,7 +21,7 @@ func serveSearch(blog string, path string) func(w http.ResponseWriter, r *http.R
|
|||
return
|
||||
}
|
||||
render(w, templateSearch, &renderData{
|
||||
blogString: blog,
|
||||
BlogString: blog,
|
||||
Canonical: appConfig.Server.PublicAddress + path,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ func serveTaxonomy(blog string, tax *taxonomy) func(w http.ResponseWriter, r *ht
|
|||
return
|
||||
}
|
||||
render(w, templateTaxonomy, &renderData{
|
||||
blogString: blog,
|
||||
BlogString: blog,
|
||||
Canonical: appConfig.Server.PublicAddress + r.URL.Path,
|
||||
Data: map[string]interface{}{
|
||||
"Taxonomy": tax,
|
||||
|
|
|
@ -9,10 +9,13 @@
|
|||
<form class="fw-form p" method="post">
|
||||
<input type="hidden" name="h" value="entry">
|
||||
<textarea name="content" class="monospace h400p">---
|
||||
title:
|
||||
status: draft
|
||||
blog: {{ .BlogString }}
|
||||
section:
|
||||
slug:
|
||||
blog:
|
||||
title:
|
||||
tags:
|
||||
-
|
||||
---
|
||||
</textarea>
|
||||
<input class="fw" type="submit" value="{{ string .Blog.Lang "create" }}">
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
publishedon: "Veröffentlicht am"
|
||||
updatedon: "Aktualisiert am"
|
||||
next: "Weiter"
|
||||
prev: "Zurück"
|
||||
view: "Anschauen"
|
||||
replyto: "Antwort an"
|
||||
anoncomment: "Du kannst auch einen anonymen Kommentar verfassen."
|
||||
count: "Anzahl"
|
||||
create: "Erstellen"
|
||||
delete: "Löschen"
|
||||
drafts: "Entwürfe"
|
||||
editor: "Editor"
|
||||
interactions: "Interaktionen & Kommentare"
|
||||
interactionslabel: "Hast du eine Antwort hierzu veröffentlicht? Füge hier die URL ein."
|
||||
likeof: "Gefällt mir von"
|
||||
translations: "Übersetzungen"
|
||||
next: "Weiter"
|
||||
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
||||
prev: "Zurück"
|
||||
publishedon: "Veröffentlicht am"
|
||||
replyto: "Antwort an"
|
||||
search: "Suchen"
|
||||
send: "Senden (zur Überprüfung)"
|
||||
share: "Teilen"
|
||||
shorturl: "Kurz-Link:"
|
||||
speak: "Lies mir bitte vor."
|
||||
stopspeak: "Hör auf zu sprechen!"
|
||||
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
||||
search: "Suchen"
|
||||
shorturl: "Kurz-URL:"
|
||||
year: "Jahr"
|
||||
count: "Anzahl"
|
||||
total: "Gesamt"
|
||||
anoncomment: "Du kannst auch einen anonymen Kommentar verfassen."
|
||||
interactions: "Interaktionen & Kommentare"
|
||||
send: "Senden (zur Überprüfung)"
|
||||
interactionslabel: "Hast du eine Antwort hierzu veröffentlicht? Füge hier die URL ein."
|
||||
translations: "Übersetzungen"
|
||||
update: "Aktualisieren"
|
||||
updatedon: "Aktualisiert am"
|
||||
upload: "Hochladen"
|
||||
view: "Anschauen"
|
||||
year: "Jahr"
|
|
@ -1,37 +1,37 @@
|
|||
publishedon: "Published on"
|
||||
updatedon: "Updated on"
|
||||
next: "Next"
|
||||
prev: "Previous"
|
||||
view: "View"
|
||||
anoncomment: "You can also create an anonymous comment."
|
||||
approve: "Approve"
|
||||
approved: "Approved"
|
||||
authenticate: "Authenticate"
|
||||
scopes: "Scopes"
|
||||
count: "Count"
|
||||
create: "Create"
|
||||
delete: "Delete"
|
||||
drafts: "Drafts"
|
||||
editor: "Editor"
|
||||
indieauth: "IndieAuth"
|
||||
replyto: "Reply to"
|
||||
interactions: "Interactions & Comments"
|
||||
interactionslabel: "Have you published a response to this? Paste the URL here."
|
||||
likeof: "Like of"
|
||||
translations: "Translations"
|
||||
login: "Login"
|
||||
next: "Next"
|
||||
oldcontent: "⚠️ This entry is already over one year old. It may no longer be up to date. Opinions may have changed."
|
||||
password: "Password"
|
||||
prev: "Previous"
|
||||
publishedon: "Published on"
|
||||
replyto: "Reply to"
|
||||
scopes: "Scopes"
|
||||
search: "Search"
|
||||
send: "Send (to review)"
|
||||
share: "Share"
|
||||
shorturl: "Short link:"
|
||||
speak: "Read to me, please."
|
||||
stopspeak: "Stop speaking!"
|
||||
oldcontent: "⚠️ This entry is already over one year old. It may no longer be up to date. Opinions may have changed."
|
||||
webmentions: "Webmentions"
|
||||
verified: "Verified"
|
||||
approved: "Approved"
|
||||
delete: "Delete"
|
||||
approve: "Approve"
|
||||
anoncomment: "You can also create an anonymous comment."
|
||||
interactions: "Interactions & Comments"
|
||||
send: "Send (to review)"
|
||||
interactionslabel: "Have you published a response to this? Paste the URL here."
|
||||
search: "Search"
|
||||
editor: "Editor"
|
||||
create: "Create"
|
||||
update: "Update"
|
||||
upload: "Upload"
|
||||
login: "Login"
|
||||
username: "Username"
|
||||
password: "Password"
|
||||
shorturl: "Short URL:"
|
||||
year: "Year"
|
||||
count: "Count"
|
||||
total: "Total"
|
||||
drafts: "Drafts"
|
||||
translations: "Translations"
|
||||
update: "Update"
|
||||
updatedon: "Updated on"
|
||||
upload: "Upload"
|
||||
username: "Username"
|
||||
verified: "Verified"
|
||||
view: "View"
|
||||
webmentions: "Webmentions"
|
||||
year: "Year"
|
Loading…
Reference in New Issue