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)
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 // 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 encoding errors but don't return error response (headers already sent)
55 log.Printf("ERROR: Failed to encode feed response: %v", err)
56 }
57}
58
59// parseRequest parses query parameters into GetCommunityFeedRequest
60func (h *GetCommunityHandler) parseRequest(r *http.Request) (communityFeeds.GetCommunityFeedRequest, error) {
61 req := communityFeeds.GetCommunityFeedRequest{}
62
63 // Required: community
64 req.Community = r.URL.Query().Get("community")
65
66 // Optional: sort (default: hot)
67 req.Sort = r.URL.Query().Get("sort")
68 if req.Sort == "" {
69 req.Sort = "hot"
70 }
71
72 // Optional: timeframe (default: day for top sort)
73 req.Timeframe = r.URL.Query().Get("timeframe")
74 if req.Timeframe == "" && req.Sort == "top" {
75 req.Timeframe = "day"
76 }
77
78 // Optional: limit (default: 15, max: 50)
79 req.Limit = 15
80 if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
81 if limit, err := strconv.Atoi(limitStr); err == nil {
82 req.Limit = limit
83 }
84 }
85
86 // Optional: cursor
87 if cursor := r.URL.Query().Get("cursor"); cursor != "" {
88 req.Cursor = &cursor
89 }
90
91 return req, nil
92}