A community based topic aggregation platform built on atproto
1package communityFeed 2 3import ( 4 "Coves/internal/core/communityFeeds" 5 "Coves/internal/core/posts" 6 "encoding/json" 7 "log" 8 "net/http" 9 "strconv" 10) 11 12// GetCommunityHandler handles community feed retrieval 13type GetCommunityHandler struct { 14 service communityFeeds.Service 15} 16 17// NewGetCommunityHandler creates a new community feed handler 18func NewGetCommunityHandler(service communityFeeds.Service) *GetCommunityHandler { 19 return &GetCommunityHandler{ 20 service: service, 21 } 22} 23 24// HandleGetCommunity retrieves posts from a community with sorting 25// GET /xrpc/social.coves.communityFeed.getCommunity?community={did_or_handle}&sort=hot&limit=15&cursor=... 26func (h *GetCommunityHandler) HandleGetCommunity(w http.ResponseWriter, r *http.Request) { 27 if r.Method != http.MethodGet { 28 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) 29 return 30 } 31 32 // Parse query parameters 33 req, err := h.parseRequest(r) 34 if err != nil { 35 writeError(w, http.StatusBadRequest, "InvalidRequest", err.Error()) 36 return 37 } 38 39 // Alpha: No viewer context needed for basic community sorting 40 // TODO(feed-generator): Extract viewer DID when implementing viewer-specific state 41 // (blocks, upvotes, saves) in feed generator skeleton 42 43 // Get community feed 44 response, err := h.service.GetCommunityFeed(r.Context(), req) 45 if err != nil { 46 handleServiceError(w, err) 47 return 48 } 49 50 // Transform blob refs to URLs for all posts 51 for _, feedPost := range response.Feed { 52 if feedPost.Post != nil { 53 posts.TransformBlobRefsToURLs(feedPost.Post) 54 } 55 } 56 57 // Return feed 58 w.Header().Set("Content-Type", "application/json") 59 w.WriteHeader(http.StatusOK) 60 if err := json.NewEncoder(w).Encode(response); err != nil { 61 // Log encoding errors but don't return error response (headers already sent) 62 log.Printf("ERROR: Failed to encode feed response: %v", err) 63 } 64} 65 66// parseRequest parses query parameters into GetCommunityFeedRequest 67func (h *GetCommunityHandler) parseRequest(r *http.Request) (communityFeeds.GetCommunityFeedRequest, error) { 68 req := communityFeeds.GetCommunityFeedRequest{} 69 70 // Required: community 71 req.Community = r.URL.Query().Get("community") 72 73 // Optional: sort (default: hot) 74 req.Sort = r.URL.Query().Get("sort") 75 if req.Sort == "" { 76 req.Sort = "hot" 77 } 78 79 // Optional: timeframe (default: day for top sort) 80 req.Timeframe = r.URL.Query().Get("timeframe") 81 if req.Timeframe == "" && req.Sort == "top" { 82 req.Timeframe = "day" 83 } 84 85 // Optional: limit (default: 15, max: 50) 86 req.Limit = 15 87 if limitStr := r.URL.Query().Get("limit"); limitStr != "" { 88 if limit, err := strconv.Atoi(limitStr); err == nil { 89 req.Limit = limit 90 } 91 } 92 93 // Optional: cursor 94 if cursor := r.URL.Query().Get("cursor"); cursor != "" { 95 req.Cursor = &cursor 96 } 97 98 return req, nil 99}