1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package web
4
5import (
6 "context"
7 "net/http"
8 "strconv"
9
10 "bnema.dev/ermite/internal/domain"
11 "bnema.dev/ermite/internal/ports"
12)
13
14// The writes of the issue pages follow those of the merge request pages
15// (mr_post.go): each is a POST that passed the gate (an Origin of this site
16// and the owner's session), calls the use case as the owner and answers 303
17// to the page that shows the result, "Cache-Control: no-store".
18
19// issueAction wraps a POST handler like mrAction does.
20func (s *Server) issueAction(h func(ctx context.Context, r *http.Request) (to string, back string, err error)) http.HandlerFunc {
21 return s.mrAction(h)
22}
23
24// issueCreate is POST /<repo>/issues: it opens an issue.
25func (s *Server) issueCreate(ctx context.Context, r *http.Request) (string, string, error) {
26 repo := r.PathValue("repo")
27 back := issuesBase(repo) + "/new"
28 name, err := domain.ParseRepoName(repo)
29 if err != nil {
30 return "", back, err
31 }
32 i, err := s.cfg.Issues.Create(ctx, principal(ctx), name, ports.CreateIssueParams{
33 Title: r.PostFormValue("title"), Body: normalizeNewlines(r.PostFormValue("body")),
34 })
35 if err != nil {
36 return "", back, err
37 }
38 return issueHref(repo, i.Number), back, nil
39}
40
41// issueComment is POST /<repo>/issues/<n>/comments.
42func (s *Server) issueComment(ctx context.Context, r *http.Request) (string, string, error) {
43 repo := r.PathValue("repo")
44 n, err := number(r)
45 if err != nil {
46 return "", "", err
47 }
48 back := issueHref(repo, n)
49 name, err := domain.ParseRepoName(repo)
50 if err != nil {
51 return "", back, err
52 }
53 c, err := s.cfg.Issues.AddComment(ctx, principal(ctx), name, n, normalizeNewlines(r.PostFormValue("text")))
54 if err != nil {
55 return "", back, err
56 }
57 return back + "#c" + strconv.FormatInt(c.ID, 10), back, nil
58}
59
60// issueClose is POST /<repo>/issues/<n>/close.
61func (s *Server) issueClose(ctx context.Context, r *http.Request) (string, string, error) {
62 return s.issueTransition(ctx, r, s.cfg.Issues.Close)
63}
64
65// issueReopen is POST /<repo>/issues/<n>/reopen.
66func (s *Server) issueReopen(ctx context.Context, r *http.Request) (string, string, error) {
67 return s.issueTransition(ctx, r, s.cfg.Issues.Reopen)
68}
69
70//hexcheck:ignore suspicious-business-logic-in-adapter closes or reopens through the use case that owns the transition; the form only picks which
71func (s *Server) issueTransition(ctx context.Context, r *http.Request, do func(context.Context, domain.Principal, domain.RepoName, int64) (domain.Issue, error)) (string, string, error) {
72 repo := r.PathValue("repo")
73 n, err := number(r)
74 if err != nil {
75 return "", "", err
76 }
77 back := issueHref(repo, n)
78 name, err := domain.ParseRepoName(repo)
79 if err != nil {
80 return "", back, err
81 }
82 if _, err := do(ctx, principal(ctx), name, n); err != nil {
83 return "", back, err
84 }
85 return back, back, nil
86}