summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--srv/src/http/posts.go23
-rw-r--r--srv/src/post/post.go24
-rw-r--r--srv/src/post/post_test.go20
3 files changed, 54 insertions, 13 deletions
diff --git a/srv/src/http/posts.go b/srv/src/http/posts.go
index c779eed..daa756c 100644
--- a/srv/src/http/posts.go
+++ b/srv/src/http/posts.go
@@ -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)
diff --git a/srv/src/post/post.go b/srv/src/post/post.go
index 29a984f..a39af61 100644
--- a/srv/src/post/post.go
+++ b/srv/src/post/post.go
@@ -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(
diff --git a/srv/src/post/post_test.go b/srv/src/post/post_test.go
index b6d8a2e..c7f9cdc 100644
--- a/srv/src/post/post_test.go
+++ b/srv/src/post/post_test.go
@@ -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")