implement backend components for push notifications

This commit is contained in:
talksik
2026-05-18 10:31:16 -07:00
parent 1618cb58cb
commit 6f476fe773
16 changed files with 904 additions and 60 deletions
+4 -33
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"log/slog"
"os"
"strings"
"time"
"cloud.google.com/go/firestore"
@@ -119,13 +118,6 @@ func runNotificationCycle(
}
for _, net := range networks {
// Build set of all member humanIds for this network (members + admin)
networkMembers := make(map[string]bool, len(net.MemberHumanIds)+1)
for _, id := range net.MemberHumanIds {
networkMembers[id] = true
}
networkMembers[net.AdminHumanId] = true
// Query Firestore for open streams in this network
streams, err := getOpenStreams(ctx, fsClient, net.ID)
if err != nil {
@@ -133,6 +125,8 @@ func runNotificationCycle(
continue
}
// net.MemberHumanIds already contains the admin (Create() adds them and
// RemoveMemberFromNetwork won't drop them) — no need to union separately.
for _, stream := range streams {
if stream.LastChildCreatedAt == nil {
continue
@@ -146,10 +140,8 @@ func runNotificationCycle(
continue
}
// Resolve members from visible_to
members := resolveMembers(stream.VisibleTo, networkMembers)
for humanId := range members {
// Resolve members from visible_to using the shared helper
for _, humanId := range network.ResolveVisibility(stream.VisibleTo, net.MemberHumanIds) {
marker, hasMarker := stream.PlaybackMarkers[humanId]
if hasMarker && !marker.Before(*stream.LastChildCreatedAt) {
continue // up to date
@@ -239,27 +231,6 @@ func getOpenStreams(ctx context.Context, client *firestore.Client, networkId str
return streams, nil
}
// resolveMembers expands visible_to entries into a set of humanIds.
// "human:{id}" adds that id directly. "network:{id}" expands to all network members.
func resolveMembers(visibleTo []string, networkMembers map[string]bool) map[string]bool {
members := map[string]bool{}
for _, entry := range visibleTo {
if strings.HasPrefix(entry, "human:") {
humanId := strings.TrimPrefix(entry, "human:")
// human can be in visible_to, but no longer a member of the network
if _, ok := networkMembers[humanId]; ok {
members[humanId] = true
}
} else if strings.HasPrefix(entry, "network:") {
// Expand to all network members
for id := range networkMembers {
members[id] = true
}
}
}
return members
}
func sendNotificationEmail(ctx context.Context, aeroSvc pbaero.PrimaryClient, h *human.Human, streamCount int) error {
streamsWord := "stream"
if streamCount != 1 {