feat: disciple link

This commit is contained in:
Krispire Admin
2026-08-07 22:46:08 +05:30
parent 4553725d4e
commit afcdd7ef19
21 changed files with 863 additions and 23 deletions
+56
View File
@@ -334,6 +334,62 @@ func (r *NotificationRepo) CreateAdminMessage(ctx context.Context, userID, body
return nil
}
// BroadcastToAllUsers writes one notification of `kind` to every active user
// except `actorID`, in a single INSERT…SELECT. One round trip regardless of
// audience size — the alternative (a row per user from Go) would be hundreds
// of round trips on the request path.
//
// Deliberately does NOT filter on notification_prefs: ListByUser already
// excludes kinds the reader has disabled for the in_app channel at read time,
// so writing the rows unconditionally keeps a re-enabled preference able to
// surface history — exactly how the existing kinds behave.
//
// Banned accounts are skipped; they can't sign in to read it anyway.
func (r *NotificationRepo) BroadcastToAllUsers(ctx context.Context, kind, actorID string) (int64, error) {
tag, err := r.pg.Pool.Exec(ctx, `
INSERT INTO notifications (user_id, actor_id, kind)
SELECT u.id, $2, $1
FROM users u
WHERE u.id <> $2 AND u.banned_at IS NULL`, kind, actorID)
if err != nil {
return 0, fmt.Errorf("broadcast notification: %w", err)
}
return tag.RowsAffected(), nil
}
// PushRecipientsForKind lists the ids of users who should receive a *push* for
// `kind` — everyone except the actor, minus banned accounts, minus anyone who
// turned this kind off for the push channel, and minus anyone with no push
// subscription registered at all.
//
// That last filter is what keeps a broadcast cheap: only devotees who actually
// enabled web push are worth iterating, which is typically a small fraction of
// the user base.
func (r *NotificationRepo) PushRecipientsForKind(ctx context.Context, kind, actorID string) ([]string, error) {
rows, err := r.pg.Pool.Query(ctx, `
SELECT DISTINCT u.id
FROM users u
JOIN push_subscriptions ps ON ps.user_id = u.id
WHERE u.id <> $2 AND u.banned_at IS NULL
AND NOT EXISTS (
SELECT 1 FROM notification_prefs np
WHERE np.user_id = u.id AND np.kind = $1
AND np.channel = 'push' AND np.enabled = FALSE)`, kind, actorID)
if err != nil {
return nil, fmt.Errorf("list push recipients: %w", err)
}
defer rows.Close()
out := []string{}
for rows.Next() {
var id string
if err := rows.Scan(&id); err != nil {
return nil, fmt.Errorf("scan push recipient: %w", err)
}
out = append(out, id)
}
return out, rows.Err()
}
// ListByUser returns a recipient's notifications, newest first, with the
// actor's display fields joined in for rendering (nil for system
// notifications or since-deleted actors). Kinds the user has turned off for