main / internal/interface/web/issue_handler.go
3.8 KB · Go Raw
1package web
2
3import (
4 "errors"
5 "net/http"
6 "strconv"
7 "strings"
8
9 "github.com/go-chi/chi"
10
11 "gitgud/internal/app"
12 "gitgud/internal/domain"
13 "gitgud/internal/interface/web/templates"
14)
15
16func (h *Handlers) issuesList(w http.ResponseWriter, r *http.Request) {
17 repo := h.viewRepo(w, r)
18 if repo == nil {
19 return
20 }
21
22 state := r.URL.Query().Get("state")
23 var filter domain.IssueState
24 switch state {
25 case "closed":
26 filter = domain.IssueClosed
27 case "all":
28 filter = ""
29 default:
30 state = "open"
31 filter = domain.IssueOpen
32 }
33
34 issues, err := h.issues.List(r.Context(), repo.ID, filter)
35 if err != nil {
36 h.writeError(w, r, err)
37 return
38 }
39 open, closed, err := h.issues.Counts(r.Context(), repo.ID)
40 if err != nil {
41 h.writeError(w, r, err)
42 return
43 }
44 render(w, r, http.StatusOK, templates.IssuesList(currentUser(r.Context()), repo, state, issues, open, closed))
45}
46
47func (h *Handlers) newIssue(w http.ResponseWriter, r *http.Request) {
48 repo := h.viewRepo(w, r)
49 if repo == nil {
50 return
51 }
52 render(w, r, http.StatusOK, templates.IssueNew(currentUser(r.Context()), repo, "", "", ""))
53}
54
55func (h *Handlers) createIssue(w http.ResponseWriter, r *http.Request) {
56 repo := h.viewRepo(w, r)
57 if repo == nil {
58 return
59 }
60 title := r.FormValue("title")
61 body := r.FormValue("body")
62
63 issue, err := h.issues.Open(r.Context(), repo, currentUser(r.Context()), title, body)
64 if err != nil {
65 if errors.Is(err, domain.ErrValidation) {
66 msg := strings.TrimSuffix(err.Error(), ": "+domain.ErrValidation.Error())
67 render(w, r, http.StatusBadRequest, templates.IssueNew(currentUser(r.Context()), repo, title, body, msg))
68 return
69 }
70 h.writeError(w, r, err)
71 return
72 }
73 http.Redirect(w, r, repoURL(repo, "/issues/"+strconv.Itoa(issue.Number)), http.StatusSeeOther)
74}
75
76func (h *Handlers) issueDetail(w http.ResponseWriter, r *http.Request) {
77 repo, issue := h.loadIssue(w, r)
78 if issue == nil {
79 return
80 }
81 comments, err := h.issues.Comments(r.Context(), issue.ID)
82 if err != nil {
83 h.writeError(w, r, err)
84 return
85 }
86 canModify := app.CanModifyIssue(repo, issue, currentUser(r.Context()))
87 render(w, r, http.StatusOK, templates.IssueDetail(currentUser(r.Context()), repo, issue, comments, canModify))
88}
89
90func (h *Handlers) addIssueComment(w http.ResponseWriter, r *http.Request) {
91 repo, issue := h.loadIssue(w, r)
92 if issue == nil {
93 return
94 }
95 if err := h.issues.Comment(r.Context(), issue, currentUser(r.Context()), r.FormValue("body")); err != nil {
96 h.writeError(w, r, err)
97 return
98 }
99 http.Redirect(w, r, repoURL(repo, "/issues/"+strconv.Itoa(issue.Number)), http.StatusSeeOther)
100}
101
102func (h *Handlers) closeIssue(w http.ResponseWriter, r *http.Request) {
103 repo, issue := h.loadIssue(w, r)
104 if issue == nil {
105 return
106 }
107 if err := h.issues.Close(r.Context(), repo, issue, currentUser(r.Context())); err != nil {
108 h.writeError(w, r, err)
109 return
110 }
111 http.Redirect(w, r, repoURL(repo, "/issues/"+strconv.Itoa(issue.Number)), http.StatusSeeOther)
112}
113
114func (h *Handlers) reopenIssue(w http.ResponseWriter, r *http.Request) {
115 repo, issue := h.loadIssue(w, r)
116 if issue == nil {
117 return
118 }
119 if err := h.issues.Reopen(r.Context(), repo, issue, currentUser(r.Context())); err != nil {
120 h.writeError(w, r, err)
121 return
122 }
123 http.Redirect(w, r, repoURL(repo, "/issues/"+strconv.Itoa(issue.Number)), http.StatusSeeOther)
124}
125
126func (h *Handlers) loadIssue(w http.ResponseWriter, r *http.Request) (*domain.Repository, *domain.Issue) {
127 repo := h.viewRepo(w, r)
128 if repo == nil {
129 return nil, nil
130 }
131 number, err := strconv.Atoi(chi.URLParam(r, "number"))
132 if err != nil {
133 h.notFound(w, r)
134 return nil, nil
135 }
136 issue, _, err := h.issues.Get(r.Context(), repo.ID, number)
137 if err != nil {
138 h.writeError(w, r, err)
139 return nil, nil
140 }
141 return repo, issue
142}
143
144func repoURL(repo *domain.Repository, sub string) string {
145 return "/" + repo.OwnerName + "/" + repo.Name + sub
146}