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}