diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 2530c7d..516d7a1 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -55,6 +55,7 @@ func (h *Handler) RegisterRoutes(mux *http.ServeMux) { mux.HandleFunc("GET /pulls", h.ListPulls) mux.HandleFunc("GET /pulls/{owner}/{repo}/{index}", h.PullDetail) mux.HandleFunc("POST /pulls/{owner}/{repo}/{index}/review", h.SubmitReview) + mux.HandleFunc("POST /pulls/{owner}/{repo}/{index}/state", h.SetPullState) // Settings (handled separately for auth bypass). settingsHandler := &SettingsHandler{ @@ -886,6 +887,53 @@ func (h *Handler) SetIssueState(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, fmt.Sprintf("/issues/%s/%s/%d", owner, repo, index), http.StatusSeeOther) } +// SetPullState handles POST /pulls/{owner}/{repo}/{index}/state. +func (h *Handler) SetPullState(w http.ResponseWriter, r *http.Request) { + token := getToken(r) + owner := r.PathValue("owner") + repo := r.PathValue("repo") + indexStr := r.PathValue("index") + + index, err := strconv.ParseInt(indexStr, 10, 64) + if err != nil { + http.Error(w, "invalid pull request index", http.StatusBadRequest) + return + } + + if err := r.ParseForm(); err != nil { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + + state := r.FormValue("state") + if state != "open" && state != "closed" { + http.Error(w, "state must be 'open' or 'closed'", http.StatusBadRequest) + return + } + + if err := h.Client.SetIssueState(r.Context(), token, owner, repo, index, state); err != nil { + slog.Error("failed to set pull request state", "error", err, "owner", owner, "repo", repo, "index", index, "state", state) + http.Error(w, "failed to update pull request state", http.StatusInternalServerError) + return + } + + if isHTMX(r) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + if state == "closed" { + fmt.Fprintf(w, `closed +`, + template.HTMLEscapeString(owner), template.HTMLEscapeString(repo), index) + } else { + fmt.Fprintf(w, `open +`, + template.HTMLEscapeString(owner), template.HTMLEscapeString(repo), index) + } + return + } + + http.Redirect(w, r, fmt.Sprintf("/pulls/%s/%s/%d", owner, repo, index), http.StatusSeeOther) +} + // AddComment handles POST /issues/{owner}/{repo}/{index}/comment. func (h *Handler) AddComment(w http.ResponseWriter, r *http.Request) { token := getToken(r) diff --git a/internal/templates/pull_detail.html b/internal/templates/pull_detail.html index 773675e..0d3aff8 100644 --- a/internal/templates/pull_detail.html +++ b/internal/templates/pull_detail.html @@ -4,7 +4,7 @@