feat: add comments
This commit is contained in:
@@ -35,6 +35,8 @@ const (
|
||||
NotifFollowAccepted = "follow_accepted"
|
||||
NotifPostLike = "post_like"
|
||||
NotifPostMention = "post_mention"
|
||||
NotifPostComment = "post_comment"
|
||||
NotifCommentReply = "comment_reply"
|
||||
|
||||
// Reminder kinds are delivered live (email + push + a websocket toast)
|
||||
// but NOT persisted — they're ephemeral nudges, not history.
|
||||
@@ -48,7 +50,7 @@ const (
|
||||
// opt-outs map exactly), but the UI reads/writes whole categories.
|
||||
var PrefCategories = map[string][]string{
|
||||
"follows": {NotifFollowRequest, NotifFollowAccepted},
|
||||
"post_interactions": {NotifPostLike, NotifPostMention},
|
||||
"post_interactions": {NotifPostLike, NotifPostMention, NotifPostComment, NotifCommentReply},
|
||||
"sadhna_reminders": {NotifChantReminder, NotifQuoteReminder, NotifChantIncomplete},
|
||||
}
|
||||
|
||||
@@ -351,6 +353,59 @@ func (s *NotificationService) NotifyPostMention(ctx context.Context, mentionedID
|
||||
})
|
||||
}
|
||||
|
||||
// NotifyPostComment tells the post author that `commenterID` commented on
|
||||
// their post. NotifyCommentReply tells `recipientID` (the author of the
|
||||
// comment being replied to) that `replierID` replied. Both: persisted row +
|
||||
// realtime + Web Push, no email (comments are interactive, not digest-worthy).
|
||||
// Self-actions are skipped.
|
||||
func (s *NotificationService) NotifyPostComment(ctx context.Context, postID, authorID, commenterID string) {
|
||||
s.notifyComment(ctx, NotifPostComment, postID, authorID, commenterID)
|
||||
}
|
||||
|
||||
func (s *NotificationService) NotifyCommentReply(ctx context.Context, postID, recipientID, replierID string) {
|
||||
s.notifyComment(ctx, NotifCommentReply, postID, recipientID, replierID)
|
||||
}
|
||||
|
||||
func (s *NotificationService) notifyComment(ctx context.Context, kind, postID, recipientID, actorID string) {
|
||||
if recipientID == "" || actorID == "" || recipientID == actorID {
|
||||
return
|
||||
}
|
||||
off := s.disabledPrefs(ctx, recipientID)
|
||||
if err := s.notifs.CreateComment(ctx, recipientID, actorID, postID, kind); err != nil {
|
||||
s.logger.Warn("persist comment notification failed",
|
||||
zap.String("recipient", recipientID), zap.String("kind", kind), zap.Error(err))
|
||||
}
|
||||
actorUser, _ := s.users.FindByID(ctx, actorID)
|
||||
if !prefOff(off, kind, repository.ChannelInApp) {
|
||||
s.publishRealtime(ctx, recipientID, kind, actorUser)
|
||||
}
|
||||
|
||||
if s.push == nil || prefOff(off, kind, repository.ChannelPush) {
|
||||
return
|
||||
}
|
||||
who := "Someone"
|
||||
if actorUser != nil {
|
||||
who = actorDisplay(actorUser)
|
||||
}
|
||||
// Tapping it opens the post (via its author's handle — the actor isn't the
|
||||
// post owner on a reply). Falls back to the notification center.
|
||||
url := s.frontendURL + "/notifications"
|
||||
if h, err := s.notifs.PostAuthorHandle(ctx, postID); err == nil && h != "" {
|
||||
url = s.frontendURL + "/u/" + h + "/posts#post-" + postID
|
||||
}
|
||||
title, body := "New comment", who+" commented on your post"
|
||||
if kind == NotifCommentReply {
|
||||
title, body = "New reply", who+" replied to your comment"
|
||||
}
|
||||
s.push.SendToUser(ctx, recipientID, PushPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: url,
|
||||
Icon: s.iconURL(),
|
||||
Tag: kind + ":" + postID,
|
||||
})
|
||||
}
|
||||
|
||||
// likeMessage renders the aggregated like text: "X liked your post" or
|
||||
// "X and N others liked your post".
|
||||
func likeMessage(who string, count int) string {
|
||||
|
||||
Reference in New Issue
Block a user