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