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}