A community based topic aggregation platform built on atproto
1package userblocks
2
3import (
4 "Coves/internal/atproto/pds"
5 "context"
6
7 "github.com/bluesky-social/indigo/atproto/auth/oauth"
8)
9
10// PDSClientFactory creates PDS clients from session data.
11// This is primarily used for test injection via NewServiceWithPDSFactory to allow
12// password-based auth in integration tests instead of OAuth DPoP.
13type PDSClientFactory func(ctx context.Context, session *oauth.ClientSessionData) (pds.Client, error)
14
15// Repository defines the interface for user block data persistence.
16// This is the AppView's indexed view of blocks from the firehose.
17type Repository interface {
18 // BlockUser creates a new block record (idempotent via ON CONFLICT DO UPDATE)
19 BlockUser(ctx context.Context, block *UserBlock) (*UserBlock, error)
20
21 // UnblockUser removes a block record. Returns ErrBlockNotFound if not exists.
22 UnblockUser(ctx context.Context, blockerDID, blockedDID string) error
23
24 // GetBlock retrieves a block by blocker + blocked DID pair.
25 // Returns ErrBlockNotFound if not exists.
26 GetBlock(ctx context.Context, blockerDID, blockedDID string) (*UserBlock, error)
27
28 // GetBlockByURI retrieves a block by its AT-URI.
29 // Used by Jetstream consumer for DELETE operations (which don't include record data).
30 // Returns ErrBlockNotFound if not exists.
31 GetBlockByURI(ctx context.Context, recordURI string) (*UserBlock, error)
32
33 // ListBlockedUsers retrieves all users blocked by the given blocker, paginated.
34 // Results are ordered by blocked_at DESC.
35 ListBlockedUsers(ctx context.Context, blockerDID string, limit, offset int) ([]*UserBlock, error)
36
37 // IsBlocked checks if blockerDID has blocked blockedDID (fast EXISTS check).
38 IsBlocked(ctx context.Context, blockerDID, blockedDID string) (bool, error)
39
40 // AreBlocked checks which of the given DIDs are blocked by blockerDID.
41 // Returns a map of blockedDID → true for each DID that is blocked.
42 // Used for batch hydration of viewer state on lists of posts/comments.
43 AreBlocked(ctx context.Context, blockerDID string, blockedDIDs []string) (map[string]bool, error)
44}
45
46// Service defines the interface for user block business logic.
47// Coordinates between Repository and external services (PDS, identity, etc.)
48// Uses write-forward pattern: Service → PDS → Firehose → Consumer → Repository
49type Service interface {
50 // BlockUser creates a block against another user.
51 // Uses OAuth session for DPoP-authenticated PDS write-forward.
52 // The identifier can be a DID or handle.
53 // Returns a BlockResult with the record URI and CID from PDS.
54 // The block is indexed asynchronously via the firehose consumer.
55 // Returns ErrCannotBlockSelf if the user attempts to block themselves.
56 // Returns ErrBlockAlreadyExists if the block already exists on PDS.
57 BlockUser(ctx context.Context, session *oauth.ClientSessionData, identifier string) (*BlockResult, error)
58
59 // UnblockUser removes a block against another user.
60 // Uses OAuth session for DPoP-authenticated PDS delete.
61 // The identifier can be a DID or handle.
62 UnblockUser(ctx context.Context, session *oauth.ClientSessionData, identifier string) error
63
64 // GetBlockedUsers retrieves all users blocked by the given user, paginated.
65 GetBlockedUsers(ctx context.Context, blockerDID string, limit, offset int) ([]*UserBlock, error)
66
67 // IsBlocked checks if blockerDID has blocked blockedDID.
68 IsBlocked(ctx context.Context, blockerDID, blockedDID string) (bool, error)
69}