From 746d64cdbf61089d64fdca896d89d793e42a9520 Mon Sep 17 00:00:00 2001 From: Bretton Date: Wed, 15 Oct 2025 23:35:53 -0700 Subject: [PATCH] feat(communities): add update handler and XRPC endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements social.coves.community.update endpoint for updating community profiles (displayName, description, visibility, etc.). Changes: - Add UpdateHandler with XRPC endpoint support - Register update route in community routes - Uses community's own PDS credentials (V2 architecture) - Preserves OAuth TODO for production deployment Related: Update endpoint was defined in service layer but had no HTTP handler or route registration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- internal/api/handlers/community/update.go | 76 +++++++++++++++++++++++ internal/api/routes/community.go | 7 ++- 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 internal/api/handlers/community/update.go diff --git a/internal/api/handlers/community/update.go b/internal/api/handlers/community/update.go new file mode 100644 index 0000000..4720d51 --- /dev/null +++ b/internal/api/handlers/community/update.go @@ -0,0 +1,76 @@ +package community + +import ( + "Coves/internal/core/communities" + "encoding/json" + "net/http" +) + +// UpdateHandler handles community updates +type UpdateHandler struct { + service communities.Service +} + +// NewUpdateHandler creates a new update handler +func NewUpdateHandler(service communities.Service) *UpdateHandler { + return &UpdateHandler{ + service: service, + } +} + +// HandleUpdate updates an existing community +// POST /xrpc/social.coves.community.update +// Body matches UpdateCommunityRequest +func (h *UpdateHandler) HandleUpdate(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // Parse request body + var req communities.UpdateCommunityRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + writeError(w, http.StatusBadRequest, "InvalidRequest", "Invalid request body") + return + } + + // Validate required fields + if req.CommunityDID == "" { + writeError(w, http.StatusBadRequest, "InvalidRequest", "communityDid is required") + return + } + + // TODO(Communities-OAuth): Extract authenticated user DID from request context + // This MUST be replaced with OAuth middleware before production deployment + // Expected implementation: + // userDID := r.Context().Value("authenticated_user_did").(string) + // req.UpdatedByDID = userDID + // For now, we require client to send it (INSECURE - allows impersonation) + if req.UpdatedByDID == "" { + writeError(w, http.StatusUnauthorized, "AuthRequired", "Authentication required") + return + } + + // Update community via service (write-forward to PDS) + community, err := h.service.UpdateCommunity(r.Context(), req) + if err != nil { + handleServiceError(w, err) + return + } + + // Return success response matching lexicon output + response := map[string]interface{}{ + "uri": community.RecordURI, + "cid": community.RecordCID, + "did": community.DID, + "handle": community.Handle, + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + if err := json.NewEncoder(w).Encode(response); err != nil { + // Log encoding errors but don't return error response (headers already sent) + // This follows Go's standard practice for HTTP handlers + _ = err + } +} diff --git a/internal/api/routes/community.go b/internal/api/routes/community.go index 75d6fd4..fd6dbbc 100644 --- a/internal/api/routes/community.go +++ b/internal/api/routes/community.go @@ -13,6 +13,7 @@ func RegisterCommunityRoutes(r chi.Router, service communities.Service) { // Initialize handlers createHandler := community.NewCreateHandler(service) getHandler := community.NewGetHandler(service) + updateHandler := community.NewUpdateHandler(service) listHandler := community.NewListHandler(service) searchHandler := community.NewSearchHandler(service) subscribeHandler := community.NewSubscribeHandler(service) @@ -31,13 +32,15 @@ func RegisterCommunityRoutes(r chi.Router, service communities.Service) { // social.coves.community.create - create a new community r.Post("/xrpc/social.coves.community.create", createHandler.HandleCreate) + // social.coves.community.update - update an existing community + r.Post("/xrpc/social.coves.community.update", updateHandler.HandleUpdate) + // social.coves.community.subscribe - subscribe to a community r.Post("/xrpc/social.coves.community.subscribe", subscribeHandler.HandleSubscribe) // social.coves.community.unsubscribe - unsubscribe from a community r.Post("/xrpc/social.coves.community.unsubscribe", subscribeHandler.HandleUnsubscribe) - // TODO: Add update and delete handlers when implemented - // r.Post("/xrpc/social.coves.community.update", updateHandler.HandleUpdate) + // TODO: Add delete handler when implemented // r.Post("/xrpc/social.coves.community.delete", deleteHandler.HandleDelete) } -- 2.51.2