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}