appview: replace PullComment to Comment #865

open
opened by boltless.me targeting master from sl/wnrvrwyvrlzo
Changed files
+407 -215
appview
+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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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
··· 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 }