appview/notify: notify users mentioned in issues #738

merged
opened by boltless.me targeting master from feat/mentions
Changed files
+64 -19
appview
+2 -1
appview/indexer/notifier.go
··· 3 import ( 4 "context" 5 6 "tangled.org/core/appview/models" 7 "tangled.org/core/appview/notify" 8 "tangled.org/core/log" ··· 10 11 var _ notify.Notifier = &Indexer{} 12 13 - func (ix *Indexer) NewIssue(ctx context.Context, issue *models.Issue) { 14 l := log.FromContext(ctx).With("notifier", "indexer", "issue", issue) 15 l.Debug("indexing new issue") 16 err := ix.Issues.Index(ctx, *issue)
··· 3 import ( 4 "context" 5 6 + "github.com/bluesky-social/indigo/atproto/syntax" 7 "tangled.org/core/appview/models" 8 "tangled.org/core/appview/notify" 9 "tangled.org/core/log" ··· 11 12 var _ notify.Notifier = &Indexer{} 13 14 + func (ix *Indexer) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 15 l := log.FromContext(ctx).With("notifier", "indexer", "issue", issue) 16 l.Debug("indexing new issue") 17 err := ix.Issues.Index(ctx, *issue)
+23 -2
appview/issues/issues.go
··· 24 "tangled.org/core/appview/notify" 25 "tangled.org/core/appview/oauth" 26 "tangled.org/core/appview/pages" 27 "tangled.org/core/appview/pagination" 28 "tangled.org/core/appview/reporesolver" 29 "tangled.org/core/appview/validator" ··· 453 454 // notify about the new comment 455 comment.Id = commentId 456 - rp.notifier.NewIssueComment(r.Context(), &comment) 457 458 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), issue.IssueId, commentId)) 459 } ··· 948 949 // everything is successful, do not rollback the atproto record 950 atUri = "" 951 - rp.notifier.NewIssue(r.Context(), issue) 952 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 953 return 954 }
··· 24 "tangled.org/core/appview/notify" 25 "tangled.org/core/appview/oauth" 26 "tangled.org/core/appview/pages" 27 + "tangled.org/core/appview/pages/markup" 28 "tangled.org/core/appview/pagination" 29 "tangled.org/core/appview/reporesolver" 30 "tangled.org/core/appview/validator" ··· 454 455 // notify about the new comment 456 comment.Id = commentId 457 + 458 + rawMentions := markup.FindUserMentions(comment.Body) 459 + idents := rp.idResolver.ResolveIdents(r.Context(), rawMentions) 460 + l.Debug("parsed mentions", "raw", rawMentions, "idents", idents) 461 + var mentions []syntax.DID 462 + for _, ident := range idents { 463 + if ident != nil && !ident.Handle.IsInvalidHandle() { 464 + mentions = append(mentions, ident.DID) 465 + } 466 + } 467 + rp.notifier.NewIssueComment(r.Context(), &comment, mentions) 468 469 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), issue.IssueId, commentId)) 470 } ··· 959 960 // everything is successful, do not rollback the atproto record 961 atUri = "" 962 + 963 + rawMentions := markup.FindUserMentions(issue.Body) 964 + idents := rp.idResolver.ResolveIdents(r.Context(), rawMentions) 965 + l.Debug("parsed mentions", "raw", rawMentions, "idents", idents) 966 + var mentions []syntax.DID 967 + for _, ident := range idents { 968 + if ident != nil && !ident.Handle.IsInvalidHandle() { 969 + mentions = append(mentions, ident.DID) 970 + } 971 + } 972 + rp.notifier.NewIssue(r.Context(), issue, mentions) 973 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 974 return 975 }
+24 -6
appview/notify/db/db.go
··· 64 // no-op 65 } 66 67 - func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue) { 68 69 // build the recipients list 70 // - owner of the repo ··· 81 } 82 83 actorDid := syntax.DID(issue.Did) 84 - eventType := models.NotificationTypeIssueCreated 85 entityType := "issue" 86 entityId := issue.AtUri().String() 87 repoId := &issue.Repo.Id ··· 91 n.notifyEvent( 92 actorDid, 93 recipients, 94 - eventType, 95 entityType, 96 entityId, 97 repoId, ··· 100 ) 101 } 102 103 - func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) { 104 issues, err := db.GetIssues(n.db, db.FilterEq("at_uri", comment.IssueAt)) 105 if err != nil { 106 log.Printf("NewIssueComment: failed to get issues: %v", err) ··· 132 } 133 134 actorDid := syntax.DID(comment.Did) 135 - eventType := models.NotificationTypeIssueCommented 136 entityType := "issue" 137 entityId := issue.AtUri().String() 138 repoId := &issue.Repo.Id ··· 142 n.notifyEvent( 143 actorDid, 144 recipients, 145 - eventType, 146 entityType, 147 entityId, 148 repoId,
··· 64 // no-op 65 } 66 67 + func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 68 69 // build the recipients list 70 // - owner of the repo ··· 81 } 82 83 actorDid := syntax.DID(issue.Did) 84 entityType := "issue" 85 entityId := issue.AtUri().String() 86 repoId := &issue.Repo.Id ··· 90 n.notifyEvent( 91 actorDid, 92 recipients, 93 + models.NotificationTypeIssueCreated, 94 + entityType, 95 + entityId, 96 + repoId, 97 + issueId, 98 + pullId, 99 + ) 100 + n.notifyEvent( 101 + actorDid, 102 + mentions, 103 + models.NotificationTypeUserMentioned, 104 entityType, 105 entityId, 106 repoId, ··· 109 ) 110 } 111 112 + func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) { 113 issues, err := db.GetIssues(n.db, db.FilterEq("at_uri", comment.IssueAt)) 114 if err != nil { 115 log.Printf("NewIssueComment: failed to get issues: %v", err) ··· 141 } 142 143 actorDid := syntax.DID(comment.Did) 144 entityType := "issue" 145 entityId := issue.AtUri().String() 146 repoId := &issue.Repo.Id ··· 150 n.notifyEvent( 151 actorDid, 152 recipients, 153 + models.NotificationTypeIssueCommented, 154 + entityType, 155 + entityId, 156 + repoId, 157 + issueId, 158 + pullId, 159 + ) 160 + n.notifyEvent( 161 + actorDid, 162 + mentions, 163 + models.NotificationTypeUserMentioned, 164 entityType, 165 entityId, 166 repoId,
+5 -4
appview/notify/merged_notifier.go
··· 6 "reflect" 7 "sync" 8 9 "tangled.org/core/appview/models" 10 "tangled.org/core/log" 11 ) ··· 53 m.fanout("DeleteStar", ctx, star) 54 } 55 56 - func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue) { 57 - m.fanout("NewIssue", ctx, issue) 58 } 59 60 - func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) { 61 - m.fanout("NewIssueComment", ctx, comment) 62 } 63 64 func (m *mergedNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {
··· 6 "reflect" 7 "sync" 8 9 + "github.com/bluesky-social/indigo/atproto/syntax" 10 "tangled.org/core/appview/models" 11 "tangled.org/core/log" 12 ) ··· 54 m.fanout("DeleteStar", ctx, star) 55 } 56 57 + func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 58 + m.fanout("NewIssue", ctx, issue, mentions) 59 } 60 61 + func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) { 62 + m.fanout("NewIssueComment", ctx, comment, mentions) 63 } 64 65 func (m *mergedNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {
+5 -4
appview/notify/notifier.go
··· 13 NewStar(ctx context.Context, star *models.Star) 14 DeleteStar(ctx context.Context, star *models.Star) 15 16 - NewIssue(ctx context.Context, issue *models.Issue) 17 - NewIssueComment(ctx context.Context, comment *models.IssueComment) 18 NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) 19 DeleteIssue(ctx context.Context, issue *models.Issue) 20 ··· 42 func (m *BaseNotifier) NewStar(ctx context.Context, star *models.Star) {} 43 func (m *BaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {} 44 45 - func (m *BaseNotifier) NewIssue(ctx context.Context, issue *models.Issue) {} 46 - func (m *BaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) {} 47 func (m *BaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {} 48 func (m *BaseNotifier) DeleteIssue(ctx context.Context, issue *models.Issue) {} 49
··· 13 NewStar(ctx context.Context, star *models.Star) 14 DeleteStar(ctx context.Context, star *models.Star) 15 16 + NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) 17 + NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) 18 NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) 19 DeleteIssue(ctx context.Context, issue *models.Issue) 20 ··· 42 func (m *BaseNotifier) NewStar(ctx context.Context, star *models.Star) {} 43 func (m *BaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {} 44 45 + func (m *BaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) {} 46 + func (m *BaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) { 47 + } 48 func (m *BaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {} 49 func (m *BaseNotifier) DeleteIssue(ctx context.Context, issue *models.Issue) {} 50
+5 -2
appview/notify/posthog/notifier.go
··· 4 "context" 5 "log" 6 7 "github.com/posthog/posthog-go" 8 "tangled.org/core/appview/models" 9 "tangled.org/core/appview/notify" ··· 56 } 57 } 58 59 - func (n *posthogNotifier) NewIssue(ctx context.Context, issue *models.Issue) { 60 err := n.client.Enqueue(posthog.Capture{ 61 DistinctId: issue.Did, 62 Event: "new_issue", 63 Properties: posthog.Properties{ 64 "repo_at": issue.RepoAt.String(), 65 "issue_id": issue.IssueId, 66 }, 67 }) 68 if err != nil { ··· 177 } 178 } 179 180 - func (n *posthogNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) { 181 err := n.client.Enqueue(posthog.Capture{ 182 DistinctId: comment.Did, 183 Event: "new_issue_comment", 184 Properties: posthog.Properties{ 185 "issue_at": comment.IssueAt, 186 }, 187 }) 188 if err != nil {
··· 4 "context" 5 "log" 6 7 + "github.com/bluesky-social/indigo/atproto/syntax" 8 "github.com/posthog/posthog-go" 9 "tangled.org/core/appview/models" 10 "tangled.org/core/appview/notify" ··· 57 } 58 } 59 60 + func (n *posthogNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 61 err := n.client.Enqueue(posthog.Capture{ 62 DistinctId: issue.Did, 63 Event: "new_issue", 64 Properties: posthog.Properties{ 65 "repo_at": issue.RepoAt.String(), 66 "issue_id": issue.IssueId, 67 + "mentions": mentions, 68 }, 69 }) 70 if err != nil { ··· 179 } 180 } 181 182 + func (n *posthogNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) { 183 err := n.client.Enqueue(posthog.Capture{ 184 DistinctId: comment.Did, 185 Event: "new_issue_comment", 186 Properties: posthog.Properties{ 187 "issue_at": comment.IssueAt, 188 + "mentions": mentions, 189 }, 190 }) 191 if err != nil {