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
70func (s *Server) issueTransition(ctx context.Context, r *http.Request, do func(context.Context, domain.Principal, domain.RepoName, int64) (domain.Issue, error)) (string, string, error) {
71 repo := r.PathValue("repo")
72 n, err := number(r)
73 if err != nil {
74 return "", "", err
75 }
76 back := issueHref(repo, n)
77 name, err := domain.ParseRepoName(repo)
78 if err != nil {
79 return "", back, err
80 }
81 if _, err := do(ctx, principal(ctx), name, n); err != nil {
82 return "", back, err
83 }
84 return back, back, nil
85}