Implement edit post page
This commit is contained in:
parent
0bc0204f0b
commit
75044eef03
@ -215,6 +215,7 @@ func (a *api) handler() http.Handler {
|
|||||||
v2Mux.Handle("/posts/", http.StripPrefix("/posts",
|
v2Mux.Handle("/posts/", http.StripPrefix("/posts",
|
||||||
apiutil.MethodMux(map[string]http.Handler{
|
apiutil.MethodMux(map[string]http.Handler{
|
||||||
"GET": a.renderPostHandler(),
|
"GET": a.renderPostHandler(),
|
||||||
|
"EDIT": a.editPostHandler(),
|
||||||
"DELETE": authMiddleware(auther,
|
"DELETE": authMiddleware(auther,
|
||||||
formMiddleware(a.deletePostHandler()),
|
formMiddleware(a.deletePostHandler()),
|
||||||
),
|
),
|
||||||
|
@ -149,7 +149,7 @@ func (a *api) postPostAssetHandler() http.Handler {
|
|||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
id := r.PostFormValue("id")
|
id := r.PostFormValue("id")
|
||||||
if id == "" {
|
if id == "/" {
|
||||||
apiutil.BadRequest(rw, r, errors.New("id is required"))
|
apiutil.BadRequest(rw, r, errors.New("id is required"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -176,7 +176,7 @@ func (a *api) deletePostAssetHandler() http.Handler {
|
|||||||
|
|
||||||
id := filepath.Base(r.URL.Path)
|
id := filepath.Base(r.URL.Path)
|
||||||
|
|
||||||
if id == "" {
|
if id == "/" {
|
||||||
apiutil.BadRequest(rw, r, errors.New("id is required"))
|
apiutil.BadRequest(rw, r, errors.New("id is required"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -138,13 +138,43 @@ func (a *api) renderPostsIndexHandler() http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *api) editPostHandler() http.Handler {
|
||||||
|
|
||||||
|
tpl := a.mustParseBasedTpl("edit-post.html")
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
id := filepath.Base(r.URL.Path)
|
||||||
|
|
||||||
|
var storedPost post.StoredPost
|
||||||
|
|
||||||
|
if id != "/" {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
storedPost, err = a.params.PostStore.GetByID(id)
|
||||||
|
|
||||||
|
if errors.Is(err, post.ErrPostNotFound) {
|
||||||
|
http.Error(rw, "Post not found", 404)
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
apiutil.InternalServerError(
|
||||||
|
rw, r, fmt.Errorf("fetching post with id %q: %w", id, err),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
executeTemplate(rw, r, tpl, storedPost)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (a *api) deletePostHandler() http.Handler {
|
func (a *api) deletePostHandler() http.Handler {
|
||||||
|
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
id := filepath.Base(r.URL.Path)
|
id := filepath.Base(r.URL.Path)
|
||||||
|
|
||||||
if id == "" {
|
if id == "/" {
|
||||||
apiutil.BadRequest(rw, r, errors.New("id is required"))
|
apiutil.BadRequest(rw, r, errors.New("id is required"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/api/apiutil"
|
"github.com/mediocregopher/blog.mediocregopher.com/srv/api/apiutil"
|
||||||
)
|
)
|
||||||
@ -50,6 +51,9 @@ func (a *api) mustParseTpl(name string) *template.Template {
|
|||||||
path := filepath.Join("posts", id)
|
path := filepath.Join("posts", id)
|
||||||
return blogURL(path)
|
return blogURL(path)
|
||||||
},
|
},
|
||||||
|
"DateTimeFormat": func(t time.Time) string {
|
||||||
|
return t.Format("2006-01-02")
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
tpl = template.Must(tpl.Parse(mustReadTplFile(name)))
|
tpl = template.Must(tpl.Parse(mustReadTplFile(name)))
|
||||||
|
82
srv/src/api/tpl/edit-post.html
Normal file
82
srv/src/api/tpl/edit-post.html
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{{ define "body" }}
|
||||||
|
|
||||||
|
<form method="POST" action="{{ BlogURL "posts/" }}">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="columns six">
|
||||||
|
<label for="idInput">Unique ID (e.g. "how-to-fly-a-kite")</label>
|
||||||
|
<input
|
||||||
|
id="idInput"
|
||||||
|
name="id"
|
||||||
|
class="u-full-width"
|
||||||
|
type="text"
|
||||||
|
value="{{ .Payload.ID }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="columns three">
|
||||||
|
<label for="tagsInput">Tags (space separated)</label>
|
||||||
|
<input
|
||||||
|
id="tagsInput"
|
||||||
|
name="tags"
|
||||||
|
class="u-full-width"
|
||||||
|
type="text"
|
||||||
|
value="{{ range $i, $tag := .Payload.Tags }}{{ if ne $i 0 }} {{ end }}{{ $tag }}{{ end }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="columns three">
|
||||||
|
<label for="seriesInput">Series</label>
|
||||||
|
<input
|
||||||
|
id="seriesInput"
|
||||||
|
name="series"
|
||||||
|
class="u-full-width"
|
||||||
|
type="text"
|
||||||
|
value="{{ .Payload.Series }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="columns six">
|
||||||
|
<label for="titleInput">Title</label>
|
||||||
|
<input
|
||||||
|
id="titleInput"
|
||||||
|
name="title"
|
||||||
|
class="u-full-width"
|
||||||
|
type="text"
|
||||||
|
value="{{ .Payload.Title }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="columns six">
|
||||||
|
<label for="descrInput">Description</label>
|
||||||
|
<input
|
||||||
|
id="descrInput"
|
||||||
|
name="description"
|
||||||
|
class="u-full-width"
|
||||||
|
type="text"
|
||||||
|
value="{{ .Payload.Description }}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="columns twelve">
|
||||||
|
<textarea
|
||||||
|
name="body"
|
||||||
|
class="u-full-width"
|
||||||
|
placeholder="Blog body"
|
||||||
|
style="height: 50vh;"
|
||||||
|
>
|
||||||
|
{{ .Payload.Body }}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="submit" value="Save" />
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ template "base.html" . }}
|
@ -7,9 +7,9 @@
|
|||||||
<h2>
|
<h2>
|
||||||
<a href="{{ PostURL .ID }}">{{ .Title }}</a>
|
<a href="{{ PostURL .ID }}">{{ .Title }}</a>
|
||||||
</h2>
|
</h2>
|
||||||
<span>{{ .PublishedAt.Format "2006-01-02" }}</span>
|
<span>{{ DateTimeFormat .PublishedAt }}</span>
|
||||||
{{ if not .LastUpdatedAt.IsZero }}
|
{{ if not .LastUpdatedAt.IsZero }}
|
||||||
<span>(Updated {{ .LastUpdatedAt.Format "2006-01-02" }})</span>
|
<span>(Updated {{ DateTimeFormat .LastUpdatedAt }})</span>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<p>{{ .Description }}</p>
|
<p>{{ .Description }}</p>
|
||||||
</li>
|
</li>
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
{{ .Payload.Title }}
|
{{ .Payload.Title }}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="light">
|
<div class="light">
|
||||||
{{ .Payload.PublishedAt.Format "2006-01-02" }}
|
{{ DateTimeFormat .Payload.PublishedAt }}
|
||||||
•
|
•
|
||||||
{{ if not .Payload.LastUpdatedAt.IsZero }}
|
{{ if not .Payload.LastUpdatedAt.IsZero }}
|
||||||
(Updated {{ .Payload.LastUpdatedAt.Format "2006-01-02" }})
|
(Updated {{ DateTimeFormat .Payload.LastUpdatedAt }})
|
||||||
•
|
•
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<em>{{ .Payload.Description }}</em>
|
<em>{{ .Payload.Description }}</em>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<p style="text-align: center;">
|
<p style="text-align: center;">
|
||||||
<a href="{{ BlogURL "posts/" }}?method=new">
|
<a href="{{ BlogURL "posts/" }}?method=edit">
|
||||||
<button>New Post</button>
|
<button>New Post</button>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
Loading…
Reference in New Issue
Block a user