Monorepo for Tangled tangled.org

appview/notify: merge new comment events into one

Signed-off-by: Seongmin Lee <git@boltless.me>

boltless.me d861bff5 30953310

verified
+137 -164
+1 -1
appview/issues/issues.go
··· 489 489 // reset atUri to make rollback a no-op 490 490 atUri = "" 491 491 492 - rp.notifier.NewIssueComment(r.Context(), &comment, mentions) 492 + rp.notifier.NewComment(r.Context(), &comment) 493 493 494 494 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f) 495 495 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", ownerSlashRepo, issue.IssueId, comment.Id))
+110 -122
appview/notify/db/db.go
··· 77 77 // no-op 78 78 } 79 79 80 - func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 80 + func (n *databaseNotifier) NewComment(ctx context.Context, comment *models.Comment) { 81 81 l := log.FromContext(ctx) 82 82 83 - collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt())) 83 + var ( 84 + // built the recipients list: 85 + // - the owner of the repo 86 + // - | if the comment is a reply -> everybody on that thread 87 + // | if the comment is a top level -> just the issue owner 88 + // - remove mentioned users from the recipients list 89 + recipients = sets.New[syntax.DID]() 90 + entityType string 91 + entityId string 92 + repoId *int64 93 + issueId *int64 94 + pullId *int64 95 + ) 96 + 97 + subjectDid, err := comment.Subject.Authority().AsDID() 84 98 if err != nil { 85 - l.Error("failed to fetch collaborators", "err", err) 99 + l.Error("expected did based at-uri for comment.subject") 86 100 return 87 101 } 102 + switch comment.Subject.Collection() { 103 + case tangled.RepoIssueNSID: 104 + issues, err := db.GetIssues( 105 + n.db, 106 + orm.FilterEq("did", subjectDid), 107 + orm.FilterEq("rkey", comment.Subject.RecordKey()), 108 + ) 109 + if err != nil { 110 + l.Error("failed to get issues", "err", err) 111 + return 112 + } 113 + if len(issues) == 0 { 114 + l.Error("no issue found", "subject", comment.Subject) 115 + return 116 + } 117 + issue := issues[0] 88 118 89 - // build the recipients list 90 - // - owner of the repo 91 - // - collaborators in the repo 92 - // - remove users already mentioned 93 - recipients := sets.Singleton(syntax.DID(issue.Repo.Did)) 94 - for _, c := range collaborators { 95 - recipients.Insert(c.SubjectDid) 119 + recipients.Insert(syntax.DID(issue.Repo.Did)) 120 + if comment.IsReply() { 121 + // if this comment is a reply, then notify everybody in that thread 122 + parentAtUri := *comment.ReplyTo 123 + 124 + // find the parent thread, and add all DIDs from here to the recipient list 125 + for _, t := range issue.CommentList() { 126 + if t.Self.AtUri() == parentAtUri { 127 + for _, p := range t.Participants() { 128 + recipients.Insert(p) 129 + } 130 + } 131 + } 132 + } else { 133 + // not a reply, notify just the issue author 134 + recipients.Insert(syntax.DID(issue.Did)) 135 + } 136 + 137 + entityType = "issue" 138 + entityId = issue.AtUri().String() 139 + repoId = &issue.Repo.Id 140 + issueId = &issue.Id 141 + case tangled.RepoPullNSID: 142 + pulls, err := db.GetPulls( 143 + n.db, 144 + orm.FilterEq("owner_did", subjectDid), 145 + orm.FilterEq("rkey", comment.Subject.RecordKey()), 146 + ) 147 + if err != nil { 148 + l.Error("NewComment: failed to get pulls", "err", err) 149 + return 150 + } 151 + if len(pulls) == 0 { 152 + l.Error("NewComment: no pull found", "aturi", comment.Subject) 153 + return 154 + } 155 + pull := pulls[0] 156 + 157 + pull.Repo, err = db.GetRepo(n.db, orm.FilterEq("at_uri", pull.RepoAt)) 158 + if err != nil { 159 + l.Error("NewComment: failed to get repo", "err", err) 160 + return 161 + } 162 + 163 + recipients.Insert(syntax.DID(pull.Repo.Did)) 164 + for _, p := range pull.Participants() { 165 + recipients.Insert(syntax.DID(p)) 166 + } 167 + 168 + entityType = "pull" 169 + entityId = pull.AtUri().String() 170 + repoId = &pull.Repo.Id 171 + p := int64(pull.ID) 172 + pullId = &p 173 + default: 174 + return // no-op 96 175 } 97 - for _, m := range mentions { 176 + 177 + for _, m := range comment.Mentions { 98 178 recipients.Remove(m) 99 179 } 100 180 101 - actorDid := syntax.DID(issue.Did) 102 - entityType := "issue" 103 - entityId := issue.AtUri().String() 104 - repoId := &issue.Repo.Id 105 - issueId := &issue.Id 106 - var pullId *int64 107 - 108 181 n.notifyEvent( 109 182 ctx, 110 - actorDid, 183 + comment.Did, 111 184 recipients, 112 - models.NotificationTypeIssueCreated, 185 + models.NotificationTypeIssueCommented, 113 186 entityType, 114 187 entityId, 115 188 repoId, ··· 118 191 ) 119 192 n.notifyEvent( 120 193 ctx, 121 - actorDid, 122 - sets.Collect(slices.Values(mentions)), 194 + comment.Did, 195 + sets.Collect(slices.Values(comment.Mentions)), 123 196 models.NotificationTypeUserMentioned, 124 197 entityType, 125 198 entityId, ··· 129 202 ) 130 203 } 131 204 132 - func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 205 + func (n *databaseNotifier) DeleteComment(ctx context.Context, comment *models.Comment) { 206 + // no-op 207 + } 208 + 209 + func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 133 210 l := log.FromContext(ctx) 134 211 135 - issues, err := db.GetIssues(n.db, orm.FilterEq("at_uri", comment.Subject)) 212 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt())) 136 213 if err != nil { 137 - l.Error("failed to get issues", "err", err) 138 - return 139 - } 140 - if len(issues) == 0 { 141 - l.Error("no issue found for", "err", comment.Subject) 214 + l.Error("failed to fetch collaborators", "err", err) 142 215 return 143 216 } 144 - issue := issues[0] 145 217 146 - // built the recipients list: 147 - // - the owner of the repo 148 - // - | if the comment is a reply -> everybody on that thread 149 - // | if the comment is a top level -> just the issue owner 150 - // - remove mentioned users from the recipients list 218 + // build the recipients list 219 + // - owner of the repo 220 + // - collaborators in the repo 221 + // - remove users already mentioned 151 222 recipients := sets.Singleton(syntax.DID(issue.Repo.Did)) 152 - 153 - if comment.IsReply() { 154 - // if this comment is a reply, then notify everybody in that thread 155 - parentAtUri := *comment.ReplyTo 156 - 157 - // find the parent thread, and add all DIDs from here to the recipient list 158 - for _, t := range issue.CommentList() { 159 - if t.Self.AtUri() == parentAtUri { 160 - for _, p := range t.Participants() { 161 - recipients.Insert(p) 162 - } 163 - } 164 - } 165 - } else { 166 - // not a reply, notify just the issue author 167 - recipients.Insert(syntax.DID(issue.Did)) 223 + for _, c := range collaborators { 224 + recipients.Insert(c.SubjectDid) 168 225 } 169 - 170 226 for _, m := range mentions { 171 227 recipients.Remove(m) 172 228 } 173 229 174 - actorDid := syntax.DID(comment.Did) 230 + actorDid := syntax.DID(issue.Did) 175 231 entityType := "issue" 176 232 entityId := issue.AtUri().String() 177 233 repoId := &issue.Repo.Id ··· 182 238 ctx, 183 239 actorDid, 184 240 recipients, 185 - models.NotificationTypeIssueCommented, 241 + models.NotificationTypeIssueCreated, 186 242 entityType, 187 243 entityId, 188 244 repoId, ··· 270 326 actorDid, 271 327 recipients, 272 328 eventType, 273 - entityType, 274 - entityId, 275 - repoId, 276 - issueId, 277 - pullId, 278 - ) 279 - } 280 - 281 - func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 282 - l := log.FromContext(ctx) 283 - 284 - pulls, err := db.GetPulls(n.db, 285 - orm.FilterEq("owner_did", comment.Subject.Authority()), 286 - orm.FilterEq("rkey", comment.Subject.RecordKey()), 287 - ) 288 - if err != nil { 289 - l.Error("failed to get pull", "err", err) 290 - return 291 - } 292 - if len(pulls) == 0 { 293 - l.Error("NewPullComment: no pull found", "aturi", comment.Subject) 294 - return 295 - } 296 - pull := pulls[0] 297 - 298 - repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", pull.RepoAt)) 299 - if err != nil { 300 - l.Error("failed to get repos", "err", err) 301 - return 302 - } 303 - 304 - // build up the recipients list: 305 - // - repo owner 306 - // - all pull participants 307 - // - remove those already mentioned 308 - recipients := sets.Singleton(syntax.DID(repo.Did)) 309 - for _, p := range pull.Participants() { 310 - recipients.Insert(syntax.DID(p)) 311 - } 312 - for _, m := range mentions { 313 - recipients.Remove(m) 314 - } 315 - 316 - actorDid := comment.Did 317 - eventType := models.NotificationTypePullCommented 318 - entityType := "pull" 319 - entityId := pull.AtUri().String() 320 - repoId := &repo.Id 321 - var issueId *int64 322 - p := int64(pull.ID) 323 - pullId := &p 324 - 325 - n.notifyEvent( 326 - ctx, 327 - actorDid, 328 - recipients, 329 - eventType, 330 - entityType, 331 - entityId, 332 - repoId, 333 - issueId, 334 - pullId, 335 - ) 336 - n.notifyEvent( 337 - ctx, 338 - actorDid, 339 - sets.Collect(slices.Values(mentions)), 340 - models.NotificationTypeUserMentioned, 341 329 entityType, 342 330 entityId, 343 331 repoId,
+6 -7
appview/notify/logging_notifier.go
··· 44 44 l.inner.NewIssue(ctx, issue, mentions) 45 45 } 46 46 47 - func (l *loggingNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) { 47 + func (l *loggingNotifier) NewComment(ctx context.Context, comment *models.Comment) { 48 48 ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewIssueComment")) 49 - l.inner.NewIssueComment(ctx, comment, mentions) 49 + l.inner.NewComment(ctx, comment) 50 + } 51 + func (l *loggingNotifier) DeleteComment(ctx context.Context, comment *models.Comment) { 52 + ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "DeleteComment")) 53 + l.inner.DeleteComment(ctx, comment) 50 54 } 51 55 52 56 func (l *loggingNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) { ··· 82 86 func (l *loggingNotifier) NewPull(ctx context.Context, pull *models.Pull) { 83 87 ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewPull")) 84 88 l.inner.NewPull(ctx, pull) 85 - } 86 - 87 - func (l *loggingNotifier) NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID) { 88 - ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewPullComment")) 89 - l.inner.NewPullComment(ctx, comment, mentions) 90 89 } 91 90 92 91 func (l *loggingNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) {
+8 -8
appview/notify/merged_notifier.go
··· 42 42 m.fanout(func(n Notifier) { n.DeleteStar(ctx, star) }) 43 43 } 44 44 45 - func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 46 - m.fanout(func(n Notifier) { n.NewIssue(ctx, issue, mentions) }) 45 + func (m *mergedNotifier) NewComment(ctx context.Context, comment *models.Comment) { 46 + m.fanout(func(n Notifier) { n.NewComment(ctx, comment) }) 47 47 } 48 48 49 - func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 50 - m.fanout(func(n Notifier) { n.NewIssueComment(ctx, comment, mentions) }) 49 + func (m *mergedNotifier) DeleteComment(ctx context.Context, comment *models.Comment) { 50 + m.fanout(func(n Notifier) { n.DeleteComment(ctx, comment) }) 51 + } 52 + 53 + func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 54 + m.fanout(func(n Notifier) { n.NewIssue(ctx, issue, mentions) }) 51 55 } 52 56 53 57 func (m *mergedNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) { ··· 76 80 77 81 func (m *mergedNotifier) NewPull(ctx context.Context, pull *models.Pull) { 78 82 m.fanout(func(n Notifier) { n.NewPull(ctx, pull) }) 79 - } 80 - 81 - func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 82 - m.fanout(func(n Notifier) { n.NewPullComment(ctx, comment, mentions) }) 83 83 } 84 84 85 85 func (m *mergedNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) {
+7 -7
appview/notify/notifier.go
··· 13 13 NewStar(ctx context.Context, star *models.Star) 14 14 DeleteStar(ctx context.Context, star *models.Star) 15 15 16 + NewComment(ctx context.Context, comment *models.Comment) 17 + DeleteComment(ctx context.Context, comment *models.Comment) 18 + 16 19 NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) 17 - NewIssueComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) 18 20 NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) 19 21 DeleteIssue(ctx context.Context, issue *models.Issue) 20 22 ··· 22 24 DeleteFollow(ctx context.Context, follow *models.Follow) 23 25 24 26 NewPull(ctx context.Context, pull *models.Pull) 25 - NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) 26 27 NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) 27 28 28 29 NewIssueLabelOp(ctx context.Context, issue *models.Issue) ··· 47 48 func (m *BaseNotifier) NewStar(ctx context.Context, star *models.Star) {} 48 49 func (m *BaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {} 49 50 51 + func (m *BaseNotifier) NewComment(ctx context.Context, comment *models.Comment) {} 52 + func (m *BaseNotifier) DeleteComment(ctx context.Context, comment *models.Comment) {} 53 + 50 54 func (m *BaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) {} 51 - func (m *BaseNotifier) NewIssueComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 52 - } 53 55 func (m *BaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {} 54 56 func (m *BaseNotifier) DeleteIssue(ctx context.Context, issue *models.Issue) {} 55 57 ··· 59 61 func (m *BaseNotifier) NewFollow(ctx context.Context, follow *models.Follow) {} 60 62 func (m *BaseNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {} 61 63 62 - func (m *BaseNotifier) NewPull(ctx context.Context, pull *models.Pull) {} 63 - func (m *BaseNotifier) NewPullComment(ctx context.Context, models *models.Comment, mentions []syntax.DID) { 64 - } 64 + func (m *BaseNotifier) NewPull(ctx context.Context, pull *models.Pull) {} 65 65 func (m *BaseNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) {} 66 66 67 67 func (m *BaseNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {}
+4 -18
appview/notify/posthog/notifier.go
··· 86 86 } 87 87 } 88 88 89 - func (n *posthogNotifier) NewPullComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 90 - err := n.client.Enqueue(posthog.Capture{ 91 - DistinctId: comment.Did.String(), 92 - Event: "new_pull_comment", 93 - Properties: posthog.Properties{ 94 - "pull_at": comment.Subject, 95 - "mentions": mentions, 96 - }, 97 - }) 98 - if err != nil { 99 - log.Println("failed to enqueue posthog event:", err) 100 - } 101 - } 102 - 103 89 func (n *posthogNotifier) NewPullClosed(ctx context.Context, pull *models.Pull) { 104 90 err := n.client.Enqueue(posthog.Capture{ 105 91 DistinctId: pull.OwnerDid, ··· 179 165 } 180 166 } 181 167 182 - func (n *posthogNotifier) NewIssueComment(ctx context.Context, comment *models.Comment, mentions []syntax.DID) { 168 + func (n *posthogNotifier) NewComment(ctx context.Context, comment *models.Comment) { 183 169 err := n.client.Enqueue(posthog.Capture{ 184 170 DistinctId: comment.Did.String(), 185 - Event: "new_issue_comment", 171 + Event: "new_comment", 186 172 Properties: posthog.Properties{ 187 - "issue_at": comment.Subject, 188 - "mentions": mentions, 173 + "subject_at": comment.Subject, 174 + "mentions": comment.Mentions, 189 175 }, 190 176 }) 191 177 if err != nil {
+1 -1
appview/pulls/pulls.go
··· 888 888 return 889 889 } 890 890 891 - s.notifier.NewPullComment(r.Context(), &comment, mentions) 891 + s.notifier.NewComment(r.Context(), &comment) 892 892 893 893 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f) 894 894 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", ownerSlashRepo, pull.PullId, comment.Id))