clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

main
tinyrelay / internal / community / records_reader.go
records_reader.go 2.3K
1package community23import (4 "context"5 "errors"6 "strings"78 "github.com/FelineStateMachine/tinyrelay/internal/communityread"9)1011// Members exposes the community-owned membership projection to records. The12// records package consumes this narrow read model and never relies on table13// names or columns.14func (s *Service) Members(ctx context.Context) ([]communityread.Member, error) {15 rows, err := s.store.DB().QueryContext(ctx, `SELECT pubkey,name,role FROM community_members ORDER BY pubkey`)16 if err != nil {17 if strings.Contains(err.Error(), "no such table") {18 return nil, nil19 }20 return nil, err21 }22 defer rows.Close()23 var out []communityread.Member24 for rows.Next() {25 var member communityread.Member26 if err := rows.Scan(&member.PubKey, &member.Name, &member.Role); err != nil {27 return nil, err28 }29 out = append(out, member)30 }31 return out, rows.Err()32}3334// MemberStatus reports the key's membership and the current member count in one35// call so succession checks use a consistent community snapshot.36func (s *Service) MemberStatus(ctx context.Context, pubkey string) (bool, int, error) {37 var count int38 var member int39 if err := s.store.DB().QueryRowContext(ctx, `SELECT count(*), coalesce(max(pubkey=?),0) FROM community_members`, pubkey).Scan(&count, &member); err != nil {40 if strings.Contains(err.Error(), "no such table") {41 return false, 0, nil42 }43 return false, 0, err44 }45 return member != 0, count, nil46}4748// ModerationCounts returns the counters needed by the moderation view.49func (s *Service) ModerationCounts(ctx context.Context, start int64) (communityread.ModerationCounts, error) {50 var out communityread.ModerationCounts51 queries := []struct {52 table string53 to *int54 where string55 }{56 {"community_bans", &out.Bans, "at>=?"},57 {"community_reports", &out.Reports, "at>=?"},58 {"community_reports", &out.Resolved, "resolved_at>=?"},59 {"community_event_bans", &out.Hidden, "at>=?"},60 {"community_ip_blocks", &out.BlockedAddresses, "at>=?"},61 }62 var failures error63 for _, query := range queries {64 if err := s.store.DB().QueryRowContext(ctx, "SELECT count(*) FROM "+query.table+" WHERE "+query.where, start).Scan(query.to); err != nil {65 if strings.Contains(err.Error(), "no such table") {66 continue67 }68 failures = errors.Join(failures, err)69 }70 }71 return out, failures72}