implemented draft publishing and removed New Posts link/capability
This commit is contained in:
parent
33a81f73e1
commit
f365b09757
@ -202,7 +202,7 @@ func (a *api) blogHandler() http.Handler {
|
|||||||
mux.Handle("/posts/", http.StripPrefix("/posts",
|
mux.Handle("/posts/", http.StripPrefix("/posts",
|
||||||
apiutil.MethodMux(map[string]http.Handler{
|
apiutil.MethodMux(map[string]http.Handler{
|
||||||
"GET": a.renderPostHandler(),
|
"GET": a.renderPostHandler(),
|
||||||
"POST": a.postPostHandler(false),
|
"POST": a.postPostHandler(),
|
||||||
"DELETE": a.deletePostHandler(false),
|
"DELETE": a.deletePostHandler(false),
|
||||||
"PREVIEW": a.previewPostHandler(),
|
"PREVIEW": a.previewPostHandler(),
|
||||||
}),
|
}),
|
||||||
@ -223,7 +223,7 @@ func (a *api) blogHandler() http.Handler {
|
|||||||
|
|
||||||
apiutil.MethodMux(map[string]http.Handler{
|
apiutil.MethodMux(map[string]http.Handler{
|
||||||
"GET": a.renderDraftPostHandler(),
|
"GET": a.renderDraftPostHandler(),
|
||||||
"POST": a.postPostHandler(true),
|
"POST": a.postDraftPostHandler(),
|
||||||
"DELETE": a.deletePostHandler(true),
|
"DELETE": a.deletePostHandler(true),
|
||||||
"PREVIEW": a.previewPostHandler(),
|
"PREVIEW": a.previewPostHandler(),
|
||||||
}),
|
}),
|
||||||
|
@ -108,3 +108,23 @@ func (a *api) renderDraftPostsIndexHandler() http.Handler {
|
|||||||
executeTemplate(rw, r, tpl, tplPayload)
|
executeTemplate(rw, r, tpl, tplPayload)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *api) postDraftPostHandler() http.Handler {
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
p, err := postFromPostReq(r)
|
||||||
|
if err != nil {
|
||||||
|
apiutil.BadRequest(rw, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.params.PostDraftStore.Set(p); err != nil {
|
||||||
|
apiutil.InternalServerError(
|
||||||
|
rw, r, fmt.Errorf("storing post with id %q: %w", p.ID, err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.executeRedirectTpl(rw, r, a.draftURL(p.ID, false)+"?edit")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
@ -16,6 +17,7 @@ import (
|
|||||||
"github.com/gomarkdown/markdown/parser"
|
"github.com/gomarkdown/markdown/parser"
|
||||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
|
"github.com/mediocregopher/blog.mediocregopher.com/srv/http/apiutil"
|
||||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/post"
|
"github.com/mediocregopher/blog.mediocregopher.com/srv/post"
|
||||||
|
"github.com/mediocregopher/mediocre-go-lib/v2/mctx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *api) parsePostBody(post post.Post) (*txttpl.Template, error) {
|
func (a *api) parsePostBody(post post.Post) (*txttpl.Template, error) {
|
||||||
@ -248,6 +250,10 @@ func (a *api) renderEditPostHandler(isDraft bool) http.Handler {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if !isDraft {
|
||||||
|
http.Error(rw, "Post ID required in URL", 400)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags, err := a.params.PostStore.GetTags()
|
tags, err := a.params.PostStore.GetTags()
|
||||||
@ -296,49 +302,54 @@ func postFromPostReq(r *http.Request) (post.Post, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *api) postPostHandler(isDraft bool) http.Handler {
|
func (a *api) storeAndPublishPost(ctx context.Context, p post.Post) error {
|
||||||
|
|
||||||
|
first, err := a.params.PostStore.Set(p, time.Now())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("storing post with id %q: %w", p.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !first {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
a.params.Logger.Info(ctx, "publishing blog post to mailing list")
|
||||||
|
urlStr := a.postURL(p.ID, true)
|
||||||
|
|
||||||
|
if err := a.params.MailingList.Publish(p.Title, urlStr); err != nil {
|
||||||
|
return fmt.Errorf("publishing post to mailing list: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.params.PostDraftStore.Delete(p.ID); err != nil {
|
||||||
|
return fmt.Errorf("deleting draft: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *api) postPostHandler() http.Handler {
|
||||||
|
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
p, err := postFromPostReq(r)
|
p, err := postFromPostReq(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiutil.BadRequest(rw, r, err)
|
apiutil.BadRequest(rw, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var first bool
|
ctx = mctx.Annotate(ctx, "postID", p.ID)
|
||||||
|
|
||||||
if isDraft {
|
if err := a.storeAndPublishPost(ctx, p); err != nil {
|
||||||
err = a.params.PostDraftStore.Set(p)
|
|
||||||
} else {
|
|
||||||
first, err = a.params.PostStore.Set(p, time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
apiutil.InternalServerError(
|
apiutil.InternalServerError(
|
||||||
rw, r, fmt.Errorf("storing post with id %q: %w", p.ID, err),
|
rw, r, fmt.Errorf("storing/publishing post with id %q: %w", p.ID, err),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isDraft && first {
|
a.executeRedirectTpl(rw, r, a.postURL(p.ID, false))
|
||||||
|
|
||||||
a.params.Logger.Info(r.Context(), "publishing blog post to mailing list")
|
|
||||||
urlStr := a.postURL(p.ID, true)
|
|
||||||
|
|
||||||
if err := a.params.MailingList.Publish(p.Title, urlStr); err != nil {
|
|
||||||
apiutil.InternalServerError(
|
|
||||||
rw, r, fmt.Errorf("publishing post with id %q: %w", p.ID, err),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDraft {
|
|
||||||
a.executeRedirectTpl(rw, r, a.draftURL(p.ID, false)+"?edit")
|
|
||||||
} else {
|
|
||||||
a.executeRedirectTpl(rw, r, a.postURL(p.ID, false)+"?edit")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="submit"
|
type="submit"
|
||||||
value="Preview"
|
value="Preview"
|
||||||
@ -99,8 +100,23 @@
|
|||||||
|
|
||||||
{{ if .Payload.IsDraft }}
|
{{ if .Payload.IsDraft }}
|
||||||
<input type="submit" value="Save" formaction="{{ BlogURL "drafts/" }}" />
|
<input type="submit" value="Save" formaction="{{ BlogURL "drafts/" }}" />
|
||||||
{{ else if eq .Payload.Post.ID "" }}
|
|
||||||
<input type="submit" value="Publish" formaction="{{ BlogURL "posts/" }}" />
|
|
||||||
|
<script>
|
||||||
|
function confirmPublish(event) {
|
||||||
|
if (!confirm("Are you sure you're ready to publish?"))
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value="Publish"
|
||||||
|
formaction="{{ BlogURL "posts/" }}"
|
||||||
|
onclick="confirmPublish(event)"
|
||||||
|
/>
|
||||||
|
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<input type="submit" value="Update" formaction="{{ BlogURL "posts/" }}" />
|
<input type="submit" value="Update" formaction="{{ BlogURL "posts/" }}" />
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
<h1>Posts</h1>
|
<h1>Posts</h1>
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="{{ BlogURL "posts/" }}?edit">
|
|
||||||
New Post
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{{ if ge .Payload.PrevPage 0 }}
|
{{ if ge .Payload.PrevPage 0 }}
|
||||||
<p>
|
<p>
|
||||||
<a href="?p={{ .Payload.PrevPage}}">< < Previous Page</a>
|
<a href="?p={{ .Payload.PrevPage}}">< < Previous Page</a>
|
||||||
|
Loading…
Reference in New Issue
Block a user