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
+9
View File
@@ -16,6 +16,9 @@ type Reader interface {
ListForHuman(ctx context.Context, humanId string) ([]*Network, error)
// IsMember returns ErrInvalidHumanId if humanId is empty.
IsMember(ctx context.Context, networkID, humanId string) (bool, error)
// ListMembers returns all human IDs belonging to the network.
// Returns an empty slice if the network doesn't exist.
ListMembers(ctx context.Context, networkID string) ([]string, error)
// ListAll returns all networks with their members
ListAll(ctx context.Context) ([]*Network, error)
// ListAllMemberships returns humanId -> networkIds for every human with at
@@ -69,6 +72,12 @@ func (r *readerImpl) IsMember(ctx context.Context, networkID, humanId string) (b
return r.repo.isMember(ctx, networkID, humanId)
}
func (r *readerImpl) ListMembers(ctx context.Context, networkID string) ([]string, error) {
// Admin is guaranteed to be in network_members: Create() calls AddMembers
// for the admin, and RemoveMemberFromNetwork rejects admin removal.
return r.repo.getMemberHumanIds(ctx, networkID)
}
func (r *readerImpl) ListAll(ctx context.Context) ([]*Network, error) {
return r.repo.listAll(ctx)
}
+41
View File
@@ -0,0 +1,41 @@
package network
import "strings"
// ResolveVisibility expands a stream particle's visible_to entries into the set
// of human IDs that should see (and thus be notified about) activity in that
// stream. Entries are formatted as `human:{id}` for a specific human or
// `network:{id}` to expand to every member of the surrounding network.
//
// networkMembers must contain every human currently in the network (members +
// admin). visible_to entries that point to humans no longer in the network are
// dropped — they may have been removed since the stream was created.
//
// Returns a deduped slice; ordering is not stable.
func ResolveVisibility(visibleTo []string, networkMembers []string) []string {
memberSet := make(map[string]bool, len(networkMembers))
for _, id := range networkMembers {
memberSet[id] = true
}
result := make(map[string]bool)
for _, entry := range visibleTo {
switch {
case strings.HasPrefix(entry, "human:"):
id := strings.TrimPrefix(entry, "human:")
if memberSet[id] {
result[id] = true
}
case strings.HasPrefix(entry, "network:"):
for id := range memberSet {
result[id] = true
}
}
}
out := make([]string, 0, len(result))
for id := range result {
out = append(out, id)
}
return out
}