···
7
+
"Coves/internal/core/communities"
10
+
// SubscribeHandler handles community subscriptions
11
+
type SubscribeHandler struct {
12
+
service communities.Service
15
+
// NewSubscribeHandler creates a new subscribe handler
16
+
func NewSubscribeHandler(service communities.Service) *SubscribeHandler {
17
+
return &SubscribeHandler{
22
+
// HandleSubscribe subscribes a user to a community
23
+
// POST /xrpc/social.coves.community.subscribe
24
+
// Body: { "community": "did:plc:xxx" or "!gaming@coves.social" }
25
+
func (h *SubscribeHandler) HandleSubscribe(w http.ResponseWriter, r *http.Request) {
26
+
if r.Method != http.MethodPost {
27
+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
31
+
// Parse request body
33
+
Community string `json:"community"`
36
+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
37
+
writeError(w, http.StatusBadRequest, "InvalidRequest", "Invalid request body")
41
+
if req.Community == "" {
42
+
writeError(w, http.StatusBadRequest, "InvalidRequest", "community is required")
46
+
// TODO(Communities-OAuth): Extract authenticated user DID from request context
47
+
// This MUST be replaced with OAuth middleware before production deployment
48
+
// Expected implementation:
49
+
// userDID := r.Context().Value("authenticated_user_did").(string)
50
+
// For now, we read from header (INSECURE - allows impersonation)
51
+
userDID := r.Header.Get("X-User-DID")
53
+
writeError(w, http.StatusUnauthorized, "AuthRequired", "Authentication required")
57
+
// Subscribe via service (write-forward to PDS)
58
+
subscription, err := h.service.SubscribeToCommunity(r.Context(), userDID, req.Community)
60
+
handleServiceError(w, err)
64
+
// Return success response
65
+
response := map[string]interface{}{
66
+
"uri": subscription.RecordURI,
67
+
"cid": subscription.RecordCID,
68
+
"existing": false, // Would be true if already subscribed
71
+
w.Header().Set("Content-Type", "application/json")
72
+
w.WriteHeader(http.StatusOK)
73
+
json.NewEncoder(w).Encode(response)
76
+
// HandleUnsubscribe unsubscribes a user from a community
77
+
// POST /xrpc/social.coves.community.unsubscribe
78
+
// Body: { "community": "did:plc:xxx" or "!gaming@coves.social" }
79
+
func (h *SubscribeHandler) HandleUnsubscribe(w http.ResponseWriter, r *http.Request) {
80
+
if r.Method != http.MethodPost {
81
+
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
85
+
// Parse request body
87
+
Community string `json:"community"`
90
+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
91
+
writeError(w, http.StatusBadRequest, "InvalidRequest", "Invalid request body")
95
+
if req.Community == "" {
96
+
writeError(w, http.StatusBadRequest, "InvalidRequest", "community is required")
100
+
// TODO(Communities-OAuth): Extract authenticated user DID from request context
101
+
// This MUST be replaced with OAuth middleware before production deployment
102
+
// Expected implementation:
103
+
// userDID := r.Context().Value("authenticated_user_did").(string)
104
+
// For now, we read from header (INSECURE - allows impersonation)
105
+
userDID := r.Header.Get("X-User-DID")
107
+
writeError(w, http.StatusUnauthorized, "AuthRequired", "Authentication required")
111
+
// Unsubscribe via service (delete record on PDS)
112
+
err := h.service.UnsubscribeFromCommunity(r.Context(), userDID, req.Community)
114
+
handleServiceError(w, err)
118
+
// Return success response
119
+
w.Header().Set("Content-Type", "application/json")
120
+
w.WriteHeader(http.StatusOK)
121
+
json.NewEncoder(w).Encode(map[string]interface{}{