A community based topic aggregation platform built on atproto
at main 2.6 kB view raw
1package discover 2 3import ( 4 "Coves/internal/api/handlers/common" 5 "Coves/internal/core/discover" 6 "Coves/internal/core/posts" 7 "Coves/internal/core/votes" 8 "encoding/json" 9 "log" 10 "net/http" 11 "strconv" 12) 13 14// GetDiscoverHandler handles discover feed retrieval 15type GetDiscoverHandler struct { 16 service discover.Service 17 voteService votes.Service 18} 19 20// NewGetDiscoverHandler creates a new discover handler 21func NewGetDiscoverHandler(service discover.Service, voteService votes.Service) *GetDiscoverHandler { 22 return &GetDiscoverHandler{ 23 service: service, 24 voteService: voteService, 25 } 26} 27 28// HandleGetDiscover retrieves posts from all communities (public feed) 29// GET /xrpc/social.coves.feed.getDiscover?sort=hot&limit=15&cursor=... 30// Public endpoint with optional auth - if authenticated, includes viewer vote state 31func (h *GetDiscoverHandler) HandleGetDiscover(w http.ResponseWriter, r *http.Request) { 32 if r.Method != http.MethodGet { 33 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) 34 return 35 } 36 37 // Parse query parameters 38 req := h.parseRequest(r) 39 40 // Get discover feed 41 response, err := h.service.GetDiscover(r.Context(), req) 42 if err != nil { 43 handleServiceError(w, err) 44 return 45 } 46 47 // Populate viewer vote state if authenticated 48 common.PopulateViewerVoteState(r.Context(), r, h.voteService, response.Feed) 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.Printf("ERROR: Failed to encode discover response: %v", err) 62 } 63} 64 65// parseRequest parses query parameters into GetDiscoverRequest 66func (h *GetDiscoverHandler) parseRequest(r *http.Request) discover.GetDiscoverRequest { 67 req := discover.GetDiscoverRequest{} 68 69 // Optional: sort (default: hot) 70 req.Sort = r.URL.Query().Get("sort") 71 if req.Sort == "" { 72 req.Sort = "hot" 73 } 74 75 // Optional: timeframe (default: day for top sort) 76 req.Timeframe = r.URL.Query().Get("timeframe") 77 if req.Timeframe == "" && req.Sort == "top" { 78 req.Timeframe = "day" 79 } 80 81 // Optional: limit (default: 15, max: 50) 82 req.Limit = 15 83 if limitStr := r.URL.Query().Get("limit"); limitStr != "" { 84 if limit, err := strconv.Atoi(limitStr); err == nil { 85 req.Limit = limit 86 } 87 } 88 89 // Optional: cursor 90 if cursor := r.URL.Query().Get("cursor"); cursor != "" { 91 req.Cursor = &cursor 92 } 93 94 return req 95}