A community based topic aggregation platform built on atproto
1package discover 2 3import ( 4 "Coves/internal/core/discover" 5 "Coves/internal/core/posts" 6 "encoding/json" 7 "log" 8 "net/http" 9 "strconv" 10) 11 12// GetDiscoverHandler handles discover feed retrieval 13type GetDiscoverHandler struct { 14 service discover.Service 15} 16 17// NewGetDiscoverHandler creates a new discover handler 18func NewGetDiscoverHandler(service discover.Service) *GetDiscoverHandler { 19 return &GetDiscoverHandler{ 20 service: service, 21 } 22} 23 24// HandleGetDiscover retrieves posts from all communities (public feed) 25// GET /xrpc/social.coves.feed.getDiscover?sort=hot&limit=15&cursor=... 26// Public endpoint - no authentication required 27func (h *GetDiscoverHandler) HandleGetDiscover(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 := h.parseRequest(r) 35 36 // Get discover feed 37 response, err := h.service.GetDiscover(r.Context(), req) 38 if err != nil { 39 handleServiceError(w, err) 40 return 41 } 42 43 // Transform blob refs to URLs for all posts 44 for _, feedPost := range response.Feed { 45 if feedPost.Post != nil { 46 posts.TransformBlobRefsToURLs(feedPost.Post) 47 } 48 } 49 50 // Return feed 51 w.Header().Set("Content-Type", "application/json") 52 w.WriteHeader(http.StatusOK) 53 if err := json.NewEncoder(w).Encode(response); err != nil { 54 log.Printf("ERROR: Failed to encode discover response: %v", err) 55 } 56} 57 58// parseRequest parses query parameters into GetDiscoverRequest 59func (h *GetDiscoverHandler) parseRequest(r *http.Request) discover.GetDiscoverRequest { 60 req := discover.GetDiscoverRequest{} 61 62 // Optional: sort (default: hot) 63 req.Sort = r.URL.Query().Get("sort") 64 if req.Sort == "" { 65 req.Sort = "hot" 66 } 67 68 // Optional: timeframe (default: day for top sort) 69 req.Timeframe = r.URL.Query().Get("timeframe") 70 if req.Timeframe == "" && req.Sort == "top" { 71 req.Timeframe = "day" 72 } 73 74 // Optional: limit (default: 15, max: 50) 75 req.Limit = 15 76 if limitStr := r.URL.Query().Get("limit"); limitStr != "" { 77 if limit, err := strconv.Atoi(limitStr); err == nil { 78 req.Limit = limit 79 } 80 } 81 82 // Optional: cursor 83 if cursor := r.URL.Query().Get("cursor"); cursor != "" { 84 req.Cursor = &cursor 85 } 86 87 return req 88}