A community based topic aggregation platform built on atproto
1package comments
2
3import (
4 "Coves/internal/api/middleware"
5 "Coves/internal/core/comments"
6 "encoding/json"
7 "log"
8 "net/http"
9)
10
11// UpdateCommentHandler handles comment update requests
12type UpdateCommentHandler struct {
13 service comments.Service
14}
15
16// NewUpdateCommentHandler creates a new handler for updating comments
17func NewUpdateCommentHandler(service comments.Service) *UpdateCommentHandler {
18 return &UpdateCommentHandler{
19 service: service,
20 }
21}
22
23// UpdateCommentInput matches the lexicon input schema for social.coves.community.comment.update
24type UpdateCommentInput struct {
25 URI string `json:"uri"`
26 Content string `json:"content"`
27 Facets []interface{} `json:"facets,omitempty"`
28 Embed interface{} `json:"embed,omitempty"`
29 Langs []string `json:"langs,omitempty"`
30 Labels interface{} `json:"labels,omitempty"`
31}
32
33// UpdateCommentOutput matches the lexicon output schema
34type UpdateCommentOutput struct {
35 URI string `json:"uri"`
36 CID string `json:"cid"`
37}
38
39// HandleUpdate handles comment update requests
40// POST /xrpc/social.coves.community.comment.update
41//
42// Request body: { "uri": "at://...", "content": "..." }
43// Response: { "uri": "at://...", "cid": "..." }
44func (h *UpdateCommentHandler) HandleUpdate(w http.ResponseWriter, r *http.Request) {
45 // 1. Check method is POST
46 if r.Method != http.MethodPost {
47 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
48 return
49 }
50
51 // 2. Limit request body size to prevent DoS attacks (100KB should be plenty for comments)
52 r.Body = http.MaxBytesReader(w, r.Body, 100*1024)
53
54 // 3. Parse JSON body into UpdateCommentInput
55 var input UpdateCommentInput
56 if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
57 writeError(w, http.StatusBadRequest, "InvalidRequest", "Invalid request body")
58 return
59 }
60
61 // 4. Get OAuth session from context (injected by auth middleware)
62 session := middleware.GetOAuthSession(r)
63 if session == nil {
64 writeError(w, http.StatusUnauthorized, "AuthRequired", "Authentication required")
65 return
66 }
67
68 // 5. Convert labels interface{} to *comments.SelfLabels if provided
69 var labels *comments.SelfLabels
70 if input.Labels != nil {
71 labelsJSON, err := json.Marshal(input.Labels)
72 if err != nil {
73 writeError(w, http.StatusBadRequest, "InvalidLabels", "Invalid labels format")
74 return
75 }
76 var selfLabels comments.SelfLabels
77 if err := json.Unmarshal(labelsJSON, &selfLabels); err != nil {
78 writeError(w, http.StatusBadRequest, "InvalidLabels", "Invalid labels structure")
79 return
80 }
81 labels = &selfLabels
82 }
83
84 // 6. Convert input to UpdateCommentRequest
85 req := comments.UpdateCommentRequest{
86 URI: input.URI,
87 Content: input.Content,
88 Facets: input.Facets,
89 Embed: input.Embed,
90 Langs: input.Langs,
91 Labels: labels,
92 }
93
94 // 7. Call service to update comment
95 response, err := h.service.UpdateComment(r.Context(), session, req)
96 if err != nil {
97 handleServiceError(w, err)
98 return
99 }
100
101 // 8. Return JSON response with URI and CID
102 output := UpdateCommentOutput{
103 URI: response.URI,
104 CID: response.CID,
105 }
106
107 w.Header().Set("Content-Type", "application/json")
108 w.WriteHeader(http.StatusOK)
109 if err := json.NewEncoder(w).Encode(output); err != nil {
110 log.Printf("Failed to encode response: %v", err)
111 }
112}