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