back interdiff of round #1 and #0

appview: introduce email notifications for @ mentions on issue/pr comments #393

closed
opened by boltless.me targeting master from boltless.me/core: feat/mentions

Stacked on top of #392

Yes, I know we have stacked PRs, but I want to explicitly separate two sets of commits and review both on different places

This is MVC implementation of email notification.

Still lot of parts are missing, but this is a PR with most basic features.

ERROR
appview/middleware/middleware.go

Failed to calculate interdiff for this file.

ERROR
appview/repo/artifact.go

Failed to calculate interdiff for this file.

ERROR
appview/repo/index.go

Failed to calculate interdiff for this file.

ERROR
appview/reporesolver/resolver.go

Failed to calculate interdiff for this file.

ERROR
appview/db/repos.go

Failed to calculate interdiff for this file.

ERROR
appview/pages/markup/markdown.go

Failed to calculate interdiff for this file.

ERROR
appview/pages/markup/markdown_at_extension.go

Failed to calculate interdiff for this file.

REVERTED
appview/issues/issues.go
··· 293 293 294 294 createdAt := time.Now().Format(time.RFC3339) 295 295 commentIdInt64 := int64(comment.CommentId) 296 + issueAt, err := db.GetIssueAt(rp.db, f.RepoAt(), issueIdInt) 296 - issue, err := db.GetIssue(rp.db, f.RepoAt(), issueIdInt) 297 297 if err != nil { 298 + log.Println("failed to get issue at", err) 298 - log.Println("failed to get issue", err) 299 299 rp.pages.Notice(w, "issue-comment", "Failed to create comment.") 300 300 return 301 301 } ··· 314 314 Record: &lexutil.LexiconTypeDecoder{ 315 315 Val: &tangled.RepoIssueComment{ 316 316 Repo: &atUri, 317 + Issue: issueAt, 317 - Issue: issue.IssueAt, 318 318 CommentId: &commentIdInt64, 319 319 Owner: &comment.OwnerDid, 320 320 Body: body, ··· 330 330 331 331 mentions := markup.FindUserMentions(comment.Body) 332 332 333 + rp.notifier.NewIssueComment(r.Context(), comment, mentions) 333 - rp.notifier.NewIssueComment(r.Context(), &f.Repo, issue, comment, mentions) 334 334 335 335 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), comment.Issue, comment.CommentId)) 336 336 return
REVERTED
appview/email/notifier.go
··· 34 34 35 35 var _ notify.Notifier = &EmailNotifier{} 36 36 37 + func (n *EmailNotifier) buildIssueEmail(ctx context.Context, repo *db.Repo, issue *db.Issue, comment *db.Comment, did string) (Email, error) { 38 + // TODO: check email preferences 39 + email, err := db.GetPrimaryEmail(n.db, did) 40 + if err != nil { 41 + return Email{}, fmt.Errorf("db.GetPrimaryEmail: %w", err) 42 + } 43 + commentOwner, err := n.idResolver.ResolveIdent(ctx, comment.OwnerDid) 44 + if err != nil || commentOwner.Handle.IsInvalidHandle() { 45 + return Email{}, fmt.Errorf("resolve comment owner did: %w", err) 46 + } 37 - // TODO: yeah this is just bad design. should be moved under idResolver ore include repoResolver at first place 38 - func (n *EmailNotifier) repoOwnerSlashName(ctx context.Context, repo *db.Repo) (string, error) { 39 47 repoOwnerID, err := n.idResolver.ResolveIdent(ctx, repo.Did) 40 48 if err != nil || repoOwnerID.Handle.IsInvalidHandle() { 49 + return Email{}, fmt.Errorf("resolve repo owner did: %w", err) 41 - return "", fmt.Errorf("resolve comment owner did: %w", err) 42 50 } 43 51 repoOwnerHandle := repoOwnerID.Handle 44 52 var repoOwnerSlashName string ··· 47 55 } else { 48 56 repoOwnerSlashName = repo.DidSlashRepo() 49 57 } 50 - return repoOwnerSlashName, nil 51 - } 52 - 53 - func (n *EmailNotifier) buildIssueEmail(ctx context.Context, repo *db.Repo, issue *db.Issue, comment *db.Comment, did string) (Email, error) { 54 - // TODO: check email preferences 55 - email, err := db.GetPrimaryEmail(n.db, did) 56 - if err != nil { 57 - return Email{}, fmt.Errorf("db.GetPrimaryEmail: %w", err) 58 - } 59 - commentOwner, err := n.idResolver.ResolveIdent(ctx, comment.OwnerDid) 60 - if err != nil || commentOwner.Handle.IsInvalidHandle() { 61 - return Email{}, fmt.Errorf("resolve comment owner did: %w", err) 62 - } 63 58 // TODO: make this configurable 64 59 baseUrl := "https://tangled.sh" 65 - repoOwnerSlashName, err := n.repoOwnerSlashName(ctx, repo) 66 - if err != nil { 67 - return Email{}, nil 68 - } 69 60 url := fmt.Sprintf("%s/%s/issues/%d#comment-%d", baseUrl, repoOwnerSlashName, comment.Issue, comment.CommentId) 70 61 return Email{ 71 62 APIKey: n.Config.Resend.ApiKey, ··· 76 67 }, nil 77 68 } 78 69 79 - func (n *EmailNotifier) buildPullEmail(ctx context.Context, repo *db.Repo, pull *db.Pull, comment *db.PullComment, did string) (Email, error) { 80 - // TODO: check email preferences 81 - email, err := db.GetPrimaryEmail(n.db, did) 82 - if err != nil { 83 - return Email{}, fmt.Errorf("db.GetPrimaryEmail: %w", err) 84 - } 85 - commentOwner, err := n.idResolver.ResolveIdent(ctx, comment.OwnerDid) 86 - if err != nil || commentOwner.Handle.IsInvalidHandle() { 87 - return Email{}, fmt.Errorf("resolve comment owner did: %w", err) 88 - } 89 - repoOwnerSlashName, err := n.repoOwnerSlashName(ctx, repo) 90 - if err != nil { 91 - return Email{}, nil 92 - } 93 - // TODO: make this configurable 94 - baseUrl := "https://tangled.sh" 95 - url := fmt.Sprintf("%s/%s/pulls/%d#comment-%d", baseUrl, repoOwnerSlashName, comment.PullId, comment.ID) 96 - return Email{ 97 - APIKey: n.Config.Resend.ApiKey, 98 - From: n.Config.Resend.SentFrom, 99 - To: email.Address, 100 - Subject: fmt.Sprintf("[%s] %s (pr#%d)", repoOwnerSlashName, pull.Title, pull.PullId), 101 - Html: fmt.Sprintf(`<p><b>@%s</b> mentioned you:</p><a href="%s">View it on tangled.sh</a>.`, commentOwner.Handle.String(), url), 102 - }, nil 103 - } 104 - 105 70 func (n *EmailNotifier) NewIssueComment(ctx context.Context, repo *db.Repo, issue *db.Issue, comment *db.Comment, mentions []string) { 106 71 resolvedIds := n.idResolver.ResolveIdents(ctx, mentions) 107 72 handleDidMap := make(map[string]string) ··· 120 85 } 121 86 } 122 87 88 + // func (n *EmailNotifier) NewPullComment(ctx context.Context, comment *db.PullComment, []string) { 89 + // n.usersMentioned(ctx, mentions) 90 + // } 123 - func (n *EmailNotifier) NewPullComment(ctx context.Context, repo *db.Repo, pull *db.Pull, comment *db.PullComment, mentions []string) { 124 - resolvedIds := n.idResolver.ResolveIdents(ctx, mentions) 125 - handleDidMap := make(map[string]string) 126 - for _, identity := range resolvedIds { 127 - if !identity.Handle.IsInvalidHandle() { 128 - handleDidMap[identity.Handle.String()] = identity.DID.String() 129 - } 130 - } 131 - for _, handle := range mentions { 132 - id, err := n.idResolver.ResolveIdent(ctx, handle) 133 - email, err := n.buildPullEmail(ctx, repo, pull, comment, id.DID.String()) 134 - if err != nil { 135 - log.Println("failed to create issue-email:", err) 136 - } 137 - SendEmail(email) 138 - } 139 - }
REVERTED
appview/notify/merged_notifier.go
··· 61 61 notifier.NewPull(ctx, pull) 62 62 } 63 63 } 64 + func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *db.PullComment) { 64 - func (m *mergedNotifier) NewPullComment(ctx context.Context, repo *db.Repo, pull *db.Pull, comment *db.PullComment, mentions []string) { 65 65 for _, notifier := range m.notifiers { 66 + notifier.NewPullComment(ctx, comment) 66 - notifier.NewPullComment(ctx, repo, pull, comment, mentions) 67 67 } 68 68 } 69 69
REVERTED
appview/notify/notifier.go
··· 19 19 DeleteFollow(ctx context.Context, follow *db.Follow) 20 20 21 21 NewPull(ctx context.Context, pull *db.Pull) 22 + NewPullComment(ctx context.Context, comment *db.PullComment) 22 - NewPullComment(ctx context.Context, repo *db.Repo, pull *db.Pull, comment *db.PullComment, mentions []string) 23 23 24 24 UpdateProfile(ctx context.Context, profile *db.Profile) 25 25 } ··· 41 41 func (m *BaseNotifier) DeleteFollow(ctx context.Context, follow *db.Follow) {} 42 42 43 43 func (m *BaseNotifier) NewPull(ctx context.Context, pull *db.Pull) {} 44 + func (m *BaseNotifier) NewPullComment(ctx context.Context, comment *db.PullComment) {} 44 - func (m *BaseNotifier) NewPullComment(ctx context.Context, repo *db.Repo, pull *db.Pull, comment *db.PullComment, mentions []string) {} 45 45 46 46 func (m *BaseNotifier) UpdateProfile(ctx context.Context, profile *db.Profile) {}
REVERTED
appview/posthog/notifier.go
··· 98 98 } 99 99 } 100 100 101 + func (n *posthogNotifier) NewPullComment(ctx context.Context, comment *db.PullComment) { 101 - func (n *posthogNotifier) NewPullComment(ctx context.Context, repo *db.Repo, pull *db.Pull, comment *db.PullComment, mentions []string) { 102 102 err := n.client.Enqueue(posthog.Capture{ 103 103 DistinctId: comment.OwnerDid, 104 104 Event: "new_pull_comment",
ERROR
appview/pulls/pulls.go

Failed to calculate interdiff for this file.