A community based topic aggregation platform built on atproto
1package comments
2
3import (
4 "Coves/internal/core/comments"
5 "encoding/json"
6 "errors"
7 "log"
8 "net/http"
9)
10
11// errorResponse represents a standardized JSON error response
12type errorResponse struct {
13 Error string `json:"error"`
14 Message string `json:"message"`
15}
16
17// writeError writes a JSON error response with the given status code
18func writeError(w http.ResponseWriter, statusCode int, errorType, message string) {
19 w.Header().Set("Content-Type", "application/json")
20 w.WriteHeader(statusCode)
21 if err := json.NewEncoder(w).Encode(errorResponse{
22 Error: errorType,
23 Message: message,
24 }); err != nil {
25 log.Printf("Failed to encode error response: %v", err)
26 }
27}
28
29// handleServiceError maps service-layer errors to HTTP responses
30// This follows the error handling pattern from other handlers (post, community)
31func handleServiceError(w http.ResponseWriter, err error) {
32 switch {
33 case comments.IsNotFound(err):
34 // Map specific not found errors to appropriate messages
35 switch {
36 case errors.Is(err, comments.ErrCommentNotFound):
37 writeError(w, http.StatusNotFound, "CommentNotFound", "Comment not found")
38 case errors.Is(err, comments.ErrParentNotFound):
39 writeError(w, http.StatusNotFound, "ParentNotFound", "Parent post or comment not found")
40 case errors.Is(err, comments.ErrRootNotFound):
41 writeError(w, http.StatusNotFound, "RootNotFound", "Root post not found")
42 default:
43 writeError(w, http.StatusNotFound, "NotFound", err.Error())
44 }
45
46 case comments.IsValidationError(err):
47 // Map specific validation errors to appropriate messages
48 switch {
49 case errors.Is(err, comments.ErrInvalidReply):
50 writeError(w, http.StatusBadRequest, "InvalidReply", "The reply reference is invalid or malformed")
51 case errors.Is(err, comments.ErrContentTooLong):
52 writeError(w, http.StatusBadRequest, "ContentTooLong", "Comment content exceeds 10000 graphemes")
53 case errors.Is(err, comments.ErrContentEmpty):
54 writeError(w, http.StatusBadRequest, "ContentEmpty", "Comment content is required")
55 default:
56 writeError(w, http.StatusBadRequest, "InvalidRequest", err.Error())
57 }
58
59 case errors.Is(err, comments.ErrNotAuthorized):
60 writeError(w, http.StatusForbidden, "NotAuthorized", "User is not authorized to perform this action")
61
62 case errors.Is(err, comments.ErrBanned):
63 writeError(w, http.StatusForbidden, "Banned", "User is banned from this community")
64
65 // NOTE: IsConflict case removed - the PDS handles duplicate detection via CreateRecord,
66 // so ErrCommentAlreadyExists is never returned from the service layer. If the PDS rejects
67 // a duplicate record, it returns an auth/validation error which is handled by other cases.
68 // Keeping this code would be dead code that never executes.
69
70 default:
71 // Don't leak internal error details to clients
72 log.Printf("Unexpected error in comments handler: %v", err)
73 writeError(w, http.StatusInternalServerError, "InternalServerError",
74 "An internal error occurred")
75 }
76}