feat: add email notification for post like
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/prabhupadasays/spsays-bff/internal/model"
|
||||
@@ -347,25 +348,57 @@ func (r *NotificationRepo) ListByUser(ctx context.Context, userID string, limit,
|
||||
|
||||
// UpsertLike records (or aggregates) a like notification: one row per
|
||||
// (recipient, post). On a repeat like it refreshes the most-recent actor,
|
||||
// bumps actor_count, and re-marks the row unread + most-recent. Returns the
|
||||
// new actor_count.
|
||||
func (r *NotificationRepo) UpsertLike(ctx context.Context, userID, actorID, postID string) (int, error) {
|
||||
var count int
|
||||
err := r.pg.Pool.QueryRow(ctx, `
|
||||
INSERT INTO notifications (user_id, actor_id, kind, post_id, actor_count)
|
||||
VALUES ($1, $2, 'post_like', $3, 1)
|
||||
// bumps actor_count, and re-marks the row unread + most-recent.
|
||||
//
|
||||
// It also throttles the aggregated like *email*: like_email_sent_at is stamped
|
||||
// to now() on the first like and again only once `throttle` has elapsed since
|
||||
// the last email. Returns the new actor_count and whether an email is due this
|
||||
// call (i.e. the stamp was (re)set now) — decided atomically in one statement
|
||||
// to avoid double-emailing under concurrent likes.
|
||||
func (r *NotificationRepo) UpsertLike(ctx context.Context, userID, actorID, postID string, throttle time.Duration) (count int, emailDue bool, err error) {
|
||||
secs := int(throttle.Seconds())
|
||||
err = r.pg.Pool.QueryRow(ctx, `
|
||||
INSERT INTO notifications (user_id, actor_id, kind, post_id, actor_count, like_email_sent_at)
|
||||
VALUES ($1, $2, 'post_like', $3, 1, now())
|
||||
ON CONFLICT (user_id, post_id) WHERE kind = 'post_like'
|
||||
DO UPDATE SET actor_id = EXCLUDED.actor_id,
|
||||
actor_count = notifications.actor_count + 1,
|
||||
read_at = NULL,
|
||||
created_at = now()
|
||||
RETURNING actor_count`,
|
||||
userID, actorID, postID,
|
||||
).Scan(&count)
|
||||
created_at = now(),
|
||||
like_email_sent_at = CASE
|
||||
WHEN notifications.like_email_sent_at IS NULL
|
||||
OR notifications.like_email_sent_at < now() - make_interval(secs => $4)
|
||||
THEN now()
|
||||
ELSE notifications.like_email_sent_at
|
||||
END
|
||||
RETURNING actor_count, (like_email_sent_at = now())`,
|
||||
userID, actorID, postID, secs,
|
||||
).Scan(&count, &emailDue)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("upsert like notification: %w", err)
|
||||
return 0, false, fmt.Errorf("upsert like notification: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
return count, emailDue, nil
|
||||
}
|
||||
|
||||
// LikeEmailsEnabled reports whether the user wants aggregated like emails.
|
||||
func (r *NotificationRepo) LikeEmailsEnabled(ctx context.Context, userID string) (bool, error) {
|
||||
var enabled bool
|
||||
if err := r.pg.Pool.QueryRow(ctx,
|
||||
`SELECT like_emails_enabled FROM users WHERE id = $1`, userID,
|
||||
).Scan(&enabled); err != nil {
|
||||
return false, fmt.Errorf("get like-email pref: %w", err)
|
||||
}
|
||||
return enabled, nil
|
||||
}
|
||||
|
||||
// SetLikeEmailsEnabled flips the user's like-email opt-in.
|
||||
func (r *NotificationRepo) SetLikeEmailsEnabled(ctx context.Context, userID string, enabled bool) error {
|
||||
if _, err := r.pg.Pool.Exec(ctx,
|
||||
`UPDATE users SET like_emails_enabled = $1 WHERE id = $2`, enabled, userID,
|
||||
); err != nil {
|
||||
return fmt.Errorf("set like-email pref: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountUnread returns how many of a recipient's notifications are unread.
|
||||
|
||||
Reference in New Issue
Block a user