Signed-off-by: Seongmin Lee git@boltless.me
+197
appview/db/comments.go
+197
appview/db/comments.go
···
1
+
package db
2
+
3
+
import (
4
+
"database/sql"
5
+
"fmt"
6
+
"maps"
7
+
"slices"
8
+
"sort"
9
+
"strings"
10
+
"time"
11
+
12
+
"github.com/bluesky-social/indigo/atproto/syntax"
13
+
"tangled.org/core/appview/models"
14
+
)
15
+
16
+
func PutComment(tx *sql.Tx, c *models.Comment) error {
17
+
result, err := tx.Exec(
18
+
`insert into comments (
19
+
did,
20
+
rkey,
21
+
subject_at,
22
+
reply_to,
23
+
body,
24
+
pull_submission_id,
25
+
created
26
+
)
27
+
values (?, ?, ?, ?, ?, ?, ?)
28
+
on conflict(did, rkey) do update set
29
+
subject_at = excluded.subject_at,
30
+
reply_to = excluded.reply_to,
31
+
body = excluded.body,
32
+
edited = case
33
+
when
34
+
comments.subject_at != excluded.subject_at
35
+
or comments.body != excluded.body
36
+
or comments.reply_to != excluded.reply_to
37
+
then ?
38
+
else comments.edited
39
+
end`,
40
+
c.Did,
41
+
c.Rkey,
42
+
c.Subject,
43
+
c.ReplyTo,
44
+
c.Body,
45
+
c.PullSubmissionId,
46
+
c.Created.Format(time.RFC3339),
47
+
time.Now().Format(time.RFC3339),
48
+
)
49
+
if err != nil {
50
+
return err
51
+
}
52
+
53
+
c.Id, err = result.LastInsertId()
54
+
if err != nil {
55
+
return err
56
+
}
57
+
58
+
if err := putReferences(tx, c.AtUri(), c.References); err != nil {
59
+
return fmt.Errorf("put reference_links: %w", err)
60
+
}
61
+
62
+
return nil
63
+
}
64
+
65
+
func DeleteComments(e Execer, filters ...filter) error {
66
+
var conditions []string
67
+
var args []any
68
+
for _, filter := range filters {
69
+
conditions = append(conditions, filter.Condition())
70
+
args = append(args, filter.Arg()...)
71
+
}
72
+
73
+
whereClause := ""
74
+
if conditions != nil {
75
+
whereClause = " where " + strings.Join(conditions, " and ")
76
+
}
77
+
78
+
query := fmt.Sprintf(`update comments set body = "", deleted = strftime('%%Y-%%m-%%dT%%H:%%M:%%SZ', 'now') %s`, whereClause)
79
+
80
+
_, err := e.Exec(query, args...)
81
+
return err
82
+
}
83
+
84
+
func GetComments(e Execer, filters ...filter) ([]models.Comment, error) {
85
+
commentMap := make(map[string]*models.Comment)
86
+
87
+
var conditions []string
88
+
var args []any
89
+
for _, filter := range filters {
90
+
conditions = append(conditions, filter.Condition())
91
+
args = append(args, filter.Arg()...)
92
+
}
93
+
94
+
whereClause := ""
95
+
if conditions != nil {
96
+
whereClause = " where " + strings.Join(conditions, " and ")
97
+
}
98
+
99
+
query := fmt.Sprintf(`
100
+
select
101
+
id,
102
+
did,
103
+
rkey,
104
+
subject_at,
105
+
reply_to,
106
+
body,
107
+
pull_submission_id,
108
+
created,
109
+
edited,
110
+
deleted
111
+
from
112
+
comments
113
+
%s
114
+
`, whereClause)
115
+
116
+
rows, err := e.Query(query, args...)
117
+
if err != nil {
118
+
return nil, err
119
+
}
120
+
121
+
for rows.Next() {
122
+
var comment models.Comment
123
+
var created string
124
+
var rkey, edited, deleted, replyTo sql.Null[string]
125
+
err := rows.Scan(
126
+
&comment.Id,
127
+
&comment.Did,
128
+
&rkey,
129
+
&comment.Subject,
130
+
&replyTo,
131
+
&comment.Body,
132
+
&comment.PullSubmissionId,
133
+
&created,
134
+
&edited,
135
+
&deleted,
136
+
)
137
+
if err != nil {
138
+
return nil, err
139
+
}
140
+
141
+
// this is a remnant from old times, newer comments always have rkey
142
+
if rkey.Valid {
143
+
comment.Rkey = rkey.V
144
+
}
145
+
146
+
if t, err := time.Parse(time.RFC3339, created); err == nil {
147
+
comment.Created = t
148
+
}
149
+
150
+
if edited.Valid {
151
+
if t, err := time.Parse(time.RFC3339, edited.V); err == nil {
152
+
comment.Edited = &t
153
+
}
154
+
}
155
+
156
+
if deleted.Valid {
157
+
if t, err := time.Parse(time.RFC3339, deleted.V); err == nil {
158
+
comment.Deleted = &t
159
+
}
160
+
}
161
+
162
+
if replyTo.Valid {
163
+
rt := syntax.ATURI(replyTo.V)
164
+
comment.ReplyTo = &rt
165
+
}
166
+
167
+
atUri := comment.AtUri().String()
168
+
commentMap[atUri] = &comment
169
+
}
170
+
171
+
if err := rows.Err(); err != nil {
172
+
return nil, err
173
+
}
174
+
175
+
// collect references from each comments
176
+
commentAts := slices.Collect(maps.Keys(commentMap))
177
+
allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts))
178
+
if err != nil {
179
+
return nil, fmt.Errorf("failed to query reference_links: %w", err)
180
+
}
181
+
for commentAt, references := range allReferencs {
182
+
if comment, ok := commentMap[commentAt.String()]; ok {
183
+
comment.References = references
184
+
}
185
+
}
186
+
187
+
var comments []models.Comment
188
+
for _, c := range commentMap {
189
+
comments = append(comments, *c)
190
+
}
191
+
192
+
sort.Slice(comments, func(i, j int) bool {
193
+
return comments[i].Created.After(comments[j].Created)
194
+
})
195
+
196
+
return comments, nil
197
+
}
+32
appview/db/db.go
+32
appview/db/db.go
···
1174
1174
return err
1175
1175
})
1176
1176
1177
+
// not migrating existing comments here
1178
+
// all legacy comments will be dropped
1179
+
runMigration(conn, logger, "add-comments-table", func(tx *sql.Tx) error {
1180
+
_, err := tx.Exec(`
1181
+
drop table comments;
1182
+
1183
+
create table comments (
1184
+
-- identifiers
1185
+
id integer primary key autoincrement,
1186
+
did text not null,
1187
+
rkey text not null,
1188
+
at_uri text generated always as ('at://' || did || '/' || 'sh.tangled.comment' || '/' || rkey) stored,
1189
+
1190
+
-- at identifiers
1191
+
subject_at text not null,
1192
+
reply_to text, -- at_uri of parent comment
1193
+
1194
+
pull_submission_id integer, -- dirty fix until we atprotate the pull-rounds
1195
+
1196
+
-- content
1197
+
body text not null,
1198
+
created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
1199
+
edited text,
1200
+
deleted text,
1201
+
1202
+
-- constraints
1203
+
unique(did, rkey)
1204
+
);
1205
+
`)
1206
+
return err
1207
+
})
1208
+
1177
1209
return &DB{
1178
1210
db,
1179
1211
logger,
+6
-121
appview/db/pulls.go
+6
-121
appview/db/pulls.go
···
446
446
return nil, err
447
447
}
448
448
449
-
// Get comments for all submissions using GetPullComments
449
+
// Get comments for all submissions using GetComments
450
450
submissionIds := slices.Collect(maps.Keys(submissionMap))
451
-
comments, err := GetPullComments(e, FilterIn("submission_id", submissionIds))
451
+
comments, err := GetComments(e, FilterIn("pull_submission_id", submissionIds))
452
452
if err != nil {
453
453
return nil, fmt.Errorf("failed to get pull comments: %w", err)
454
454
}
455
455
for _, comment := range comments {
456
-
if submission, ok := submissionMap[comment.SubmissionId]; ok {
457
-
submission.Comments = append(submission.Comments, comment)
456
+
if comment.PullSubmissionId != nil {
457
+
if submission, ok := submissionMap[*comment.PullSubmissionId]; ok {
458
+
submission.Comments = append(submission.Comments, comment)
459
+
}
458
460
}
459
461
}
460
462
···
474
476
return m, nil
475
477
}
476
478
477
-
func GetPullComments(e Execer, filters ...filter) ([]models.PullComment, error) {
478
-
var conditions []string
479
-
var args []any
480
-
for _, filter := range filters {
481
-
conditions = append(conditions, filter.Condition())
482
-
args = append(args, filter.Arg()...)
483
-
}
484
-
485
-
whereClause := ""
486
-
if conditions != nil {
487
-
whereClause = " where " + strings.Join(conditions, " and ")
488
-
}
489
-
490
-
query := fmt.Sprintf(`
491
-
select
492
-
id,
493
-
pull_id,
494
-
submission_id,
495
-
repo_at,
496
-
owner_did,
497
-
comment_at,
498
-
body,
499
-
created
500
-
from
501
-
pull_comments
502
-
%s
503
-
order by
504
-
created asc
505
-
`, whereClause)
506
-
507
-
rows, err := e.Query(query, args...)
508
-
if err != nil {
509
-
return nil, err
510
-
}
511
-
defer rows.Close()
512
-
513
-
commentMap := make(map[string]*models.PullComment)
514
-
for rows.Next() {
515
-
var comment models.PullComment
516
-
var createdAt string
517
-
err := rows.Scan(
518
-
&comment.ID,
519
-
&comment.PullId,
520
-
&comment.SubmissionId,
521
-
&comment.RepoAt,
522
-
&comment.OwnerDid,
523
-
&comment.CommentAt,
524
-
&comment.Body,
525
-
&createdAt,
526
-
)
527
-
if err != nil {
528
-
return nil, err
529
-
}
530
-
531
-
if t, err := time.Parse(time.RFC3339, createdAt); err == nil {
532
-
comment.Created = t
533
-
}
534
-
535
-
atUri := comment.AtUri().String()
536
-
commentMap[atUri] = &comment
537
-
}
538
-
539
-
if err := rows.Err(); err != nil {
540
-
return nil, err
541
-
}
542
-
543
-
// collect references for each comments
544
-
commentAts := slices.Collect(maps.Keys(commentMap))
545
-
allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts))
546
-
if err != nil {
547
-
return nil, fmt.Errorf("failed to query reference_links: %w", err)
548
-
}
549
-
for commentAt, references := range allReferencs {
550
-
if comment, ok := commentMap[commentAt.String()]; ok {
551
-
comment.References = references
552
-
}
553
-
}
554
-
555
-
var comments []models.PullComment
556
-
for _, c := range commentMap {
557
-
comments = append(comments, *c)
558
-
}
559
-
560
-
sort.Slice(comments, func(i, j int) bool {
561
-
return comments[i].Created.Before(comments[j].Created)
562
-
})
563
-
564
-
return comments, nil
565
-
}
566
-
567
479
// timeframe here is directly passed into the sql query filter, and any
568
480
// timeframe in the past should be negative; e.g.: "-3 months"
569
481
func GetPullsByOwnerDid(e Execer, did, timeframe string) ([]models.Pull, error) {
···
640
552
return pulls, nil
641
553
}
642
554
643
-
func NewPullComment(tx *sql.Tx, comment *models.PullComment) (int64, error) {
644
-
query := `insert into pull_comments (owner_did, repo_at, submission_id, comment_at, pull_id, body) values (?, ?, ?, ?, ?, ?)`
645
-
res, err := tx.Exec(
646
-
query,
647
-
comment.OwnerDid,
648
-
comment.RepoAt,
649
-
comment.SubmissionId,
650
-
comment.CommentAt,
651
-
comment.PullId,
652
-
comment.Body,
653
-
)
654
-
if err != nil {
655
-
return 0, err
656
-
}
657
-
658
-
i, err := res.LastInsertId()
659
-
if err != nil {
660
-
return 0, err
661
-
}
662
-
663
-
if err := putReferences(tx, comment.AtUri(), comment.References); err != nil {
664
-
return 0, fmt.Errorf("put reference_links: %w", err)
665
-
}
666
-
667
-
return i, nil
668
-
}
669
-
670
555
func SetPullState(e Execer, repoAt syntax.ATURI, pullId int, pullState models.PullState) error {
671
556
_, err := e.Exec(
672
557
`update pulls set state = ? where repo_at = ? and pull_id = ? and (state <> ? or state <> ?)`,
+7
-8
appview/db/reference.go
+7
-8
appview/db/reference.go
···
123
123
values %s
124
124
)
125
125
select
126
-
p.owner_did, p.rkey,
127
-
c.comment_at
126
+
p.owner_did, p.rkey, c.at_uri
128
127
from input inp
129
128
join repos r
130
129
on r.did = inp.owner_did
···
132
131
join pulls p
133
132
on p.repo_at = r.at_uri
134
133
and p.pull_id = inp.pull_id
135
-
left join pull_comments c
134
+
left join comments c
136
135
on inp.comment_id is not null
137
-
and c.repo_at = r.at_uri and c.pull_id = p.pull_id
136
+
and c.subject_at = ('at://' || p.owner_did || '/' || 'sh.tangled.repo.pull' || '/' || p.rkey)
138
137
and c.id = inp.comment_id
139
138
`,
140
139
strings.Join(vals, ","),
···
292
291
return nil, fmt.Errorf("get pull backlinks: %w", err)
293
292
}
294
293
backlinks = append(backlinks, ls...)
295
-
ls, err = getPullCommentBacklinks(e, backlinksMap[tangled.RepoPullCommentNSID])
294
+
ls, err = getPullCommentBacklinks(e, backlinksMap[tangled.CommentNSID])
296
295
if err != nil {
297
296
return nil, fmt.Errorf("get pull_comment backlinks: %w", err)
298
297
}
···
427
426
if len(aturis) == 0 {
428
427
return nil, nil
429
428
}
430
-
filter := FilterIn("c.comment_at", aturis)
429
+
filter := FilterIn("c.at_uri", aturis)
431
430
rows, err := e.Query(
432
431
fmt.Sprintf(
433
432
`select r.did, r.name, p.pull_id, c.id, p.title, p.state
434
433
from repos r
435
434
join pulls p
436
435
on r.at_uri = p.repo_at
437
-
join pull_comments c
438
-
on r.at_uri = c.repo_at and p.pull_id = c.pull_id
436
+
join comments c
437
+
on ('at://' || p.owner_did || '/' || 'sh.tangled.repo.pull' || '/' || p.rkey) = c.subject_at
439
438
where %s`,
440
439
filter.Condition(),
441
440
),
+117
appview/models/comment.go
+117
appview/models/comment.go
···
1
+
package models
2
+
3
+
import (
4
+
"fmt"
5
+
"strings"
6
+
"time"
7
+
8
+
"github.com/bluesky-social/indigo/atproto/syntax"
9
+
"tangled.org/core/api/tangled"
10
+
)
11
+
12
+
type Comment struct {
13
+
Id int64
14
+
Did syntax.DID
15
+
Rkey string
16
+
Subject syntax.ATURI
17
+
ReplyTo *syntax.ATURI
18
+
Body string
19
+
Created time.Time
20
+
Edited *time.Time
21
+
Deleted *time.Time
22
+
Mentions []syntax.DID
23
+
References []syntax.ATURI
24
+
PullSubmissionId *int
25
+
}
26
+
27
+
func (c *Comment) AtUri() syntax.ATURI {
28
+
return syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", c.Did, tangled.CommentNSID, c.Rkey))
29
+
}
30
+
31
+
func (c *Comment) AsRecord() tangled.Comment {
32
+
mentions := make([]string, len(c.Mentions))
33
+
for i, did := range c.Mentions {
34
+
mentions[i] = string(did)
35
+
}
36
+
references := make([]string, len(c.References))
37
+
for i, uri := range c.References {
38
+
references[i] = string(uri)
39
+
}
40
+
var replyTo *string
41
+
if c.ReplyTo != nil {
42
+
replyToStr := c.ReplyTo.String()
43
+
replyTo = &replyToStr
44
+
}
45
+
return tangled.Comment{
46
+
Subject: c.Subject.String(),
47
+
Body: c.Body,
48
+
CreatedAt: c.Created.Format(time.RFC3339),
49
+
ReplyTo: replyTo,
50
+
Mentions: mentions,
51
+
References: references,
52
+
}
53
+
}
54
+
55
+
func (c *Comment) IsTopLevel() bool {
56
+
return c.ReplyTo == nil
57
+
}
58
+
59
+
func (c *Comment) IsReply() bool {
60
+
return c.ReplyTo != nil
61
+
}
62
+
63
+
func (c *Comment) Validate() error {
64
+
// TODO: sanitize the body and then trim space
65
+
if sb := strings.TrimSpace(c.Body); sb == "" {
66
+
return fmt.Errorf("body is empty after HTML sanitization")
67
+
}
68
+
69
+
// if it's for PR, PullSubmissionId should not be nil
70
+
if c.Subject.Collection().String() == tangled.RepoPullNSID {
71
+
if c.PullSubmissionId == nil {
72
+
return fmt.Errorf("PullSubmissionId should not be nil")
73
+
}
74
+
}
75
+
return nil
76
+
}
77
+
78
+
func CommentFromRecord(did, rkey string, record tangled.Comment) (*Comment, error) {
79
+
created, err := time.Parse(time.RFC3339, record.CreatedAt)
80
+
if err != nil {
81
+
created = time.Now()
82
+
}
83
+
84
+
ownerDid := did
85
+
86
+
if _, err = syntax.ParseATURI(record.Subject); err != nil {
87
+
return nil, err
88
+
}
89
+
90
+
i := record
91
+
mentions := make([]syntax.DID, len(record.Mentions))
92
+
for i, did := range record.Mentions {
93
+
mentions[i] = syntax.DID(did)
94
+
}
95
+
references := make([]syntax.ATURI, len(record.References))
96
+
for i, uri := range i.References {
97
+
references[i] = syntax.ATURI(uri)
98
+
}
99
+
var replyTo *syntax.ATURI
100
+
if record.ReplyTo != nil {
101
+
replyToAtUri := syntax.ATURI(*record.ReplyTo)
102
+
replyTo = &replyToAtUri
103
+
}
104
+
105
+
comment := Comment{
106
+
Did: syntax.DID(ownerDid),
107
+
Rkey: rkey,
108
+
Body: record.Body,
109
+
Subject: syntax.ATURI(record.Subject),
110
+
ReplyTo: replyTo,
111
+
Created: created,
112
+
Mentions: mentions,
113
+
References: references,
114
+
}
115
+
116
+
return &comment, nil
117
+
}
+2
-46
appview/models/pull.go
+2
-46
appview/models/pull.go
···
138
138
RoundNumber int
139
139
Patch string
140
140
Combined string
141
-
Comments []PullComment
141
+
Comments []Comment
142
142
SourceRev string // include the rev that was used to create this submission: only for branch/fork PRs
143
143
144
144
// meta
145
145
Created time.Time
146
146
}
147
147
148
-
type PullComment struct {
149
-
// ids
150
-
ID int
151
-
PullId int
152
-
SubmissionId int
153
-
154
-
// at ids
155
-
RepoAt string
156
-
OwnerDid string
157
-
CommentAt string
158
-
159
-
// content
160
-
Body string
161
-
162
-
// meta
163
-
Mentions []syntax.DID
164
-
References []syntax.ATURI
165
-
166
-
// meta
167
-
Created time.Time
168
-
}
169
-
170
-
func (p *PullComment) AtUri() syntax.ATURI {
171
-
return syntax.ATURI(p.CommentAt)
172
-
}
173
-
174
-
// func (p *PullComment) AsRecord() tangled.RepoPullComment {
175
-
// mentions := make([]string, len(p.Mentions))
176
-
// for i, did := range p.Mentions {
177
-
// mentions[i] = string(did)
178
-
// }
179
-
// references := make([]string, len(p.References))
180
-
// for i, uri := range p.References {
181
-
// references[i] = string(uri)
182
-
// }
183
-
// return tangled.RepoPullComment{
184
-
// Pull: p.PullAt,
185
-
// Body: p.Body,
186
-
// Mentions: mentions,
187
-
// References: references,
188
-
// CreatedAt: p.Created.Format(time.RFC3339),
189
-
// }
190
-
// }
191
-
192
148
func (p *Pull) LastRoundNumber() int {
193
149
return len(p.Submissions) - 1
194
150
}
···
289
245
addParticipant(s.PullAt.Authority().String())
290
246
291
247
for _, c := range s.Comments {
292
-
addParticipant(c.OwnerDid)
248
+
addParticipant(c.Did.String())
293
249
}
294
250
295
251
return participants
+11
-6
appview/notify/db/db.go
+11
-6
appview/notify/db/db.go
···
248
248
)
249
249
}
250
250
251
-
func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID) {
252
-
pull, err := db.GetPull(n.db,
253
-
syntax.ATURI(comment.RepoAt),
254
-
comment.PullId,
251
+
func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) {
252
+
pulls, err := db.GetPulls(n.db,
253
+
db.FilterEq("owner_did", comment.Subject.Authority()),
254
+
db.FilterEq("rkey", comment.Subject.RecordKey()),
255
255
)
256
256
if err != nil {
257
257
log.Printf("NewPullComment: failed to get pulls: %v", err)
258
258
return
259
259
}
260
+
if len(pulls) == 0 {
261
+
log.Printf("NewPullComment: no pull found for %s", comment.Subject)
262
+
return
263
+
}
264
+
pull := pulls[0]
260
265
261
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", comment.RepoAt))
266
+
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", pull.RepoAt))
262
267
if err != nil {
263
268
log.Printf("NewPullComment: failed to get repos: %v", err)
264
269
return
···
273
278
recipients = append(recipients, syntax.DID(p))
274
279
}
275
280
276
-
actorDid := syntax.DID(comment.OwnerDid)
281
+
actorDid := comment.Did
277
282
eventType := models.NotificationTypePullCommented
278
283
entityType := "pull"
279
284
entityId := pull.AtUri().String()
+1
-1
appview/notify/merged_notifier.go
+1
-1
appview/notify/merged_notifier.go
···
82
82
m.fanout("NewPull", ctx, pull)
83
83
}
84
84
85
-
func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID) {
85
+
func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) {
86
86
m.fanout("NewPullComment", ctx, comment, mentions)
87
87
}
88
88
+2
-2
appview/notify/notifier.go
+2
-2
appview/notify/notifier.go
···
22
22
DeleteFollow(ctx context.Context, follow *models.Follow)
23
23
24
24
NewPull(ctx context.Context, pull *models.Pull)
25
-
NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID)
25
+
NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID)
26
26
NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull)
27
27
28
28
UpdateProfile(ctx context.Context, profile *models.Profile)
···
52
52
func (m *BaseNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {}
53
53
54
54
func (m *BaseNotifier) NewPull(ctx context.Context, pull *models.Pull) {}
55
-
func (m *BaseNotifier) NewPullComment(ctx context.Context, models *models.PullComment, mentions []syntax.DID) {
55
+
func (m *BaseNotifier) NewPullComment(ctx context.Context, models *models.Comment, mentions []syntax.DID) {
56
56
}
57
57
func (m *BaseNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) {}
58
58
+3
-4
appview/notify/posthog/notifier.go
+3
-4
appview/notify/posthog/notifier.go
···
86
86
}
87
87
}
88
88
89
-
func (n *posthogNotifier) NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID) {
89
+
func (n *posthogNotifier) NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) {
90
90
err := n.client.Enqueue(posthog.Capture{
91
-
DistinctId: comment.OwnerDid,
91
+
DistinctId: comment.Did.String(),
92
92
Event: "new_pull_comment",
93
93
Properties: posthog.Properties{
94
-
"repo_at": comment.RepoAt,
95
-
"pull_id": comment.PullId,
94
+
"pull_at": comment.Subject,
96
95
"mentions": mentions,
97
96
},
98
97
})
+3
-3
appview/pages/templates/repo/pulls/pull.html
+3
-3
appview/pages/templates/repo/pulls/pull.html
···
165
165
166
166
<div class="md:pl-[3.5rem] flex flex-col gap-2 mt-2 relative">
167
167
{{ range $cidx, $c := .Comments }}
168
-
<div id="comment-{{$c.ID}}" class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-2 px-4 relative w-full">
168
+
<div id="comment-{{$c.Id}}" class="bg-white dark:bg-gray-800 rounded drop-shadow-sm py-2 px-4 relative w-full">
169
169
{{ if gt $cidx 0 }}
170
170
<div class="absolute left-8 -top-2 w-px h-2 bg-gray-300 dark:bg-gray-600"></div>
171
171
{{ end }}
172
172
<div class="text-sm text-gray-500 dark:text-gray-400 flex items-center gap-1">
173
-
{{ template "user/fragments/picHandleLink" $c.OwnerDid }}
173
+
{{ template "user/fragments/picHandleLink" $c.Did.String }}
174
174
<span class="before:content-['·']"></span>
175
-
<a class="text-gray-500 dark:text-gray-400 hover:text-gray-500 dark:hover:text-gray-300" href="#comment-{{.ID}}">{{ template "repo/fragments/time" $c.Created }}</a>
175
+
<a class="text-gray-500 dark:text-gray-400 hover:text-gray-500 dark:hover:text-gray-300" href="#comment-{{.Id}}">{{ template "repo/fragments/time" $c.Created }}</a>
176
176
</div>
177
177
<div class="prose dark:prose-invert">
178
178
{{ $c.Body | markdown }}
+1
-1
appview/pulls/opengraph.go
+1
-1
appview/pulls/opengraph.go
···
276
276
}
277
277
278
278
// Get comment count from database
279
-
comments, err := db.GetPullComments(s.db, db.FilterEq("pull_id", pull.ID))
279
+
comments, err := db.GetComments(s.db, db.FilterEq("subject_at", pull.AtUri()))
280
280
if err != nil {
281
281
log.Printf("failed to get pull comments: %v", err)
282
282
}
+24
-23
appview/pulls/pulls.go
+24
-23
appview/pulls/pulls.go
···
740
740
}
741
741
defer tx.Rollback()
742
742
743
-
createdAt := time.Now().Format(time.RFC3339)
743
+
comment := models.Comment{
744
+
Did: syntax.DID(user.Did),
745
+
Rkey: tid.TID(),
746
+
Subject: pull.AtUri(),
747
+
ReplyTo: nil,
748
+
Body: body,
749
+
Created: time.Now(),
750
+
Mentions: mentions,
751
+
References: references,
752
+
PullSubmissionId: &pull.Submissions[roundNumber].ID,
753
+
}
754
+
if err = comment.Validate(); err != nil {
755
+
log.Println("failed to validate comment", err)
756
+
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
757
+
return
758
+
}
759
+
record := comment.AsRecord()
744
760
745
761
client, err := s.oauth.AuthorizedClient(r)
746
762
if err != nil {
···
748
764
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
749
765
return
750
766
}
751
-
atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
752
-
Collection: tangled.RepoPullCommentNSID,
767
+
_, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
768
+
Collection: tangled.CommentNSID,
753
769
Repo: user.Did,
754
-
Rkey: tid.TID(),
770
+
Rkey: comment.Rkey,
755
771
Record: &lexutil.LexiconTypeDecoder{
756
-
Val: &tangled.RepoPullComment{
757
-
Pull: pull.AtUri().String(),
758
-
Body: body,
759
-
CreatedAt: createdAt,
760
-
},
772
+
Val: &record,
761
773
},
762
774
})
763
775
if err != nil {
···
766
778
return
767
779
}
768
780
769
-
comment := &models.PullComment{
770
-
OwnerDid: user.Did,
771
-
RepoAt: f.RepoAt().String(),
772
-
PullId: pull.PullId,
773
-
Body: body,
774
-
CommentAt: atResp.Uri,
775
-
SubmissionId: pull.Submissions[roundNumber].ID,
776
-
Mentions: mentions,
777
-
References: references,
778
-
}
779
-
780
781
// Create the pull comment in the database with the commentAt field
781
-
commentId, err := db.NewPullComment(tx, comment)
782
+
err = db.PutComment(tx, &comment)
782
783
if err != nil {
783
784
log.Println("failed to create pull comment", err)
784
785
s.pages.Notice(w, "pull-comment", "Failed to create comment.")
···
792
793
return
793
794
}
794
795
795
-
s.notifier.NewPullComment(r.Context(), comment, mentions)
796
+
s.notifier.NewPullComment(r.Context(), &comment, mentions)
796
797
797
798
ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
798
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", ownerSlashRepo, pull.PullId, commentId))
799
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", ownerSlashRepo, pull.PullId, comment.Id))
799
800
return
800
801
}
801
802
}