From 1db01d86118c9a0ca78f1fc9f31309462abc421f Mon Sep 17 00:00:00 2001 From: Anirudh Oppiliappan Date: Thu, 21 Aug 2025 22:32:40 +0300 Subject: [PATCH] appview: ingest issue comment records Change-Id: wnotmtoqlnvlsqluyynpxmtlxwpxzsmu Signed-off-by: Anirudh Oppiliappan --- appview/db/issues.go | 46 ++++++++++++++++++++---- appview/ingester.go | 79 ++++++++++++++++++++++++++++++++++++++++++ appview/state/state.go | 1 + 3 files changed, 120 insertions(+), 6 deletions(-) diff --git a/appview/db/issues.go b/appview/db/issues.go index 7340397e..927b7467 100644 --- a/appview/db/issues.go +++ b/appview/db/issues.go @@ -3,6 +3,7 @@ package db import ( "database/sql" "fmt" + mathrand "math/rand/v2" "strings" "time" @@ -109,12 +110,13 @@ func IssueCommentFromRecord(e Execer, did, rkey string, record tangled.RepoIssue } comment := Comment{ - OwnerDid: ownerDid, - RepoAt: repoAt, - Rkey: rkey, - Body: record.Body, - Issue: issueId, - Created: &created, + OwnerDid: ownerDid, + RepoAt: repoAt, + Rkey: rkey, + Body: record.Body, + Issue: issueId, + CommentId: mathrand.IntN(1000000), + Created: &created, } return comment, nil @@ -624,6 +626,38 @@ func DeleteComment(e Execer, repoAt syntax.ATURI, issueId, commentId int) error return err } +func UpdateCommentByRkey(e Execer, ownerDid, rkey, newBody string) error { + _, err := e.Exec( + ` + update comments + set body = ?, + edited = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') + where owner_did = ? and rkey = ? + `, newBody, ownerDid, rkey) + return err +} + +func DeleteCommentByRkey(e Execer, ownerDid, rkey string) error { + _, err := e.Exec( + ` + update comments + set body = "", + deleted = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') + where owner_did = ? and rkey = ? + `, ownerDid, rkey) + return err +} + +func UpdateIssueByRkey(e Execer, ownerDid, rkey, title, body string) error { + _, err := e.Exec(`update issues set title = ?, body = ? where owner_did = ? and rkey = ?`, title, body, ownerDid, rkey) + return err +} + +func DeleteIssueByRkey(e Execer, ownerDid, rkey string) error { + _, err := e.Exec(`delete from issues where owner_did = ? and rkey = ?`, ownerDid, rkey) + return err +} + func CloseIssue(e Execer, repoAt syntax.ATURI, issueId int) error { _, err := e.Exec(`update issues set open = 0 where repo_at = ? and issue_id = ?`, repoAt, issueId) return err diff --git a/appview/ingester.go b/appview/ingester.go index e195e8a8..533b7b5b 100644 --- a/appview/ingester.go +++ b/appview/ingester.go @@ -74,6 +74,8 @@ func (i *Ingester) Ingest() processFunc { err = i.ingestString(e) case tangled.RepoIssueNSID: err = i.ingestIssue(ctx, e) + case tangled.RepoIssueCommentNSID: + err = i.ingestIssueComment(e) } l = i.Logger.With("nsid", e.Commit.Collection) } @@ -862,3 +864,80 @@ func (i *Ingester) ingestIssue(ctx context.Context, e *models.Event) error { return fmt.Errorf("unknown operation: %s", e.Commit.Operation) } + +func (i *Ingester) ingestIssueComment(e *models.Event) error { + did := e.Did + rkey := e.Commit.RKey + + var err error + + l := i.Logger.With("handler", "ingestIssueComment", "nsid", e.Commit.Collection, "did", did, "rkey", rkey) + l.Info("ingesting record") + + ddb, ok := i.Db.Execer.(*db.DB) + if !ok { + return fmt.Errorf("failed to index issue comment record, invalid db cast") + } + + switch e.Commit.Operation { + case models.CommitOperationCreate: + raw := json.RawMessage(e.Commit.Record) + record := tangled.RepoIssueComment{} + err = json.Unmarshal(raw, &record) + if err != nil { + l.Error("invalid record", "err", err) + return err + } + + comment, err := db.IssueCommentFromRecord(ddb, did, rkey, record) + if err != nil { + l.Error("failed to parse comment from record", "err", err) + return err + } + + sanitizer := markup.NewSanitizer() + if sb := strings.TrimSpace(sanitizer.SanitizeDefault(comment.Body)); sb == "" { + return fmt.Errorf("body is empty after HTML sanitization") + } + + err = db.NewIssueComment(ddb, &comment) + if err != nil { + l.Error("failed to create issue comment", "err", err) + return err + } + + return nil + + case models.CommitOperationUpdate: + raw := json.RawMessage(e.Commit.Record) + record := tangled.RepoIssueComment{} + err = json.Unmarshal(raw, &record) + if err != nil { + l.Error("invalid record", "err", err) + return err + } + + sanitizer := markup.NewSanitizer() + if sb := strings.TrimSpace(sanitizer.SanitizeDefault(record.Body)); sb == "" { + return fmt.Errorf("body is empty after HTML sanitization") + } + + err = db.UpdateCommentByRkey(ddb, did, rkey, record.Body) + if err != nil { + l.Error("failed to update issue comment", "err", err) + return err + } + + return nil + + case models.CommitOperationDelete: + if err := db.DeleteCommentByRkey(ddb, did, rkey); err != nil { + l.Error("failed to delete", "err", err) + return fmt.Errorf("failed to delete issue comment record: %w", err) + } + + return nil + } + + return fmt.Errorf("unknown operation: %s", e.Commit.Operation) +} diff --git a/appview/state/state.go b/appview/state/state.go index e0136c66..168e8fd3 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -100,6 +100,7 @@ func Make(ctx context.Context, config *config.Config) (*State, error) { tangled.SpindleNSID, tangled.StringNSID, tangled.RepoIssueNSID, + tangled.RepoIssueCommentNSID, }, nil, slog.Default(), -- 2.43.0