Publish new posts to mailing list

This commit is contained in:
Brian Picciano 2022-05-21 11:15:37 -06:00
parent 3e67823205
commit 3059909deb
3 changed files with 54 additions and 13 deletions

View File

@ -131,11 +131,17 @@ func (a *api) renderPostHandler() http.Handler {
func (a *api) renderPostsIndexHandler() http.Handler {
renderEditPostHandler := a.renderEditPostHandler()
tpl := a.mustParseBasedTpl("posts.html")
const pageCount = 20
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if _, ok := r.URL.Query()["edit"]; ok {
renderEditPostHandler.ServeHTTP(rw, r)
return
}
page, err := apiutil.StrToInt(r.FormValue("p"), 0)
if err != nil {
apiutil.BadRequest(
@ -239,13 +245,28 @@ func (a *api) postPostHandler() http.Handler {
return
}
if err := a.params.PostStore.Set(p, time.Now()); err != nil {
first, err := a.params.PostStore.Set(p, time.Now())
if err != nil {
apiutil.InternalServerError(
rw, r, fmt.Errorf("storing post with id %q: %w", p.ID, err),
)
return
}
if first {
a.params.Logger.Info(r.Context(), "publishing blog post to mailing list")
urlStr := a.params.PublicURL.String() + filepath.Join("/posts", p.ID)
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
}
}
redirectPath := fmt.Sprintf("posts/%s?edit", p.ID)
a.executeRedirectTpl(rw, r, redirectPath)

View File

@ -48,9 +48,10 @@ type StoredPost struct {
// Store is used for storing posts to a persistent storage.
type Store interface {
// Set sets the Post data into the storage, keyed by the Post's ID. It
// overwrites a previous Post with the same ID, if there was one.
Set(post Post, now time.Time) error
// Set sets the Post data into the storage, keyed by the Post's ID. If there
// was not a previously existing Post with the same ID then Set returns
// true. It overwrites the previous Post with the same ID otherwise.
Set(post Post, now time.Time) (bool, error)
// Get returns count StoredPosts, sorted time descending, offset by the
// given page number. The returned boolean indicates if there are more pages
@ -114,13 +115,15 @@ func (s *store) withTx(cb func(*sql.Tx) error) error {
return nil
}
func (s *store) Set(post Post, now time.Time) error {
func (s *store) Set(post Post, now time.Time) (bool, error) {
if post.ID == "" {
return errors.New("post ID can't be empty")
return false, errors.New("post ID can't be empty")
}
return s.withTx(func(tx *sql.Tx) error {
var first bool
err := s.withTx(func(tx *sql.Tx) error {
nowTS := now.Unix()
@ -173,8 +176,17 @@ func (s *store) Set(post Post, now time.Time) error {
}
}
err = tx.QueryRow(
`SELECT 1 FROM posts WHERE id=? AND last_updated_at IS NULL`,
post.ID,
).Scan(new(int))
first = !errors.Is(err, sql.ErrNoRows)
return nil
})
return first, err
}
func (s *store) get(

View File

@ -108,7 +108,9 @@ func TestStore(t *testing.T) {
post := testPost(0)
post.Tags = []string{"foo", "bar"}
assert.NoError(t, h.store.Set(post, now))
first, err := h.store.Set(post, now)
assert.NoError(t, err)
assert.True(t, first)
gotPost, err := h.store.GetByID(post.ID)
assert.NoError(t, err)
@ -129,7 +131,9 @@ func TestStore(t *testing.T) {
post.Body = "anything"
post.Tags = []string{"bar", "baz"}
assert.NoError(t, h.store.Set(post, newNow))
first, err = h.store.Set(post, newNow)
assert.NoError(t, err)
assert.False(t, first)
gotPost, err = h.store.GetByID(post.ID)
assert.NoError(t, err)
@ -160,7 +164,8 @@ func TestStore(t *testing.T) {
}
for _, post := range posts {
assert.NoError(t, h.store.Set(post.Post, now))
_, err := h.store.Set(post.Post, now)
assert.NoError(t, err)
}
gotPosts, hasMore, err := h.store.Get(0, 2)
@ -174,7 +179,8 @@ func TestStore(t *testing.T) {
assertPostsEqual(t, posts[2:4], gotPosts)
posts = append([]StoredPost{h.testStoredPost(4)}, posts...)
assert.NoError(t, h.store.Set(posts[0].Post, now))
_, err = h.store.Set(posts[0].Post, now)
assert.NoError(t, err)
gotPosts, hasMore, err = h.store.Get(1, 2)
assert.NoError(t, err)
@ -204,7 +210,8 @@ func TestStore(t *testing.T) {
posts[2].Series = "bar"
for _, post := range posts {
assert.NoError(t, h.store.Set(post.Post, now))
_, err := h.store.Set(post.Post, now)
assert.NoError(t, err)
}
fooPosts, err := h.store.GetBySeries("foo")
@ -238,7 +245,8 @@ func TestStore(t *testing.T) {
posts[2].Tags = []string{"bar"}
for _, post := range posts {
assert.NoError(t, h.store.Set(post.Post, now))
_, err := h.store.Set(post.Post, now)
assert.NoError(t, err)
}
fooPosts, err := h.store.GetByTag("foo")