A community based topic aggregation platform built on atproto
at main 3.0 kB view raw
1package community 2 3import ( 4 "Coves/internal/core/communities" 5 "encoding/json" 6 "net/http" 7 "strconv" 8) 9 10// ListHandler handles listing communities 11type ListHandler struct { 12 service communities.Service 13} 14 15// NewListHandler creates a new list handler 16func NewListHandler(service communities.Service) *ListHandler { 17 return &ListHandler{ 18 service: service, 19 } 20} 21 22// HandleList lists communities with filters 23// GET /xrpc/social.coves.community.list?limit={n}&cursor={str}&sort={popular|active|new|alphabetical}&visibility={public|unlisted|private} 24func (h *ListHandler) HandleList(w http.ResponseWriter, r *http.Request) { 25 if r.Method != http.MethodGet { 26 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) 27 return 28 } 29 30 // Parse query parameters 31 query := r.URL.Query() 32 33 // Parse limit (1-100, default 50) 34 limit := 50 35 if limitStr := query.Get("limit"); limitStr != "" { 36 if l, err := strconv.Atoi(limitStr); err == nil { 37 if l < 1 { 38 limit = 1 39 } else if l > 100 { 40 limit = 100 41 } else { 42 limit = l 43 } 44 } 45 } 46 47 // Parse cursor (offset-based for now) 48 offset := 0 49 if cursorStr := query.Get("cursor"); cursorStr != "" { 50 if o, err := strconv.Atoi(cursorStr); err == nil && o >= 0 { 51 offset = o 52 } 53 } 54 55 // Parse sort enum (default: popular) 56 sort := query.Get("sort") 57 if sort == "" { 58 sort = "popular" 59 } 60 61 // Validate sort value 62 validSorts := map[string]bool{ 63 "popular": true, 64 "active": true, 65 "new": true, 66 "alphabetical": true, 67 } 68 if !validSorts[sort] { 69 http.Error(w, "Invalid sort value. Must be: popular, active, new, or alphabetical", http.StatusBadRequest) 70 return 71 } 72 73 // Validate visibility value if provided 74 visibility := query.Get("visibility") 75 if visibility != "" { 76 validVisibilities := map[string]bool{ 77 "public": true, 78 "unlisted": true, 79 "private": true, 80 } 81 if !validVisibilities[visibility] { 82 http.Error(w, "Invalid visibility value. Must be: public, unlisted, or private", http.StatusBadRequest) 83 return 84 } 85 } 86 87 req := communities.ListCommunitiesRequest{ 88 Limit: limit, 89 Offset: offset, 90 Sort: sort, 91 Visibility: visibility, 92 Category: query.Get("category"), 93 Language: query.Get("language"), 94 } 95 96 // Get communities from AppView DB 97 results, err := h.service.ListCommunities(r.Context(), req) 98 if err != nil { 99 handleServiceError(w, err) 100 return 101 } 102 103 // Build response 104 var cursor string 105 if len(results) == limit { 106 // More results available - return next cursor 107 cursor = strconv.Itoa(offset + len(results)) 108 } 109 // If len(results) < limit, we've reached the end - cursor remains empty string 110 111 response := map[string]interface{}{ 112 "communities": results, 113 "cursor": cursor, 114 } 115 116 w.Header().Set("Content-Type", "application/json") 117 w.WriteHeader(http.StatusOK) 118 if err := json.NewEncoder(w).Encode(response); err != nil { 119 // Log encoding errors but don't return error response (headers already sent) 120 // This follows Go's standard practice for HTTP handlers 121 _ = err 122 } 123}