A community based topic aggregation platform built on atproto
at main 104 lines 3.0 kB view raw
1package post 2 3import ( 4 "Coves/internal/api/middleware" 5 "Coves/internal/core/posts" 6 "encoding/json" 7 "errors" 8 "log" 9 "net/http" 10) 11 12// DeleteHandler handles post deletion requests 13type DeleteHandler struct { 14 service posts.Service 15} 16 17// NewDeleteHandler creates a new handler for deleting posts 18func NewDeleteHandler(service posts.Service) *DeleteHandler { 19 return &DeleteHandler{ 20 service: service, 21 } 22} 23 24// DeletePostInput matches the lexicon input schema for social.coves.community.post.delete 25type DeletePostInput struct { 26 URI string `json:"uri"` 27} 28 29// DeletePostOutput is empty per lexicon specification 30type DeletePostOutput struct{} 31 32// HandleDelete handles post deletion requests 33// POST /xrpc/social.coves.community.post.delete 34// 35// Request body: { "uri": "at://..." } 36// Response: {} 37func (h *DeleteHandler) HandleDelete(w http.ResponseWriter, r *http.Request) { 38 // 1. Check method is POST 39 if r.Method != http.MethodPost { 40 http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) 41 return 42 } 43 44 // 2. Limit request body size to prevent DoS attacks (100KB should be plenty for delete requests) 45 r.Body = http.MaxBytesReader(w, r.Body, 100*1024) 46 47 // 3. Parse JSON body into DeletePostInput 48 var input DeletePostInput 49 if err := json.NewDecoder(r.Body).Decode(&input); err != nil { 50 writeError(w, http.StatusBadRequest, "InvalidRequest", "Invalid request body") 51 return 52 } 53 54 // 4. Get OAuth session from context (injected by auth middleware) 55 session := middleware.GetOAuthSession(r) 56 if session == nil { 57 writeError(w, http.StatusUnauthorized, "AuthRequired", "Authentication required") 58 return 59 } 60 61 // 5. Convert input to DeletePostRequest 62 req := posts.DeletePostRequest{ 63 URI: input.URI, 64 } 65 66 // 6. Call service to delete post 67 err := h.service.DeletePost(r.Context(), session, req) 68 if err != nil { 69 handleDeleteError(w, err) 70 return 71 } 72 73 // 7. Return empty JSON object per lexicon specification 74 output := DeletePostOutput{} 75 76 w.Header().Set("Content-Type", "application/json") 77 w.WriteHeader(http.StatusOK) 78 if err := json.NewEncoder(w).Encode(output); err != nil { 79 log.Printf("Failed to encode response: %v", err) 80 } 81} 82 83// handleDeleteError maps delete-specific service errors to HTTP responses 84func handleDeleteError(w http.ResponseWriter, err error) { 85 switch { 86 case errors.Is(err, posts.ErrNotFound): 87 writeError(w, http.StatusNotFound, "PostNotFound", "Post not found") 88 89 case errors.Is(err, posts.ErrNotAuthorized): 90 writeError(w, http.StatusForbidden, "NotAuthorized", "You are not authorized to delete this post") 91 92 case errors.Is(err, posts.ErrCommunityNotFound): 93 writeError(w, http.StatusNotFound, "CommunityNotFound", "Community not found") 94 95 case posts.IsValidationError(err): 96 writeError(w, http.StatusBadRequest, "InvalidRequest", err.Error()) 97 98 default: 99 // Don't leak internal error details to clients 100 log.Printf("Unexpected error in post delete handler: %v", err) 101 writeError(w, http.StatusInternalServerError, "InternalServerError", 102 "An internal error occurred") 103 } 104}