···
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
203
-
log.Println("failed to get repo and knot", err)
203
+
l.Error("failed to get repo and knot", "err", err)
207
-
issueId := chi.URLParam(r, "issue")
208
-
issueIdInt, err := strconv.Atoi(issueId)
210
-
http.Error(w, "bad issue id", http.StatusBadRequest)
211
-
log.Println("failed to parse issue id", err)
207
+
issue, ok := r.Context().Value("issue").(*db.Issue)
209
+
l.Error("failed to get issue")
210
+
rp.pages.Error404(w)
216
-
case http.MethodPost:
217
-
body := r.FormValue("body")
219
-
rp.pages.Notice(w, "issue", "Body is required")
223
-
commentId := mathrand.IntN(1000000)
214
+
body := r.FormValue("body")
216
+
rp.pages.Notice(w, "issue", "Body is required")
226
-
err := db.NewIssueComment(rp.db, &db.Comment{
227
-
OwnerDid: user.Did,
228
-
RepoAt: f.RepoAt(),
230
-
CommentId: commentId,
220
+
replyToUri := r.FormValue("reply-to")
221
+
var replyTo *string
222
+
if replyToUri != "" {
223
+
uri, err := syntax.ParseATURI(replyToUri)
235
-
log.Println("failed to create comment", err)
225
+
l.Error("failed to get parse replyTo", "err", err, "replyTo", replyToUri)
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
240
-
createdAt := time.Now().Format(time.RFC3339)
241
-
ownerDid := user.Did
242
-
issueAt, err := db.GetIssueAt(rp.db, f.RepoAt(), issueIdInt)
244
-
log.Println("failed to get issue at", err)
245
-
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
249
-
atUri := f.RepoAt().String()
250
-
client, err := rp.oauth.AuthorizedClient(r)
252
-
log.Println("failed to get authorized client", err)
253
-
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
256
-
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
257
-
Collection: tangled.RepoIssueCommentNSID,
260
-
Record: &lexutil.LexiconTypeDecoder{
261
-
Val: &tangled.RepoIssueComment{
266
-
CreatedAt: createdAt,
271
-
log.Println("failed to create comment", err)
229
+
if uri.Collection() != tangled.RepoIssueCommentNSID {
230
+
l.Error("invalid replyTo collection", "collection", uri.Collection())
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
276
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), issueIdInt, commentId))
238
+
comment := db.IssueComment{
241
+
IssueAt: issue.AtUri().String(),
244
+
Created: time.Now(),
246
+
if err = rp.validator.ValidateIssueComment(&comment); err != nil {
247
+
l.Error("failed to validate comment", "err", err)
248
+
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
251
+
record := comment.AsRecord()
281
-
func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) {
282
-
user := rp.oauth.GetUser(r)
283
-
f, err := rp.repoResolver.Resolve(r)
253
+
client, err := rp.oauth.AuthorizedClient(r)
285
-
log.Println("failed to get repo and knot", err)
255
+
l.Error("failed to get authorized client", "err", err)
256
+
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
289
-
issueId := chi.URLParam(r, "issue")
290
-
issueIdInt, err := strconv.Atoi(issueId)
260
+
// create a record first
261
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
262
+
Collection: tangled.RepoIssueCommentNSID,
264
+
Rkey: comment.Rkey,
265
+
Record: &lexutil.LexiconTypeDecoder{
292
-
http.Error(w, "bad issue id", http.StatusBadRequest)
293
-
log.Println("failed to parse issue id", err)
270
+
l.Error("failed to create comment", "err", err)
271
+
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
276
+
if err := rollbackRecord(context.Background(), atUri, client); err != nil {
277
+
l.Error("rollback failed", "err", err)
297
-
commentId := chi.URLParam(r, "comment_id")
298
-
commentIdInt, err := strconv.Atoi(commentId)
281
+
commentId, err := db.AddIssueComment(rp.db, comment)
300
-
http.Error(w, "bad comment id", http.StatusBadRequest)
301
-
log.Println("failed to parse issue id", err)
283
+
l.Error("failed to create comment", "err", err)
284
+
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
305
-
issue, err := db.GetIssue(rp.db, f.RepoAt(), issueIdInt)
288
+
// reset atUri to make rollback a no-op
290
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), issue.IssueId, commentId))
293
+
func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) {
294
+
l := rp.logger.With("handler", "IssueComment")
295
+
user := rp.oauth.GetUser(r)
296
+
f, err := rp.repoResolver.Resolve(r)
307
-
log.Println("failed to get issue", err)
308
-
rp.pages.Notice(w, "issues", "Failed to load issue. Try again later.")
298
+
l.Error("failed to get repo and knot", "err", err)
312
-
comment, err := db.GetComment(rp.db, f.RepoAt(), issueIdInt, commentIdInt)
302
+
issue, ok := r.Context().Value("issue").(*db.Issue)
304
+
l.Error("failed to get issue")
305
+
rp.pages.Error404(w)
309
+
commentId := chi.URLParam(r, "commentId")
310
+
comments, err := db.GetIssueComments(
312
+
db.FilterEq("id", commentId),
314
-
http.Error(w, "bad comment id", http.StatusBadRequest)
315
+
l.Error("failed to fetch comment", "id", commentId)
316
+
http.Error(w, "failed to fetch comment id", http.StatusBadRequest)
319
+
if len(comments) != 1 {
320
+
l.Error("incorrect number of comments returned", "id", commentId, "len(comments)", len(comments))
321
+
http.Error(w, "invalid comment id", http.StatusBadRequest)
324
+
comment := comments[0]
318
-
rp.pages.SingleIssueCommentFragment(w, pages.SingleIssueCommentParams{
326
+
rp.pages.IssueCommentBodyFragment(w, pages.IssueCommentBodyParams{
RepoInfo: f.RepoInfo(user),
func (rp *Issues) EditIssueComment(w http.ResponseWriter, r *http.Request) {
335
+
l := rp.logger.With("handler", "EditIssueComment")
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
330
-
log.Println("failed to get repo and knot", err)
339
+
l.Error("failed to get repo and knot", "err", err)
334
-
issueId := chi.URLParam(r, "issue")
335
-
issueIdInt, err := strconv.Atoi(issueId)
337
-
http.Error(w, "bad issue id", http.StatusBadRequest)
338
-
log.Println("failed to parse issue id", err)
343
+
issue, ok := r.Context().Value("issue").(*db.Issue)
345
+
l.Error("failed to get issue")
346
+
rp.pages.Error404(w)
342
-
commentId := chi.URLParam(r, "comment_id")
343
-
commentIdInt, err := strconv.Atoi(commentId)
350
+
commentId := chi.URLParam(r, "commentId")
351
+
comments, err := db.GetIssueComments(
353
+
db.FilterEq("id", commentId),
345
-
http.Error(w, "bad comment id", http.StatusBadRequest)
346
-
log.Println("failed to parse issue id", err)
356
+
l.Error("failed to fetch comment", "id", commentId)
357
+
http.Error(w, "failed to fetch comment id", http.StatusBadRequest)
350
-
issue, err := db.GetIssue(rp.db, f.RepoAt(), issueIdInt)
352
-
log.Println("failed to get issue", err)
353
-
rp.pages.Notice(w, "issues", "Failed to load issue. Try again later.")
357
-
comment, err := db.GetComment(rp.db, f.RepoAt(), issueIdInt, commentIdInt)
359
-
http.Error(w, "bad comment id", http.StatusBadRequest)
360
+
if len(comments) != 1 {
361
+
l.Error("incorrect number of comments returned", "id", commentId, "len(comments)", len(comments))
362
+
http.Error(w, "invalid comment id", http.StatusBadRequest)
365
+
comment := comments[0]
363
-
if comment.OwnerDid != user.Did {
367
+
if comment.Did != user.Did {
368
+
l.Error("unauthorized comment edit", "expectedDid", comment.Did, "gotDid", user.Did)
http.Error(w, "you are not the author of this comment", http.StatusUnauthorized)
···
rp.pages.Notice(w, "issue-comment", "Failed to create comment.")
385
-
rkey := comment.Rkey
392
+
newComment := comment
393
+
newComment.Body = newBody
394
+
newComment.Edited = &now
395
+
record := newComment.AsRecord()
387
-
// optimistic update
388
-
edited := time.Now()
389
-
err = db.EditComment(rp.db, comment.RepoAt, comment.Issue, comment.CommentId, newBody)
397
+
_, err = db.AddIssueComment(rp.db, newComment)
log.Println("failed to perferom update-description query", err)
rp.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
···
456
+
func (rp *Issues) ReplyIssueCommentPlaceholder(w http.ResponseWriter, r *http.Request) {
457
+
l := rp.logger.With("handler", "ReplyIssueCommentPlaceholder")
458
+
user := rp.oauth.GetUser(r)
459
+
f, err := rp.repoResolver.Resolve(r)
461
+
l.Error("failed to get repo and knot", "err", err)
465
+
issue, ok := r.Context().Value("issue").(*db.Issue)
467
+
l.Error("failed to get issue")
468
+
rp.pages.Error404(w)
472
+
commentId := chi.URLParam(r, "commentId")
473
+
comments, err := db.GetIssueComments(
475
+
db.FilterEq("id", commentId),
478
+
l.Error("failed to fetch comment", "id", commentId)
479
+
http.Error(w, "failed to fetch comment id", http.StatusBadRequest)
482
+
if len(comments) != 1 {
483
+
l.Error("incorrect number of comments returned", "id", commentId, "len(comments)", len(comments))
484
+
http.Error(w, "invalid comment id", http.StatusBadRequest)
487
+
comment := comments[0]
489
+
rp.pages.ReplyIssueCommentPlaceholderFragment(w, pages.ReplyIssueCommentPlaceholderParams{
490
+
LoggedInUser: user,
491
+
RepoInfo: f.RepoInfo(user),
497
+
func (rp *Issues) ReplyIssueComment(w http.ResponseWriter, r *http.Request) {
498
+
l := rp.logger.With("handler", "ReplyIssueComment")
499
+
user := rp.oauth.GetUser(r)
500
+
f, err := rp.repoResolver.Resolve(r)
502
+
l.Error("failed to get repo and knot", "err", err)
506
+
issue, ok := r.Context().Value("issue").(*db.Issue)
508
+
l.Error("failed to get issue")
509
+
rp.pages.Error404(w)
513
+
commentId := chi.URLParam(r, "commentId")
514
+
comments, err := db.GetIssueComments(
516
+
db.FilterEq("id", commentId),
519
+
l.Error("failed to fetch comment", "id", commentId)
520
+
http.Error(w, "failed to fetch comment id", http.StatusBadRequest)
523
+
if len(comments) != 1 {
524
+
l.Error("incorrect number of comments returned", "id", commentId, "len(comments)", len(comments))
525
+
http.Error(w, "invalid comment id", http.StatusBadRequest)
528
+
comment := comments[0]
530
+
rp.pages.ReplyIssueCommentFragment(w, pages.ReplyIssueCommentParams{
531
+
LoggedInUser: user,
532
+
RepoInfo: f.RepoInfo(user),
func (rp *Issues) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
539
+
l := rp.logger.With("handler", "DeleteIssueComment")
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
454
-
log.Println("failed to get repo and knot", err)