diff options
-rw-r--r-- | src/gmi/tpl.go | 2 | ||||
-rw-r--r-- | src/http/assets.go | 20 | ||||
-rw-r--r-- | src/http/drafts.go | 40 | ||||
-rw-r--r-- | src/http/posts.go | 167 | ||||
-rw-r--r-- | src/http/tpl.go | 2 | ||||
-rw-r--r-- | src/http/tpl/draft-posts-manage.html | 26 | ||||
-rw-r--r-- | src/http/tpl/post-assets-manage.html | 6 | ||||
-rw-r--r-- | src/http/tpl/post-edit.html | 34 | ||||
-rw-r--r-- | src/http/tpl/posts-manage.html | 14 | ||||
-rw-r--r-- | src/http/tpl/posts.html | 15 | ||||
-rw-r--r-- | src/render/methods.go | 51 |
11 files changed, 121 insertions, 256 deletions
diff --git a/src/gmi/tpl.go b/src/gmi/tpl.go index 8ffa6bc..f6c1754 100644 --- a/src/gmi/tpl.go +++ b/src/gmi/tpl.go @@ -177,6 +177,8 @@ func (a *api) tplHandler() (gemini.Handler, error) { a.params.PublicURL, a.params.HTTPGeminiGatewayURL, a.params.PostStore, + nil, // asset.Store, not supported by gemini endpoint + nil, // post.DraftStore, not supported by gemini endpoint preprocessFuncs, )) diff --git a/src/http/assets.go b/src/http/assets.go index 5a47152..8c5ac7e 100644 --- a/src/http/assets.go +++ b/src/http/assets.go @@ -14,27 +14,9 @@ import ( ) func (a *api) managePostAssetsHandler() http.Handler { - tpl := a.mustParseBasedTpl("post-assets-manage.html") - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - ids, err := a.params.PostAssetStore.List() - - if err != nil { - apiutil.InternalServerError( - rw, r, fmt.Errorf("getting list of asset ids: %w", err), - ) - return - } - - tplPayload := struct { - IDs []string - }{ - IDs: ids, - } - - a.executeTemplate(rw, r, tpl, tplPayload) + a.executeTemplate(rw, r, tpl, nil) }) } diff --git a/src/http/drafts.go b/src/http/drafts.go index b0550ce..8f17eec 100644 --- a/src/http/drafts.go +++ b/src/http/drafts.go @@ -5,50 +5,12 @@ import ( "net/http" "dev.mediocregopher.com/mediocre-blog.git/src/http/apiutil" - "dev.mediocregopher.com/mediocre-blog.git/src/post" ) func (a *api) manageDraftPostsHandler() http.Handler { - tpl := a.mustParseBasedTpl("draft-posts-manage.html") - const pageCount = 20 - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - page, err := apiutil.StrToInt(r.FormValue("p"), 0) - if err != nil { - apiutil.BadRequest( - rw, r, fmt.Errorf("invalid page number: %w", err), - ) - return - } - - posts, hasMore, err := a.params.PostDraftStore.Get(page, pageCount) - if err != nil { - apiutil.InternalServerError( - rw, r, fmt.Errorf("fetching page %d of posts: %w", page, err), - ) - return - } - - tplPayload := struct { - Posts []post.Post - PrevPage, NextPage int - }{ - Posts: posts, - PrevPage: -1, - NextPage: -1, - } - - if page > 0 { - tplPayload.PrevPage = page - 1 - } - - if hasMore { - tplPayload.NextPage = page + 1 - } - - a.executeTemplate(rw, r, tpl, tplPayload) + a.executeTemplate(rw, r, tpl, nil) }) } diff --git a/src/http/posts.go b/src/http/posts.go index 939b811..14224f2 100644 --- a/src/http/posts.go +++ b/src/http/posts.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - "html/template" "net/http" "path/filepath" "strings" @@ -58,12 +57,6 @@ func (a *api) postPreprocessFuncImage(args ...string) (string, error) { return buf.String(), nil } -type postTplPayload struct { - post.StoredPost - SeriesPrevious, SeriesNext *post.StoredPost - Body template.HTML -} - func (a *api) postPreprocessFuncs() post.PreprocessFunctions { return post.PreprocessFunctions{ BlogURL: func(path string) string { @@ -90,76 +83,17 @@ func (a *api) postPreprocessFuncs() post.PreprocessFunctions { } func (a *api) getPostsHandler() http.Handler { - - tpl := a.mustParseBasedTpl("posts.html") - getPostHandler := a.getPostHandler() - const pageCount = 20 + var ( + tpl = a.mustParseBasedTpl("posts.html") + getPostHandler = a.getPostHandler() + ) return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - id := filepath.Base(r.URL.Path) - - if id != "/" { + if id := filepath.Base(r.URL.Path); id != "/" { getPostHandler.ServeHTTP(rw, r) return } - - page, err := apiutil.StrToInt(r.FormValue("p"), 0) - if err != nil { - apiutil.BadRequest( - rw, r, fmt.Errorf("invalid page number: %w", err), - ) - return - } - - tag := r.FormValue("tag") - - var ( - posts []post.StoredPost - hasMore bool - ) - - if tag == "" { - posts, hasMore, err = a.params.PostStore.Get(page, pageCount) - } else { - posts, err = a.params.PostStore.GetByTag(tag) - } - - if err != nil { - apiutil.InternalServerError( - rw, r, fmt.Errorf("fetching page %d of posts: %w", page, err), - ) - return - } - - tags, err := a.params.PostStore.GetTags() - if err != nil { - apiutil.InternalServerError( - rw, r, fmt.Errorf("fething tags: %w", err), - ) - return - } - - tplPayload := struct { - Posts []post.StoredPost - PrevPage, NextPage int - Tags []string - }{ - Posts: posts, - PrevPage: -1, - NextPage: -1, - Tags: tags, - } - - if page > 0 { - tplPayload.PrevPage = page - 1 - } - - if hasMore { - tplPayload.NextPage = page + 1 - } - - a.executeTemplate(rw, r, tpl, tplPayload) + a.executeTemplate(rw, r, tpl, nil) }) } @@ -173,105 +107,22 @@ func (a *api) getPostHandler() http.Handler { } func (a *api) managePostsHandler() http.Handler { - tpl := a.mustParseBasedTpl("posts-manage.html") - const pageCount = 20 - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - page, err := apiutil.StrToInt(r.FormValue("p"), 0) - if err != nil { - apiutil.BadRequest( - rw, r, fmt.Errorf("invalid page number: %w", err), - ) - return - } - - posts, hasMore, err := a.params.PostStore.Get(page, pageCount) - if err != nil { - apiutil.InternalServerError( - rw, r, fmt.Errorf("fetching page %d of posts: %w", page, err), - ) - return - } - - tplPayload := struct { - Posts []post.StoredPost - PrevPage, NextPage int - }{ - Posts: posts, - PrevPage: -1, - NextPage: -1, - } - - if page > 0 { - tplPayload.PrevPage = page - 1 - } - - if hasMore { - tplPayload.NextPage = page + 1 - } - - a.executeTemplate(rw, r, tpl, tplPayload) + a.executeTemplate(rw, r, tpl, nil) }) } func (a *api) editPostHandler(isDraft bool) http.Handler { - tpl := a.mustParseBasedTpl("post-edit.html") - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - - id := filepath.Base(r.URL.Path) - - if id == "/" && !isDraft { - http.Error(rw, "Post id required", 400) - return - } - - var ( - storedPost post.StoredPost - err error - ) - - if id != "/" { - - if isDraft { - storedPost.Post, err = a.params.PostDraftStore.GetByID(id) - } else { - 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 - } - } - - tags, err := a.params.PostStore.GetTags() - if err != nil { - apiutil.InternalServerError(rw, r, fmt.Errorf("fetching tags: %w", err)) - return - } - - tplPayload := struct { - Post post.StoredPost - Tags []string + a.executeTemplate(rw, r, tpl, struct { IsDraft bool Formats []post.Format }{ - Post: storedPost, - Tags: tags, IsDraft: isDraft, Formats: post.Formats, - } - - a.executeTemplate(rw, r, tpl, tplPayload) + }) }) } diff --git a/src/http/tpl.go b/src/http/tpl.go index c623f2e..afd4c8e 100644 --- a/src/http/tpl.go +++ b/src/http/tpl.go @@ -151,6 +151,8 @@ func (a *api) newTPLData(r *http.Request, payload interface{}) tplData { a.params.PublicURL, a.params.GeminiGatewayURL, a.params.PostStore, + a.params.PostAssetStore, + a.params.PostDraftStore, a.postPreprocessFuncs(), ), Payload: payload, diff --git a/src/http/tpl/draft-posts-manage.html b/src/http/tpl/draft-posts-manage.html index 5454f24..b1b4362 100644 --- a/src/http/tpl/draft-posts-manage.html +++ b/src/http/tpl/draft-posts-manage.html @@ -1,5 +1,15 @@ {{ define "body" }} + {{ $page := .GetQueryIntValue "p" 0 -}} + {{ $getPostsRes := .GetDraftPosts $page 20 -}} + + <script> + function confirmDelete(event) { + if (!confirm("Are you sure you want to delete this draft?")) + event.preventDefault(); + } + </script> + <p> <a href="{{ BlogURL "admin" }}">Back to Admin</a> </p> @@ -10,15 +20,15 @@ <a href="{{ BlogURL "drafts" }}?method=edit">New Draft</a> </p> - {{ if ge .Payload.PrevPage 0 }} + {{ if gt $page 0 }} <p> - <a href="?method=manage&p={{ .Payload.PrevPage}}">< < Previous Page</a> + <a href="?method=manage&p={{ .Add $page -1 }}">< < Previous Page</a> </p> {{ end }} <table> - {{ range .Payload.Posts }} + {{ range $getPostsRes.Posts }} <tr> <td>{{ .Title }}</td> <td> @@ -31,7 +41,11 @@ action="{{ DraftURL .ID }}?method=delete" method="POST" > - <input type="submit" value="Delete" /> + <input + type="submit" + value="Delete" + onclick="confirmDelete(event)" + /> </form> </td> </tr> @@ -39,9 +53,9 @@ </table> - {{ if ge .Payload.NextPage 0 }} + {{ if $getPostsRes.HasMore }} <p> - <a href="?method=manage&p={{ .Payload.NextPage}}">Next Page > ></a> + <a href="?method=manage&p={{ .Add $page 1 }}">Next Page > ></a> </p> {{ end }} diff --git a/src/http/tpl/post-assets-manage.html b/src/http/tpl/post-assets-manage.html index f21717a..a0b0da0 100644 --- a/src/http/tpl/post-assets-manage.html +++ b/src/http/tpl/post-assets-manage.html @@ -1,5 +1,7 @@ {{ define "body" }} +{{ $assetIDs := .GetPostAssetIDs }} + <p> <a href="{{ BlogURL "admin" }}">Back to Admin</a> </p> @@ -27,13 +29,13 @@ </div> </form> -{{ if gt (len .Payload.IDs) 0 }} +{{ if $assetIDs }} <h2>Existing Assets</h2> <table> - {{ range .Payload.IDs }} + {{ range $assetIDs }} <tr> <td><a href="{{ AssetURL . }}">{{ . }}</a></td> <td> diff --git a/src/http/tpl/post-edit.html b/src/http/tpl/post-edit.html index c66b60a..28dcd0e 100644 --- a/src/http/tpl/post-edit.html +++ b/src/http/tpl/post-edit.html @@ -1,5 +1,9 @@ {{ define "body" }} +{{ $tags := .GetTags }} + +{{ $post := (or (and .Payload.IsDraft .GetThisDraftPost) .GetThisPost) }} + <p> {{ if .Payload.IsDraft }} <a href="{{ BlogURL "drafts?method=manage" }}"> @@ -21,19 +25,19 @@ Unique ID </td> <td> - {{ if eq .Payload.Post.ID "" }} + {{ if eq $post.ID "" }} <input name="id" type="text" required placeholder="e.g. how-to-fly-a-kite" - value="{{ .Payload.Post.ID }}" /> + value="{{ $post.ID }}" /> {{ else if .Payload.IsDraft }} - {{ .Payload.Post.ID }} - <input name="id" type="hidden" value="{{ .Payload.Post.ID }}" /> + {{ $post.ID }} + <input name="id" type="hidden" value="{{ $post.ID }}" /> {{ else }} - <a href="{{ PostURL .Payload.Post.ID }}">{{ .Payload.Post.ID }}</a> - <input name="id" type="hidden" value="{{ .Payload.Post.ID }}" /> + <a href="{{ PostURL $post.ID }}">{{ $post.ID }}</a> + <input name="id" type="hidden" value="{{ $post.ID }}" /> {{ end }} </td> </tr> @@ -45,15 +49,15 @@ name="tags" type="text" required - value="{{- range $i, $tag := .Payload.Post.Tags -}} + value="{{- range $i, $tag := $post.Tags -}} {{- if ne $i 0 }} {{ end }}{{ $tag -}} {{- end -}} "/> - {{ if gt (len .Payload.Tags) 0 }} + {{ if $tags }} <em> Existing tags: - {{ range $i, $tag := .Payload.Tags }} + {{ range $i, $tag := $tags }} {{ if ne $i 0 }} {{ end }}{{ $tag }} {{ end }} </em> @@ -67,7 +71,7 @@ <input name="series" type="text" - value="{{ .Payload.Post.Series }}" /> + value="{{ $post.Series }}" /> </td> </tr> @@ -78,7 +82,7 @@ name="title" type="text" required - value="{{ .Payload.Post.Title }}" /> + value="{{ $post.Title }}" /> </td> </tr> @@ -88,7 +92,7 @@ <input name="description" type="text" - value="{{ .Payload.Post.Description }}" /> + value="{{ $post.Description }}" /> </td> </tr> @@ -98,7 +102,7 @@ <select name="format" required> <option value=""></option> - {{ $format := .Payload.Post.Format }} + {{ $format := $post.Format }} {{ range .Payload.Formats -}} <option {{- if eq . $format }} @@ -122,7 +126,7 @@ placeholder="Post body" style="width:100%;height: 75vh;" > - {{- .Payload.Post.Body -}} + {{- $post.Body -}} </textarea> </p> @@ -131,7 +135,7 @@ <input type="submit" value="Preview" - formaction="{{ BlogURL "posts/" }}{{ .Payload.Post.ID }}?method=preview" + formaction="{{ BlogURL "posts/" }}{{ $post.ID }}?method=preview" formtarget="_blank" /> diff --git a/src/http/tpl/posts-manage.html b/src/http/tpl/posts-manage.html index 96b30ca..f9adbc1 100644 --- a/src/http/tpl/posts-manage.html +++ b/src/http/tpl/posts-manage.html @@ -1,4 +1,8 @@ {{ define "body" }} + + {{ $page := .GetQueryIntValue "p" 0 -}} + {{ $getPostsRes := .GetPosts $page 20 -}} + <script> function confirmDelete(event) { if (!confirm("Are you sure you want to delete this post?")) @@ -12,9 +16,9 @@ <h1>Posts</h1> - {{ if ge .Payload.PrevPage 0 }} + {{ if gt $page 0 }} <p> - <a href="?method=manage&p={{ .Payload.PrevPage}}">< < Previous Page</a> + <a href="?method=manage&p={{ .Add $page -1 }}">< < Previous Page</a> </p> {{ end }} @@ -26,7 +30,7 @@ <col span="1" style="width: auto;"> </colgroup> - {{ range .Payload.Posts }} + {{ range $getPostsRes.Posts }} <tr> <td>{{ .PublishedAt.Local.Format "2006-01-02 15:04:05 MST" }}</td> <td><a href="{{ PostURL .ID }}">{{ .Title }}</a></td> @@ -52,9 +56,9 @@ </table> - {{ if ge .Payload.NextPage 0 }} + {{ if $getPostsRes.HasMore }} <p> - <a href="?method=manage&p={{ .Payload.NextPage}}">Next Page > ></a> + <a href="?method=manage&p={{ .Add $page 1 }}">Next Page > ></a> </p> {{ end }} diff --git a/src/http/tpl/posts.html b/src/http/tpl/posts.html index 0701459..2fa336d 100644 --- a/src/http/tpl/posts.html +++ b/src/http/tpl/posts.html @@ -1,8 +1,11 @@ {{ define "body" }} - {{ if ge .Payload.PrevPage 0 }} + {{ $page := .GetQueryIntValue "p" 0 -}} + {{ $getPostsRes := .GetPosts $page 20 -}} + + {{ if gt $page 0 }} <p> - <a href="?p={{ .Payload.PrevPage}}">< < Previous Page</a> + <a href="?p={{ .Add $page -1 }}">< < Previous Page</a> </p> {{ else }} <p> @@ -12,10 +15,10 @@ {{ end }} <ul> - {{ range .Payload.Posts }} + {{ range $getPostsRes.Posts }} <li> <strong><a href="{{ PostURL .ID }}"> - {{ DateTimeFormat .PublishedAt }} / {{ .Title }} + {{ .PublishedAt.Format "2006-01-02" }} - {{ .Title }} </a></strong> {{ if .Description }} <br/><em>{{ .Description }}</em> @@ -24,9 +27,9 @@ {{ end }} </ul> - {{ if ge .Payload.NextPage 0 }} + {{ if $getPostsRes.HasMore }} <p> - <a href="?p={{ .Payload.NextPage}}">Next Page > ></a> + <a href="?p={{ .Add $page 1 }}">Next Page > ></a> </p> {{ end }} diff --git a/src/render/methods.go b/src/render/methods.go index 6dd9332..5b2c0b1 100644 --- a/src/render/methods.go +++ b/src/render/methods.go @@ -13,6 +13,7 @@ import ( "dev.mediocregopher.com/mediocre-blog.git/src/gmi/gemtext" "dev.mediocregopher.com/mediocre-blog.git/src/post" + "dev.mediocregopher.com/mediocre-blog.git/src/post/asset" "github.com/gomarkdown/markdown" "github.com/gomarkdown/markdown/html" "github.com/gomarkdown/markdown/parser" @@ -37,6 +38,12 @@ type GetPostsRes struct { HasMore bool } +// GetDraftPostsRes are the fields returned from the GetDraftPosts method. +type GetDraftPostsRes struct { + Posts []post.Post + HasMore bool +} + // GetPostSeriesNextPreviousRes are the fields returned from the // GetPostSeriesNextPreviousRes method. type GetPostSeriesNextPreviousRes struct { @@ -51,9 +58,12 @@ type Methods struct { publicURL *url.URL geminiGatewayURL *url.URL postStore post.Store + postAssetStore asset.Store + postDraftStore post.DraftStore preprocessFuncs post.PreprocessFunctions - thisPost *post.StoredPost // cache + thisPost *post.StoredPost // cache + thisDraftPost *post.Post // cache } // NewMethods initializes a Methods using its required dependencies. @@ -63,6 +73,8 @@ func NewMethods( publicURL *url.URL, geminiGatewayURL *url.URL, postStore post.Store, + postAssetStore asset.Store, + postDraftStore post.DraftStore, preprocessFuncs post.PreprocessFunctions, ) *Methods { return &Methods{ @@ -71,16 +83,32 @@ func NewMethods( publicURL, geminiGatewayURL, postStore, + postAssetStore, + postDraftStore, preprocessFuncs, nil, // thisPost + nil, // thisDraftPost } } +func (m *Methods) GetTags() ([]string, error) { + return m.postStore.GetTags() +} + +func (m *Methods) GetPostAssetIDs() ([]string, error) { + return m.postAssetStore.List() +} + func (m *Methods) GetPosts(page, count int) (GetPostsRes, error) { posts, hasMore, err := m.postStore.Get(page, count) return GetPostsRes{posts, hasMore}, err } +func (m *Methods) GetDraftPosts(page, count int) (GetDraftPostsRes, error) { + posts, hasMore, err := m.postDraftStore.Get(page, count) + return GetDraftPostsRes{posts, hasMore}, err +} + func (m *Methods) GetThisPost() (p post.StoredPost, err error) { if m.thisPost != nil { return *m.thisPost, nil @@ -100,12 +128,23 @@ func (m *Methods) GetThisPost() (p post.StoredPost, err error) { return m.postStore.GetByID(id) } -func (m *Methods) GetPostByID(id string) (post.StoredPost, error) { - p, err := m.postStore.GetByID(id) - if err != nil { - return post.StoredPost{}, fmt.Errorf("fetching post %q: %w", id, err) +func (m *Methods) GetThisDraftPost() (p post.Post, err error) { + if m.thisPost != nil { + return *m.thisDraftPost, nil } - return p, nil + + defer func() { + m.thisDraftPost = &p + }() + + id := path.Base(m.url.Path) + if id == "/" { + // An empty draft is fine, in the context of editing + return + } + + id = strings.TrimSuffix(id, path.Ext(id)) + return m.postDraftStore.GetByID(id) } func (m *Methods) GetPostSeriesNextPrevious( |