Notify homeowners of plumber replies
CI / test (pull_request) Successful in 6m16s

This commit is contained in:
2026-08-27 09:12:30 -07:00
parent df17e0e6f3
commit 17e73ad2d3
2 changed files with 27 additions and 5 deletions
+10 -4
View File
@@ -93,7 +93,8 @@ func (s *Server) handleCreatePost(w http.ResponseWriter, r *http.Request) {
) )
} }
// notifyPostReply asynchronously emails the direct parent post's author. // notifyPostReply emails the root homeowner for admin replies and the direct
// parent author for homeowner replies.
func (s *Server) notifyPostReply( func (s *Server) notifyPostReply(
parent *store.Post, parent *store.Post,
root *store.Post, root *store.Post,
@@ -104,13 +105,19 @@ func (s *Server) notifyPostReply(
root == nil || root == nil ||
reply == nil || reply == nil ||
replyAuthor == nil || replyAuthor == nil ||
s.cfg.Mail == nil || s.cfg.Mail == nil {
parent.AuthorID == replyAuthor.ID {
return return
} }
if _, disabled := s.cfg.Mail.(mail.Nop); disabled { if _, disabled := s.cfg.Mail.(mail.Nop); disabled {
return return
} }
recipientID := parent.AuthorID
if replyAuthor.Admin() {
recipientID = root.AuthorID
}
if recipientID == replyAuthor.ID {
return
}
msg := mail.PostReply{ msg := mail.PostReply{
RootID: root.ID, RootID: root.ID,
RootTitle: root.Title, RootTitle: root.Title,
@@ -118,7 +125,6 @@ func (s *Server) notifyPostReply(
ReplyBody: reply.Body, ReplyBody: reply.Body,
ReplyAuthorName: replyAuthor.Name, ReplyAuthorName: replyAuthor.Name,
} }
recipientID := parent.AuthorID
go func() { go func() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
+17 -1
View File
@@ -334,6 +334,22 @@ func TestPostReplyNotifications(t *testing.T) {
t.Fatalf("homeowner reply notification = %+v", msg) t.Fatalf("homeowner reply notification = %+v", msg)
} }
rec = postForm(handler, "/posts", url.Values{
"_csrf": {adminCSRF},
"parent_id": {adminReply.ID},
"body": {"One more plumber detail."},
}, adminCookies)
if rec.Code != http.StatusSeeOther {
t.Fatalf("nested admin reply status = %d: %s", rec.Code, rec.Body.String())
}
msgs = waitForMail(t, recording, 3)
if msg := msgs[2]; msg.ToEmail != homeowner.Email ||
msg.RootID != root.ID ||
msg.ReplyBody != "One more plumber detail." ||
msg.ReplyAuthorName != admin.Name {
t.Fatalf("nested admin reply notification = %+v", msg)
}
rec = postForm(handler, "/posts", url.Values{ rec = postForm(handler, "/posts", url.Values{
"_csrf": {homeownerCSRF}, "_csrf": {homeownerCSRF},
"parent_id": {root.ID}, "parent_id": {root.ID},
@@ -376,7 +392,7 @@ func TestPostReplyNotifications(t *testing.T) {
t.Fatalf("no-email reply status = %d: %s", rec.Code, rec.Body.String()) t.Fatalf("no-email reply status = %d: %s", rec.Code, rec.Body.String())
} }
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
if recording.Len() != 2 { if recording.Len() != 3 {
t.Fatalf("self, edit, or no-email action sent a notification: %+v", recording.Snapshot()) t.Fatalf("self, edit, or no-email action sent a notification: %+v", recording.Snapshot())
} }
} }