Monorepo for Tangled tangled.org

appview/notify: merge new comment events into one

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

boltless.me e101a344 55f195b8

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