vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Render the styled error page for every miss and failure
e84a66f5b53c269d8b0c207d0335b537e1646cb3 · Keenan Nemetz · 15d ago · parent f6f4b1db
Render the styled error page for every miss and failure Handler-level 404s now use the same view as the catch-all, including unknown detail resources and download paths. Internal 500s render the shared error layout and log the detail instead of exposing it. A panic before the first byte is recovered into that page; a partial response is left to net/http. Also mark label/assignee triage and inline review comments done in the UI plan, where the slice order was stale.
server/web/writes.go +19−19
| @@ -65,7 +65,7 @@ func (w *Web) CreateIssue(rw http.ResponseWriter, r *http.Request) { | |||
| 65 | 65 | return | |
| 66 | 66 | } | |
| 67 | 67 | if err := metadata.CreateIssue(m.Git(), iss, pr.account.Name); err != nil { | |
| 68 | http.Error(rw, "cannot create the issue: "+err.Error(), http.StatusInternalServerError) | ||
| 68 | w.serverError(rw, r, "cannot create the issue: "+err.Error()) | ||
| 69 | 69 | return | |
| 70 | 70 | } | |
| 71 | 71 | w.audit("web.issue.create", pr.account.ID, m.Name+" "+iss.ID) | |
| @@ -95,7 +95,7 @@ func (w *Web) SetIssueLabels(rw http.ResponseWriter, r *http.Request) { | |||
| 95 | 95 | id := r.PathValue("id") | |
| 96 | 96 | iss, err := index.LoadIssue(m, id) | |
| 97 | 97 | if err != nil { | |
| 98 | http.NotFound(rw, r) | ||
| 98 | w.notFound(rw, r) | ||
| 99 | 99 | return | |
| 100 | 100 | } | |
| 101 | 101 | acl, err := m.ACL() | |
| @@ -156,7 +156,7 @@ func (w *Web) SetIssueAssignees(rw http.ResponseWriter, r *http.Request) { | |||
| 156 | 156 | id := r.PathValue("id") | |
| 157 | 157 | iss, err := index.LoadIssue(m, id) | |
| 158 | 158 | if err != nil { | |
| 159 | http.NotFound(rw, r) | ||
| 159 | w.notFound(rw, r) | ||
| 160 | 160 | return | |
| 161 | 161 | } | |
| 162 | 162 | acl, err := m.ACL() | |
| @@ -231,7 +231,7 @@ func (w *Web) AddIssueComment(rw http.ResponseWriter, r *http.Request) { | |||
| 231 | 231 | id := r.PathValue("id") | |
| 232 | 232 | iss, err := index.LoadIssue(m, id) | |
| 233 | 233 | if err != nil { | |
| 234 | http.NotFound(rw, r) | ||
| 234 | w.notFound(rw, r) | ||
| 235 | 235 | return | |
| 236 | 236 | } | |
| 237 | 237 | if err := r.ParseForm(); err != nil { | |
| @@ -330,12 +330,12 @@ func (w *Web) EditIssueComment(rw http.ResponseWriter, r *http.Request) { | |||
| 330 | 330 | id, commentID := r.PathValue("id"), r.PathValue("comment") | |
| 331 | 331 | iss, err := index.LoadIssue(m, id) | |
| 332 | 332 | if err != nil { | |
| 333 | http.NotFound(rw, r) | ||
| 333 | w.notFound(rw, r) | ||
| 334 | 334 | return | |
| 335 | 335 | } | |
| 336 | 336 | c := issueCommentByID(iss, commentID) | |
| 337 | 337 | if c == nil { | |
| 338 | http.NotFound(rw, r) | ||
| 338 | w.notFound(rw, r) | ||
| 339 | 339 | return | |
| 340 | 340 | } | |
| 341 | 341 | acl, _ := m.ACL() | |
| @@ -401,12 +401,12 @@ func (w *Web) DeleteIssueComment(rw http.ResponseWriter, r *http.Request) { | |||
| 401 | 401 | id, commentID := r.PathValue("id"), r.PathValue("comment") | |
| 402 | 402 | iss, err := index.LoadIssue(m, id) | |
| 403 | 403 | if err != nil { | |
| 404 | http.NotFound(rw, r) | ||
| 404 | w.notFound(rw, r) | ||
| 405 | 405 | return | |
| 406 | 406 | } | |
| 407 | 407 | c := issueCommentByID(iss, commentID) | |
| 408 | 408 | if c == nil { | |
| 409 | http.NotFound(rw, r) | ||
| 409 | w.notFound(rw, r) | ||
| 410 | 410 | return | |
| 411 | 411 | } | |
| 412 | 412 | acl, _ := m.ACL() | |
| @@ -464,7 +464,7 @@ func (w *Web) ApproveRequest(rw http.ResponseWriter, r *http.Request) { | |||
| 464 | 464 | id := r.PathValue("id") | |
| 465 | 465 | req, err := metadata.GetRequest(m.Git(), id) | |
| 466 | 466 | if err != nil { | |
| 467 | http.NotFound(rw, r) | ||
| 467 | w.notFound(rw, r) | ||
| 468 | 468 | return | |
| 469 | 469 | } | |
| 470 | 470 | if !req.Open() { | |
| @@ -578,7 +578,7 @@ func (w *Web) CreateChangeRequest(rw http.ResponseWriter, r *http.Request) { | |||
| 578 | 578 | return | |
| 579 | 579 | } | |
| 580 | 580 | if err := metadata.CreateRequest(m.Git(), req, pr.account.Name); err != nil { | |
| 581 | http.Error(rw, "cannot open the change request: "+err.Error(), http.StatusInternalServerError) | ||
| 581 | w.serverError(rw, r, "cannot open the change request: "+err.Error()) | ||
| 582 | 582 | return | |
| 583 | 583 | } | |
| 584 | 584 | w.audit("web.request.create", pr.account.ID, m.Name+" "+req.ID+" "+headCommit) | |
| @@ -617,7 +617,7 @@ func (w *Web) ChangeIssueState(rw http.ResponseWriter, r *http.Request) { | |||
| 617 | 617 | } | |
| 618 | 618 | iss, err := index.LoadIssue(m, id) | |
| 619 | 619 | if err != nil { | |
| 620 | http.NotFound(rw, r) | ||
| 620 | w.notFound(rw, r) | ||
| 621 | 621 | return | |
| 622 | 622 | } | |
| 623 | 623 | acl, err := m.ACL() | |
| @@ -633,7 +633,7 @@ func (w *Web) ChangeIssueState(rw http.ResponseWriter, r *http.Request) { | |||
| 633 | 633 | return nil | |
| 634 | 634 | }, pr.account.Name) | |
| 635 | 635 | if err != nil && !errors.Is(err, metadata.ErrNoChange) { | |
| 636 | http.Error(rw, "cannot change the issue: "+err.Error(), http.StatusInternalServerError) | ||
| 636 | w.serverError(rw, r, "cannot change the issue: "+err.Error()) | ||
| 637 | 637 | return | |
| 638 | 638 | } | |
| 639 | 639 | w.audit("web.issue.state", pr.account.ID, m.Name+" "+id+" "+state) | |
| @@ -668,7 +668,7 @@ func (w *Web) AddRequestComment(rw http.ResponseWriter, r *http.Request) { | |||
| 668 | 668 | id := r.PathValue("id") | |
| 669 | 669 | req, err := metadata.GetRequest(m.Git(), id) | |
| 670 | 670 | if err != nil { | |
| 671 | http.NotFound(rw, r) | ||
| 671 | w.notFound(rw, r) | ||
| 672 | 672 | return | |
| 673 | 673 | } | |
| 674 | 674 | if err := r.ParseForm(); err != nil { | |
| @@ -775,12 +775,12 @@ func (w *Web) EditRequestComment(rw http.ResponseWriter, r *http.Request) { | |||
| 775 | 775 | id, commentID := r.PathValue("id"), r.PathValue("comment") | |
| 776 | 776 | req, err := metadata.GetRequest(m.Git(), id) | |
| 777 | 777 | if err != nil { | |
| 778 | http.NotFound(rw, r) | ||
| 778 | w.notFound(rw, r) | ||
| 779 | 779 | return | |
| 780 | 780 | } | |
| 781 | 781 | c := requestCommentByID(req, commentID) | |
| 782 | 782 | if c == nil { | |
| 783 | http.NotFound(rw, r) | ||
| 783 | w.notFound(rw, r) | ||
| 784 | 784 | return | |
| 785 | 785 | } | |
| 786 | 786 | acl, _ := m.ACL() | |
| @@ -846,12 +846,12 @@ func (w *Web) DeleteRequestComment(rw http.ResponseWriter, r *http.Request) { | |||
| 846 | 846 | id, commentID := r.PathValue("id"), r.PathValue("comment") | |
| 847 | 847 | req, err := metadata.GetRequest(m.Git(), id) | |
| 848 | 848 | if err != nil { | |
| 849 | http.NotFound(rw, r) | ||
| 849 | w.notFound(rw, r) | ||
| 850 | 850 | return | |
| 851 | 851 | } | |
| 852 | 852 | c := requestCommentByID(req, commentID) | |
| 853 | 853 | if c == nil { | |
| 854 | http.NotFound(rw, r) | ||
| 854 | w.notFound(rw, r) | ||
| 855 | 855 | return | |
| 856 | 856 | } | |
| 857 | 857 | acl, _ := m.ACL() | |
| @@ -907,7 +907,7 @@ func (w *Web) ChangeRequestState(rw http.ResponseWriter, r *http.Request) { | |||
| 907 | 907 | id := r.PathValue("id") | |
| 908 | 908 | req, err := metadata.GetRequest(m.Git(), id) | |
| 909 | 909 | if err != nil { | |
| 910 | http.NotFound(rw, r) | ||
| 910 | w.notFound(rw, r) | ||
| 911 | 911 | return | |
| 912 | 912 | } | |
| 913 | 913 | acl, err := m.ACL() | |
| @@ -925,7 +925,7 @@ func (w *Web) ChangeRequestState(rw http.ResponseWriter, r *http.Request) { | |||
| 925 | 925 | return | |
| 926 | 926 | } | |
| 927 | 927 | if _, err := metadata.SetRequestState(m.Git(), id, state, pr.account.Name); err != nil { | |
| 928 | http.Error(rw, "cannot change the change request: "+err.Error(), http.StatusInternalServerError) | ||
| 928 | w.serverError(rw, r, "cannot change the change request: "+err.Error()) | ||
| 929 | 929 | return | |
| 930 | 930 | } | |
| 931 | 931 | w.audit("web.request.state", pr.account.ID, m.Name+" "+id+" "+state) | |