// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/blockedemail/delete.go package blockedemail import ( "encoding/json" "net/http" "net/url" "go.uber.org/zap" "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config" "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/middleware" svc_blockedemail "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/blockedemail" "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror" "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation" ) type DeleteBlockedEmailHTTPHandler struct { config *config.Configuration logger *zap.Logger service svc_blockedemail.DeleteBlockedEmailService middleware middleware.Middleware } func NewDeleteBlockedEmailHTTPHandler( config *config.Configuration, logger *zap.Logger, service svc_blockedemail.DeleteBlockedEmailService, middleware middleware.Middleware, ) *DeleteBlockedEmailHTTPHandler { logger = logger.Named("DeleteBlockedEmailHTTPHandler") return &DeleteBlockedEmailHTTPHandler{ config: config, logger: logger, service: service, middleware: middleware, } } func (*DeleteBlockedEmailHTTPHandler) Pattern() string { return "DELETE /api/v1/me/blocked-emails/{email}" } func (h *DeleteBlockedEmailHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { h.middleware.Attach(h.Execute)(w, req) } func (h *DeleteBlockedEmailHTTPHandler) Execute(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") ctx := r.Context() // Extract email from URL path emailEncoded := r.PathValue("email") if emailEncoded == "" { httperror.RespondWithError(w, r, httperror.NewBadRequestError("Email is required")) return } // URL decode the email using PathUnescape (not QueryUnescape) // PathUnescape correctly handles %2B as + instead of treating + as space email, err := url.PathUnescape(emailEncoded) if err != nil { h.logger.Error("failed to decode email", zap.String("encoded_email", validation.MaskEmail(emailEncoded)), zap.Any("error", err)) httperror.RespondWithError(w, r, httperror.NewBadRequestError("Invalid email format")) return } h.logger.Debug("decoded email from path", zap.String("encoded", validation.MaskEmail(emailEncoded)), zap.String("decoded", validation.MaskEmail(email))) resp, err := h.service.Execute(ctx, email) if err != nil { httperror.RespondWithError(w, r, err) return } if err := json.NewEncoder(w).Encode(resp); err != nil { h.logger.Error("failed to encode response", zap.Any("error", err)) httperror.RespondWithError(w, r, err) return } }