+5
-1
appview/db/pulls.go
+5
-1
appview/db/pulls.go
···
101
101
}
102
102
103
103
func (p *Pull) LatestPatch() string {
104
-
latestSubmission := p.Submissions[len(p.Submissions)-1]
104
+
latestSubmission := p.Submissions[p.LastRoundNumber()]
105
105
return latestSubmission.Patch
106
+
}
107
+
108
+
func (p *Pull) LastRoundNumber() int {
109
+
return len(p.Submissions) - 1
106
110
}
107
111
108
112
func (s PullSubmission) AsNiceDiff(targetBranch string) types.NiceDiff {
+15
appview/pages/funcmap.go
+15
appview/pages/funcmap.go
···
1
1
package pages
2
2
3
3
import (
4
+
"errors"
4
5
"fmt"
5
6
"html"
6
7
"html/template"
···
120
121
},
121
122
"list": func(args ...any) []any {
122
123
return args
124
+
},
125
+
"dict": func(values ...any) (map[string]any, error) {
126
+
if len(values)%2 != 0 {
127
+
return nil, errors.New("invalid dict call")
128
+
}
129
+
dict := make(map[string]any, len(values)/2)
130
+
for i := 0; i < len(values); i += 2 {
131
+
key, ok := values[i].(string)
132
+
if !ok {
133
+
return nil, errors.New("dict keys must be strings")
134
+
}
135
+
dict[key] = values[i+1]
136
+
}
137
+
return dict, nil
123
138
},
124
139
"i": func(name string, classes ...string) template.HTML {
125
140
data, err := icon(name, classes)
+34
appview/pages/pages.go
+34
appview/pages/pages.go
···
576
576
return p.execute("repo/pulls/patch", w, params)
577
577
}
578
578
579
+
type PullResubmitParams struct {
580
+
LoggedInUser *auth.User
581
+
RepoInfo RepoInfo
582
+
Pull *db.Pull
583
+
SubmissionId int
584
+
}
585
+
586
+
func (p *Pages) PullResubmitFragment(w io.Writer, params PullResubmitParams) error {
587
+
return p.executePlain("fragments/pullResubmit", w, params)
588
+
}
589
+
590
+
type PullActionsParams struct {
591
+
LoggedInUser *auth.User
592
+
RepoInfo RepoInfo
593
+
Pull *db.Pull
594
+
RoundNumber int
595
+
MergeCheck types.MergeCheckResponse
596
+
}
597
+
598
+
func (p *Pages) PullActionsFragment(w io.Writer, params PullActionsParams) error {
599
+
return p.executePlain("fragments/pullActions", w, params)
600
+
}
601
+
602
+
type PullNewCommentParams struct {
603
+
LoggedInUser *auth.User
604
+
RepoInfo RepoInfo
605
+
Pull *db.Pull
606
+
RoundNumber int
607
+
}
608
+
609
+
func (p *Pages) PullNewCommentFragment(w io.Writer, params PullNewCommentParams) error {
610
+
return p.executePlain("fragments/pullNewComment", w, params)
611
+
}
612
+
579
613
func (p *Pages) Static() http.Handler {
580
614
sub, err := fs.Sub(Files, "static")
581
615
if err != nil {
+2
-2
appview/pages/templates/fragments/editRepoDescription.html
+2
-2
appview/pages/templates/fragments/editRepoDescription.html
···
2
2
<form hx-put="/{{ .RepoInfo.FullName }}/description" hx-target="this" hx-swap="outerHTML" class="flex flex-wrap gap-2">
3
3
<input type="text" class="p-1" name="description" value="{{ .RepoInfo.Description }}">
4
4
<button type="submit" class="btn p-2 flex items-center gap-2 no-underline text-sm">
5
-
save {{ i "check" "w-3 h-3" }}
5
+
{{ i "check" "w-3 h-3" }} save
6
6
</button>
7
7
<button type="button" class="btn p-2 flex items-center gap-2 no-underline text-sm" hx-get="/{{ .RepoInfo.FullName }}/description" >
8
-
cancel {{ i "x" "w-3 h-3" }}
8
+
{{ i "x" "w-3 h-3" }} cancel
9
9
</button>
10
10
</form>
11
11
{{ end }}
+72
appview/pages/templates/fragments/pullActions.html
+72
appview/pages/templates/fragments/pullActions.html
···
1
+
{{ define "fragments/pullActions" }}
2
+
{{ $lastIdx := sub (len .Pull.Submissions) 1 }}
3
+
{{ $roundNumber := .RoundNumber }}
4
+
5
+
{{ $isPushAllowed := .RepoInfo.Roles.IsPushAllowed }}
6
+
{{ $isMerged := .Pull.State.IsMerged }}
7
+
{{ $isClosed := .Pull.State.IsClosed }}
8
+
{{ $isOpen := .Pull.State.IsOpen }}
9
+
{{ $isConflicted := and .MergeCheck (or .MergeCheck.Error .MergeCheck.IsConflicted) }}
10
+
{{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }}
11
+
{{ $isLastRound := eq $roundNumber $lastIdx }}
12
+
<div class="relative w-fit">
13
+
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
14
+
<div id="actions-{{$roundNumber}}" class="flex flex-wrap gap-2">
15
+
<button
16
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ $roundNumber }}/comment"
17
+
hx-target="#actions-{{$roundNumber}}"
18
+
hx-swap="outerHtml"
19
+
class="btn p-2 flex items-center gap-2 no-underline hover:no-underline">
20
+
{{ i "message-square-plus" "w-4 h-4" }}
21
+
<span>comment</span>
22
+
</button>
23
+
{{ if and $isPushAllowed $isOpen $isLastRound }}
24
+
{{ $disabled := "" }}
25
+
{{ if $isConflicted }}
26
+
{{ $disabled = "disabled" }}
27
+
{{ end }}
28
+
<button
29
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
30
+
hx-swap="none"
31
+
hx-confirm="Are you sure you want to merge this pull request?"
32
+
class="btn p-2 flex items-center gap-2" {{ $disabled }}>
33
+
{{ i "git-merge" "w-4 h-4" }}
34
+
<span>merge</span>
35
+
</button>
36
+
{{ end }}
37
+
38
+
{{ if and $isPullAuthor $isOpen $isLastRound }}
39
+
<button
40
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/resubmit"
41
+
hx-target="#actions-{{$roundNumber}}"
42
+
hx-swap="outerHtml"
43
+
class="btn p-2 flex items-center gap-2">
44
+
{{ i "rotate-ccw" "w-4 h-4" }}
45
+
<span>resubmit</span>
46
+
</button>
47
+
{{ end }}
48
+
49
+
{{ if and $isPullAuthor $isPushAllowed $isOpen $isLastRound }}
50
+
<button
51
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/close"
52
+
hx-swap="none"
53
+
class="btn p-2 flex items-center gap-2">
54
+
{{ i "ban" "w-4 h-4" }}
55
+
<span>close</span>
56
+
</button>
57
+
{{ end }}
58
+
59
+
{{ if and $isPullAuthor $isPushAllowed $isClosed $isLastRound }}
60
+
<button
61
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/reopen"
62
+
hx-swap="none"
63
+
class="btn p-2 flex items-center gap-2">
64
+
{{ i "circle-dot" "w-4 h-4" }}
65
+
<span>reopen</span>
66
+
</button>
67
+
{{ end }}
68
+
</div>
69
+
</div>
70
+
{{ end }}
71
+
72
+
+32
appview/pages/templates/fragments/pullNewComment.html
+32
appview/pages/templates/fragments/pullNewComment.html
···
1
+
{{ define "fragments/pullNewComment" }}
2
+
<div
3
+
id="pull-comment-card-{{ .RoundNumber }}"
4
+
class="bg-white rounded drop-shadow-sm py-4 px-6 relative w-full flex flex-col gap-2">
5
+
<div class="text-sm text-gray-500">
6
+
{{ didOrHandle .LoggedInUser.Did .LoggedInUser.Handle }}
7
+
</div>
8
+
<form
9
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ .RoundNumber }}/comment"
10
+
hx-swap="none"
11
+
class="w-full flex flex-wrap gap-2">
12
+
<textarea
13
+
name="body"
14
+
class="w-full p-2 rounded border border-gray-200"
15
+
placeholder="Add to the discussion..."></textarea>
16
+
<button type="submit" class="btn flex items-center gap-2">
17
+
{{ i "message-square" "w-4 h-4" }} comment
18
+
</button>
19
+
<button
20
+
type="button"
21
+
class="btn flex items-center gap-2"
22
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ .RoundNumber }}/actions"
23
+
hx-swap="outerHTML"
24
+
hx-target="#pull-comment-card-{{ .RoundNumber }}">
25
+
{{ i "x" "w-4 h-4" }}
26
+
<span>cancel</span>
27
+
</button>
28
+
<div id="pull-comment"></div>
29
+
</form>
30
+
</div>
31
+
{{ end }}
32
+
+52
appview/pages/templates/fragments/pullResubmit.html
+52
appview/pages/templates/fragments/pullResubmit.html
···
1
+
{{ define "fragments/pullResubmit" }}
2
+
<div
3
+
id="resubmit-pull-card"
4
+
class="rounded relative border bg-amber-50 border-amber-200 px-6 py-2">
5
+
6
+
<div class="flex items-center gap-2 text-amber-500">
7
+
{{ i "pencil" "w-4 h-4" }}
8
+
<span class="font-medium">resubmit your patch</span>
9
+
</div>
10
+
11
+
<div class="mt-2 text-sm text-gray-700">
12
+
You can update this patch to address any reviews.
13
+
This will begin a new round of reviews,
14
+
but you'll still be able to view your previous submissions and feedback.
15
+
</div>
16
+
17
+
<div class="mt-4 flex flex-col">
18
+
<form
19
+
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/resubmit"
20
+
hx-swap="none"
21
+
class="w-full flex flex-wrap gap-2">
22
+
<textarea
23
+
name="patch"
24
+
class="w-full p-2 mb-2 rounded border border-gray-200"
25
+
placeholder="Paste your updated patch here."
26
+
rows="15"
27
+
></textarea>
28
+
<button
29
+
type="submit"
30
+
class="btn flex items-center gap-2"
31
+
{{ if or .Pull.State.IsClosed }}
32
+
disabled
33
+
{{ end }}>
34
+
{{ i "rotate-ccw" "w-4 h-4" }}
35
+
<span>resubmit</span>
36
+
</button>
37
+
<button
38
+
type="button"
39
+
class="btn flex items-center gap-2"
40
+
hx-get="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/round/{{ .Pull.LastRoundNumber }}/actions"
41
+
hx-swap="outerHTML"
42
+
hx-target="#resubmit-pull-card">
43
+
{{ i "x" "w-4 h-4" }}
44
+
<span>cancel</span>
45
+
</button>
46
+
</form>
47
+
48
+
<div id="resubmit-error" class="error"></div>
49
+
<div id="resubmit-success" class="success"></div>
50
+
</div>
51
+
</div>
52
+
{{ end }}
+1
-2
appview/pages/templates/fragments/repoDescription.html
+1
-2
appview/pages/templates/fragments/repoDescription.html
+22
-67
appview/pages/templates/repo/pulls/pull.html
+22
-67
appview/pages/templates/repo/pulls/pull.html
···
115
115
</div>
116
116
{{ end }}
117
117
118
-
{{ block "mergeStatus" $ }} {{ end }}
118
+
{{ if eq $lastIdx .RoundNumber }}
119
+
{{ block "mergeStatus" $ }} {{ end }}
120
+
{{ end }}
119
121
120
122
{{ if $.LoggedInUser }}
121
-
{{ block "actions" (list $ .ID) }} {{ end }}
123
+
{{ template "fragments/pullActions" (dict "LoggedInUser" $.LoggedInUser "Pull" $.Pull "RepoInfo" $.RepoInfo "RoundNumber" .RoundNumber "MergeCheck" $.MergeCheck) }}
122
124
{{ else }}
123
125
<div class="bg-white rounded drop-shadow-sm px-6 py-4 w-fit">
124
126
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
···
132
134
{{ end }}
133
135
134
136
{{ define "mergeStatus" }}
135
-
{{ if .Pull.State.IsMerged }}
137
+
{{ if .Pull.State.IsClosed }}
138
+
<div class="bg-gray-50 border border-black rounded drop-shadow-sm px-6 py-2 relative w-fit">
139
+
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
140
+
<div class="flex items-center gap-2 text-black">
141
+
{{ i "ban" "w-4 h-4" }}
142
+
<span class="font-medium">closed without merging</span
143
+
>
144
+
</div>
145
+
</div>
146
+
{{ else if .Pull.State.IsMerged }}
136
147
<div class="bg-purple-50 border border-purple-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
137
148
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
138
149
<div class="flex items-center gap-2 text-purple-500">
···
141
152
>
142
153
</div>
143
154
</div>
155
+
{{ else if and .MergeCheck .MergeCheck.Error }}
156
+
<div class="bg-red-50 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
157
+
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
158
+
<div class="flex items-center gap-2 text-red-500">
159
+
{{ i "triangle-alert" "w-4 h-4" }}
160
+
<span class="font-medium">{{ .MergeCheck.Error }}</span>
161
+
</div>
162
+
</div>
144
163
{{ else if and .MergeCheck .MergeCheck.IsConflicted }}
145
164
<div class="bg-red-50 border border-red-500 rounded drop-shadow-sm px-6 py-2 relative w-fit">
146
165
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
···
167
186
<span class="font-medium">no conflicts, ready to merge</span>
168
187
</div>
169
188
</div>
170
-
{{ end }}
171
-
{{ end }}
172
-
173
-
{{ define "actions" }}
174
-
{{ $rootObj := index . 0 }}
175
-
{{ $submissionId := index . 1 }}
176
-
177
-
{{ with $rootObj }}
178
-
{{ $isPushAllowed := .RepoInfo.Roles.IsPushAllowed }}
179
-
{{ $isMerged := .Pull.State.IsMerged }}
180
-
{{ $isClosed := .Pull.State.IsClosed }}
181
-
{{ $isOpen := .Pull.State.IsOpen }}
182
-
{{ $isConflicted := and .MergeCheck .MergeCheck.IsConflicted }}
183
-
{{ $isPullAuthor := and .LoggedInUser (eq .LoggedInUser.Did .Pull.OwnerDid) }}
184
-
<div class="relative w-fit">
185
-
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300"></div>
186
-
<div class="flex flex-wrap gap-2">
187
-
<button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline">
188
-
{{ i "message-square-plus" "w-4 h-4" }}
189
-
<span>comment</span>
190
-
</button>
191
-
{{ if and $isPushAllowed $isOpen }}
192
-
{{ $disabled := "" }}
193
-
{{ if $isConflicted }}
194
-
{{ $disabled = "disabled" }}
195
-
{{ end }}
196
-
<button
197
-
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/merge"
198
-
hx-swap="none"
199
-
hx-confirm="Are you sure you want to merge this pull request?"
200
-
class="btn p-2 flex items-center gap-2" {{ $disabled }}>
201
-
{{ i "git-merge" "w-4 h-4" }}
202
-
<span>merge</span>
203
-
</button>
204
-
{{ end }}
205
-
206
-
{{ if and $isPullAuthor $isOpen }}
207
-
<button href="#" class="btn p-2 flex items-center gap-2 no-underline hover:no-underline">
208
-
{{ i "rotate-ccw" "w-4 h-4" }}
209
-
<span>resubmit</span>
210
-
</button>
211
-
{{ end }}
212
-
213
-
{{ if and $isPullAuthor $isPushAllowed $isOpen }}
214
-
<button
215
-
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/close"
216
-
hx-swap="none"
217
-
class="btn p-2 flex items-center gap-2">
218
-
{{ i "ban" "w-4 h-4" }}
219
-
<span>close</span>
220
-
</button>
221
-
{{ end }}
222
-
223
-
{{ if and $isPullAuthor $isPushAllowed $isClosed }}
224
-
<button
225
-
hx-post="/{{ .RepoInfo.FullName }}/pulls/{{ .Pull.PullId }}/reopen"
226
-
hx-swap="none"
227
-
class="btn p-2 flex items-center gap-2">
228
-
{{ i "circle-dot" "w-4 h-4" }}
229
-
<span>reopen</span>
230
-
</button>
231
-
{{ end }}
232
-
</div>
233
-
</div>
234
189
{{ end }}
235
190
{{ end }}
236
191
+124
-39
appview/state/pull.go
+124
-39
appview/state/pull.go
···
20
20
lexutil "github.com/bluesky-social/indigo/lex/util"
21
21
)
22
22
23
+
// htmx fragment
24
+
func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
25
+
switch r.Method {
26
+
case http.MethodGet:
27
+
user := s.auth.GetUser(r)
28
+
f, err := fullyResolvedRepo(r)
29
+
if err != nil {
30
+
log.Println("failed to get repo and knot", err)
31
+
return
32
+
}
33
+
34
+
pull, ok := r.Context().Value("pull").(*db.Pull)
35
+
if !ok {
36
+
log.Println("failed to get pull")
37
+
s.pages.Notice(w, "pull-error", "Failed to edit patch. Try again later.")
38
+
return
39
+
}
40
+
41
+
roundNumberStr := chi.URLParam(r, "round")
42
+
roundNumber, err := strconv.Atoi(roundNumberStr)
43
+
if err != nil {
44
+
roundNumber = pull.LastRoundNumber()
45
+
}
46
+
if roundNumber >= len(pull.Submissions) {
47
+
http.Error(w, "bad round id", http.StatusBadRequest)
48
+
log.Println("failed to parse round id", err)
49
+
return
50
+
}
51
+
52
+
mergeCheckResponse := s.mergeCheck(f, pull)
53
+
54
+
s.pages.PullActionsFragment(w, pages.PullActionsParams{
55
+
LoggedInUser: user,
56
+
RepoInfo: f.RepoInfo(s, user),
57
+
Pull: pull,
58
+
RoundNumber: roundNumber,
59
+
MergeCheck: mergeCheckResponse,
60
+
})
61
+
return
62
+
}
63
+
}
64
+
23
65
func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
24
66
user := s.auth.GetUser(r)
25
67
f, err := fullyResolvedRepo(r)
···
62
104
}
63
105
}
64
106
65
-
var mergeCheckResponse types.MergeCheckResponse
66
-
67
-
// Only perform merge check if the pull request is not already merged
68
-
if pull.State != db.PullMerged {
69
-
secret, err := db.GetRegistrationKey(s.db, f.Knot)
70
-
if err != nil {
71
-
log.Printf("failed to get registration key for %s", f.Knot)
72
-
s.pages.Notice(w, "pull", "Failed to load pull request. Try again later.")
73
-
return
74
-
}
75
-
76
-
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
77
-
if err == nil {
78
-
resp, err := ksClient.MergeCheck([]byte(pull.LatestPatch()), pull.OwnerDid, f.RepoName, pull.TargetBranch)
79
-
if err != nil {
80
-
log.Println("failed to check for mergeability:", err)
81
-
} else {
82
-
respBody, err := io.ReadAll(resp.Body)
83
-
if err != nil {
84
-
log.Println("failed to read merge check response body")
85
-
} else {
86
-
err = json.Unmarshal(respBody, &mergeCheckResponse)
87
-
if err != nil {
88
-
log.Println("failed to unmarshal merge check response", err)
89
-
}
90
-
}
91
-
}
92
-
} else {
93
-
log.Printf("failed to setup signed client for %s; ignoring...", f.Knot)
94
-
}
95
-
}
107
+
mergeCheckResponse := s.mergeCheck(f, pull)
96
108
97
109
s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{
98
110
LoggedInUser: user,
···
103
115
})
104
116
}
105
117
118
+
func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull) types.MergeCheckResponse {
119
+
if pull.State == db.PullMerged {
120
+
return types.MergeCheckResponse{}
121
+
}
122
+
123
+
secret, err := db.GetRegistrationKey(s.db, f.Knot)
124
+
if err != nil {
125
+
log.Printf("failed to get registration key: %w", err)
126
+
return types.MergeCheckResponse{
127
+
Error: "failed to check merge status: this knot is unregistered",
128
+
}
129
+
}
130
+
131
+
ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
132
+
if err != nil {
133
+
log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err)
134
+
return types.MergeCheckResponse{
135
+
Error: "failed to check merge status",
136
+
}
137
+
}
138
+
139
+
resp, err := ksClient.MergeCheck([]byte(pull.LatestPatch()), pull.OwnerDid, f.RepoName, pull.TargetBranch)
140
+
if err != nil {
141
+
log.Println("failed to check for mergeability:", err)
142
+
switch resp.StatusCode {
143
+
case 400:
144
+
return types.MergeCheckResponse{
145
+
Error: "failed to check merge status: does this knot support PRs?",
146
+
}
147
+
default:
148
+
return types.MergeCheckResponse{
149
+
Error: "failed to check merge status: this knot is unreachable",
150
+
}
151
+
}
152
+
}
153
+
154
+
respBody, err := io.ReadAll(resp.Body)
155
+
if err != nil {
156
+
log.Println("failed to read merge check response body")
157
+
return types.MergeCheckResponse{
158
+
Error: "failed to check merge status: knot is not speaking the right language",
159
+
}
160
+
}
161
+
defer resp.Body.Close()
162
+
163
+
var mergeCheckResponse types.MergeCheckResponse
164
+
err = json.Unmarshal(respBody, &mergeCheckResponse)
165
+
if err != nil {
166
+
log.Println("failed to unmarshal merge check response", err)
167
+
return types.MergeCheckResponse{
168
+
Error: "failed to check merge status: knot is not speaking the right language",
169
+
}
170
+
}
171
+
172
+
return mergeCheckResponse
173
+
}
174
+
106
175
func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
107
176
user := s.auth.GetUser(r)
108
177
f, err := fullyResolvedRepo(r)
···
213
282
return
214
283
}
215
284
285
+
roundNumberStr := chi.URLParam(r, "round")
286
+
roundNumber, err := strconv.Atoi(roundNumberStr)
287
+
if err != nil || roundNumber >= len(pull.Submissions) {
288
+
http.Error(w, "bad round id", http.StatusBadRequest)
289
+
log.Println("failed to parse round id", err)
290
+
return
291
+
}
292
+
216
293
switch r.Method {
294
+
case http.MethodGet:
295
+
s.pages.PullNewCommentFragment(w, pages.PullNewCommentParams{
296
+
LoggedInUser: user,
297
+
RepoInfo: f.RepoInfo(s, user),
298
+
Pull: pull,
299
+
RoundNumber: roundNumber,
300
+
})
301
+
return
217
302
case http.MethodPost:
218
303
body := r.FormValue("body")
219
304
if body == "" {
220
305
s.pages.Notice(w, "pull", "Comment body is required")
221
-
return
222
-
}
223
-
224
-
submissionIdstr := r.FormValue("submissionId")
225
-
submissionId, err := strconv.Atoi(submissionIdstr)
226
-
if err != nil {
227
-
s.pages.Notice(w, "pull", "Invalid comment submission.")
228
306
return
229
307
}
230
308
···
263
341
},
264
342
},
265
343
})
344
+
log.Println(atResp.Uri)
266
345
if err != nil {
267
346
log.Println("failed to create pull comment", err)
268
347
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
···
276
355
PullId: pull.PullId,
277
356
Body: body,
278
357
CommentAt: atResp.Uri,
279
-
SubmissionId: submissionId,
358
+
SubmissionId: pull.Submissions[roundNumber].ID,
280
359
})
281
360
if err != nil {
282
361
log.Println("failed to create pull comment", err)
···
433
512
}
434
513
435
514
switch r.Method {
515
+
case http.MethodGet:
516
+
s.pages.PullResubmitFragment(w, pages.PullResubmitParams{
517
+
RepoInfo: f.RepoInfo(s, user),
518
+
Pull: pull,
519
+
})
520
+
return
436
521
case http.MethodPost:
437
522
patch := r.FormValue("patch")
438
523
+17
-3
appview/state/router.go
+17
-3
appview/state/router.go
···
66
66
r.Route("/{pull}", func(r chi.Router) {
67
67
r.Use(ResolvePull(s))
68
68
r.Get("/", s.RepoSinglePull)
69
-
r.Get("/round/{round}", s.RepoPullPatch)
69
+
70
+
r.Route("/round/{round}", func(r chi.Router) {
71
+
r.Get("/", s.RepoPullPatch)
72
+
r.Get("/actions", s.PullActions)
73
+
r.Route("/comment", func(r chi.Router) {
74
+
r.Get("/", s.PullComment)
75
+
r.Post("/", s.PullComment)
76
+
})
77
+
})
70
78
71
79
// authorized requests below this point
72
80
r.Group(func(r chi.Router) {
73
81
r.Use(AuthMiddleware(s))
74
-
r.Post("/resubmit", s.ResubmitPull)
75
-
r.Post("/comment", s.PullComment)
82
+
r.Route("/resubmit", func(r chi.Router) {
83
+
r.Get("/", s.ResubmitPull)
84
+
r.Post("/", s.ResubmitPull)
85
+
})
86
+
r.Route("/comment", func(r chi.Router) {
87
+
r.Get("/", s.PullComment)
88
+
r.Post("/", s.PullComment)
89
+
})
76
90
r.Post("/close", s.ClosePull)
77
91
r.Post("/reopen", s.ReopenPull)
78
92
// collaborators only