feat(api): add endpoint to list community prefixes with pagination
Introduced a new GET endpoint `/v1/communities/{id}/prefixes` to retrieve unique prefixes associated with a community, including pagination support via cursor and limit parameters. Updated OpenAPI documentation to reflect this addition. Implemented backend logic in both PostgreSQL and in-memory storage to handle the new functionality, ensuring proper authorization checks and response formatting.
This commit is contained in:
@@ -60,6 +60,8 @@ type Backend interface {
|
||||
CreateCommunity(tenantID string, in *Community) (*Community, error)
|
||||
UpdateCommunity(tenantID, id string, patch *CommunityPatch) (*Community, error)
|
||||
DeleteCommunity(tenantID, id string) error
|
||||
// ListCommunityPrefixes returns unique prefixes tagged with community from latest revision per module.
|
||||
ListCommunityPrefixes(tenantID, communityID, cursor string, limit int) (prefixes []PrefixRow, nextCursor string, hasMore bool, err error)
|
||||
|
||||
// ListPeers returns all BGP peers for a tenant (control plane may paginate in httpapi).
|
||||
ListPeers(tenantID string) []*BGPPeer
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -593,6 +595,74 @@ func (m *Memory) GetCommunity(tenantID, id string) (*Community, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (m *Memory) ListCommunityPrefixes(tenantID, communityID, cursor string, limit int) ([]PrefixRow, string, bool, error) {
|
||||
if _, err := m.GetCommunity(tenantID, communityID); err != nil {
|
||||
return nil, "", false, err
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 500
|
||||
}
|
||||
if limit > 5000 {
|
||||
limit = 5000
|
||||
}
|
||||
off := 0
|
||||
if cursor != "" {
|
||||
if n, err := strconv.Atoi(cursor); err == nil && n >= 0 {
|
||||
off = n
|
||||
}
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
latestByModule := map[string]*Revision{}
|
||||
for _, rev := range m.revisions {
|
||||
if rev.TenantID != tenantID || strings.TrimSpace(rev.ModuleID) == "" {
|
||||
continue
|
||||
}
|
||||
cur := latestByModule[rev.ModuleID]
|
||||
if cur == nil || rev.CreatedAt.After(cur.CreatedAt) {
|
||||
latestByModule[rev.ModuleID] = rev
|
||||
}
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
var all []PrefixRow
|
||||
comm := communityID
|
||||
for _, rev := range latestByModule {
|
||||
for _, pr := range m.revPrefixes[rev.ID] {
|
||||
if pr.CommunityID == nil || *pr.CommunityID != communityID {
|
||||
continue
|
||||
}
|
||||
pfx := strings.TrimSpace(pr.Prefix)
|
||||
if pfx == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[pfx]; ok {
|
||||
continue
|
||||
}
|
||||
seen[pfx] = struct{}{}
|
||||
all = append(all, PrefixRow{Prefix: pfx, CommunityID: &comm, Source: pr.Source})
|
||||
}
|
||||
}
|
||||
sort.Slice(all, func(i, j int) bool { return all[i].Prefix < all[j].Prefix })
|
||||
if off > len(all) {
|
||||
return nil, "", false, nil
|
||||
}
|
||||
end := off + limit
|
||||
more := false
|
||||
next := ""
|
||||
if end < len(all) {
|
||||
more = true
|
||||
next = strconv.Itoa(end)
|
||||
all = all[off:end]
|
||||
} else {
|
||||
all = all[off:]
|
||||
}
|
||||
if len(all) == 0 {
|
||||
return nil, "", false, nil
|
||||
}
|
||||
return all, next, more, nil
|
||||
}
|
||||
|
||||
func (m *Memory) CreateCommunity(tenantID string, in *Community) (*Community, error) {
|
||||
if in == nil || strings.TrimSpace(in.Community) == "" {
|
||||
return nil, ErrInvalidInput
|
||||
|
||||
Reference in New Issue
Block a user