fix pagination on crew record check

This commit is contained in:
Evan Jarrett
2026-01-06 09:29:37 -06:00
parent c80b5b2941
commit 482d921cc8
+62 -45
View File
@@ -324,56 +324,73 @@ func (a *RemoteHoldAuthorizer) IsCrewMember(ctx context.Context, holdDID, userDI
}
// isCrewMemberNoCache queries XRPC without caching (internal helper)
// Handles pagination to check all crew records, not just the first page
func (a *RemoteHoldAuthorizer) isCrewMemberNoCache(ctx context.Context, holdDID, userDID string) (bool, error) {
// Resolve DID to URL
holdURL := atproto.ResolveHoldURL(holdDID)
// Build XRPC request URL
// GET /xrpc/com.atproto.repo.listRecords?repo={did}&collection=io.atcr.hold.crew
xrpcURL := fmt.Sprintf("%s%s?repo=%s&collection=%s",
holdURL, atproto.RepoListRecords, url.QueryEscape(holdDID), url.QueryEscape(atproto.CrewCollection))
req, err := http.NewRequestWithContext(ctx, "GET", xrpcURL, nil)
if err != nil {
return false, err
}
resp, err := a.httpClient.Do(req)
if err != nil {
return false, fmt.Errorf("XRPC request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return false, fmt.Errorf("XRPC request failed: status %d: %s", resp.StatusCode, string(body))
}
// Parse response
var xrpcResp struct {
Records []struct {
URI string `json:"uri"`
CID string `json:"cid"`
Value struct {
Type string `json:"$type"`
Member string `json:"member"`
Role string `json:"role"`
Permissions []string `json:"permissions"`
AddedAt string `json:"addedAt"`
} `json:"value"`
} `json:"records"`
}
if err := json.NewDecoder(resp.Body).Decode(&xrpcResp); err != nil {
return false, fmt.Errorf("failed to decode XRPC response: %w", err)
}
// Check if userDID is in the crew list
for _, record := range xrpcResp.Records {
if record.Value.Member == userDID {
// TODO: Check expiration if set
return true, nil
// Paginate through all crew records
cursor := ""
for {
// Build XRPC request URL with pagination
// GET /xrpc/com.atproto.repo.listRecords?repo={did}&collection=io.atcr.hold.crew&limit=100
xrpcURL := fmt.Sprintf("%s%s?repo=%s&collection=%s&limit=100",
holdURL, atproto.RepoListRecords, url.QueryEscape(holdDID), url.QueryEscape(atproto.CrewCollection))
if cursor != "" {
xrpcURL += "&cursor=" + url.QueryEscape(cursor)
}
req, err := http.NewRequestWithContext(ctx, "GET", xrpcURL, nil)
if err != nil {
return false, err
}
resp, err := a.httpClient.Do(req)
if err != nil {
return false, fmt.Errorf("XRPC request failed: %w", err)
}
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
return false, fmt.Errorf("XRPC request failed: status %d: %s", resp.StatusCode, string(body))
}
// Parse response
var xrpcResp struct {
Cursor string `json:"cursor"`
Records []struct {
URI string `json:"uri"`
CID string `json:"cid"`
Value struct {
Type string `json:"$type"`
Member string `json:"member"`
Role string `json:"role"`
Permissions []string `json:"permissions"`
AddedAt string `json:"addedAt"`
} `json:"value"`
} `json:"records"`
}
if err := json.NewDecoder(resp.Body).Decode(&xrpcResp); err != nil {
resp.Body.Close()
return false, fmt.Errorf("failed to decode XRPC response: %w", err)
}
resp.Body.Close()
// Check if userDID is in this page of crew records
for _, record := range xrpcResp.Records {
if record.Value.Member == userDID {
// TODO: Check expiration if set
return true, nil
}
}
// Check if there are more pages
if xrpcResp.Cursor == "" || len(xrpcResp.Records) == 0 {
break
}
cursor = xrpcResp.Cursor
}
return false, nil