Monorepo for Tangled tangled.org

appview: wrap posthog under unified notifier

- Make `db.New*()` methods to accept complete model object instead of
individual fields
- Remove `posthog` field from *most* Service structs. Oauth still has
one as an edge-case
- Add more notifier methods to replace posthog logics

Signed-off-by: Seongmin Lee <boltlessengineer@proton.me>

+2 -2
appview/db/follow.go
··· 12 Rkey string 13 } 14 15 - func AddFollow(e Execer, userDid, subjectDid, rkey string) error { 16 query := `insert or ignore into follows (user_did, subject_did, rkey) values (?, ?, ?)` 17 - _, err := e.Exec(query, userDid, subjectDid, rkey) 18 return err 19 } 20
··· 12 Rkey string 13 } 14 15 + func AddFollow(e Execer, follow *Follow) error { 16 query := `insert or ignore into follows (user_did, subject_did, rkey) values (?, ?, ?)` 17 + _, err := e.Exec(query, follow.UserDid, follow.SubjectDid, follow.Rkey) 18 return err 19 } 20
+7 -2
appview/db/star.go
··· 33 return nil 34 } 35 36 - func AddStar(e Execer, starredByDid string, repoAt syntax.ATURI, rkey string) error { 37 query := `insert or ignore into stars (starred_by_did, repo_at, rkey) values (?, ?, ?)` 38 - _, err := e.Exec(query, starredByDid, repoAt, rkey) 39 return err 40 } 41
··· 33 return nil 34 } 35 36 + func AddStar(e Execer, star *Star) error { 37 query := `insert or ignore into stars (starred_by_did, repo_at, rkey) values (?, ?, ?)` 38 + _, err := e.Exec( 39 + query, 40 + star.StarredByDid, 41 + star.RepoAt.String(), 42 + star.Rkey, 43 + ) 44 return err 45 } 46
+10 -3
appview/ingester.go
··· 100 l.Error("invalid record", "err", err) 101 return err 102 } 103 - err = db.AddStar(i.Db, did, subjectUri, e.Commit.RKey) 104 case models.CommitOperationDelete: 105 err = db.DeleteStarByRkey(i.Db, did, e.Commit.RKey) 106 } ··· 129 return err 130 } 131 132 - subjectDid := record.Subject 133 - err = db.AddFollow(i.Db, did, subjectDid, e.Commit.RKey) 134 case models.CommitOperationDelete: 135 err = db.DeleteFollowByRkey(i.Db, did, e.Commit.RKey) 136 }
··· 100 l.Error("invalid record", "err", err) 101 return err 102 } 103 + err = db.AddStar(i.Db, &db.Star{ 104 + StarredByDid: did, 105 + RepoAt: subjectUri, 106 + Rkey: e.Commit.RKey, 107 + }) 108 case models.CommitOperationDelete: 109 err = db.DeleteStarByRkey(i.Db, did, e.Commit.RKey) 110 } ··· 133 return err 134 } 135 136 + err = db.AddFollow(i.Db, &db.Follow{ 137 + UserDid: did, 138 + SubjectDid: record.Subject, 139 + Rkey: e.Commit.RKey, 140 + }) 141 case models.CommitOperationDelete: 142 err = db.DeleteFollowByRkey(i.Db, did, e.Commit.RKey) 143 }
+5 -14
appview/issues/issues.go
··· 14 "github.com/bluesky-social/indigo/atproto/syntax" 15 lexutil "github.com/bluesky-social/indigo/lex/util" 16 "github.com/go-chi/chi/v5" 17 - "github.com/posthog/posthog-go" 18 19 "tangled.sh/tangled.sh/core/api/tangled" 20 "tangled.sh/tangled.sh/core/appview" 21 "tangled.sh/tangled.sh/core/appview/config" 22 "tangled.sh/tangled.sh/core/appview/db" 23 "tangled.sh/tangled.sh/core/appview/idresolver" 24 "tangled.sh/tangled.sh/core/appview/oauth" 25 "tangled.sh/tangled.sh/core/appview/pages" 26 "tangled.sh/tangled.sh/core/appview/pagination" ··· 34 idResolver *idresolver.Resolver 35 db *db.DB 36 config *config.Config 37 - posthog posthog.Client 38 } 39 40 func New( ··· 44 idResolver *idresolver.Resolver, 45 db *db.DB, 46 config *config.Config, 47 - posthog posthog.Client, 48 ) *Issues { 49 return &Issues{ 50 oauth: oauth, ··· 53 idResolver: idResolver, 54 db: db, 55 config: config, 56 - posthog: posthog, 57 } 58 } 59 ··· 750 return 751 } 752 753 - if !rp.config.Core.Dev { 754 - err = rp.posthog.Enqueue(posthog.Capture{ 755 - DistinctId: user.Did, 756 - Event: "new_issue", 757 - Properties: posthog.Properties{"repo_at": f.RepoAt.String(), "issue_id": issue.IssueId}, 758 - }) 759 - if err != nil { 760 - log.Println("failed to enqueue posthog event:", err) 761 - } 762 - } 763 764 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 765 return
··· 14 "github.com/bluesky-social/indigo/atproto/syntax" 15 lexutil "github.com/bluesky-social/indigo/lex/util" 16 "github.com/go-chi/chi/v5" 17 18 "tangled.sh/tangled.sh/core/api/tangled" 19 "tangled.sh/tangled.sh/core/appview" 20 "tangled.sh/tangled.sh/core/appview/config" 21 "tangled.sh/tangled.sh/core/appview/db" 22 "tangled.sh/tangled.sh/core/appview/idresolver" 23 + "tangled.sh/tangled.sh/core/appview/notify" 24 "tangled.sh/tangled.sh/core/appview/oauth" 25 "tangled.sh/tangled.sh/core/appview/pages" 26 "tangled.sh/tangled.sh/core/appview/pagination" ··· 34 idResolver *idresolver.Resolver 35 db *db.DB 36 config *config.Config 37 + notifier notify.Notifier 38 } 39 40 func New( ··· 44 idResolver *idresolver.Resolver, 45 db *db.DB, 46 config *config.Config, 47 + notifier notify.Notifier, 48 ) *Issues { 49 return &Issues{ 50 oauth: oauth, ··· 53 idResolver: idResolver, 54 db: db, 55 config: config, 56 + notifier: notifier, 57 } 58 } 59 ··· 750 return 751 } 752 753 + rp.notifier.NewIssue(r.Context(), issue) 754 755 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) 756 return
+37 -6
appview/notify/merged_notifier.go
··· 11 } 12 13 func NewMergedNotifier(notifiers ...Notifier) Notifier { 14 - return &mergedNotifier{ 15 - notifiers, 16 - } 17 } 18 19 var _ Notifier = &mergedNotifier{} 20 21 func (m *mergedNotifier) NewIssue(ctx context.Context, issue *db.Issue) { 22 for _, notifier := range m.notifiers { 23 notifier.NewIssue(ctx, issue) 24 } 25 } 26 27 - func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment db.Comment) { 28 for _, notifier := range m.notifiers { 29 - notifier.NewIssueComment(ctx, comment) 30 } 31 } 32 33 - func (m *mergedNotifier) NewPullComment(ctx context.Context, comment db.PullComment) { 34 for _, notifier := range m.notifiers { 35 notifier.NewPullComment(ctx, comment) 36 } 37 }
··· 11 } 12 13 func NewMergedNotifier(notifiers ...Notifier) Notifier { 14 + return &mergedNotifier{notifiers} 15 } 16 17 var _ Notifier = &mergedNotifier{} 18 19 + func (m *mergedNotifier) NewRepo(ctx context.Context, repo *db.Repo) { 20 + for _, notifier := range m.notifiers { 21 + notifier.NewRepo(ctx, repo) 22 + } 23 + } 24 + 25 + func (m *mergedNotifier) NewStar(ctx context.Context, star *db.Star) { 26 + for _, notifier := range m.notifiers { 27 + notifier.NewStar(ctx, star) 28 + } 29 + } 30 + func (m *mergedNotifier) DeleteStar(ctx context.Context, star *db.Star) { 31 + for _, notifier := range m.notifiers { 32 + notifier.DeleteStar(ctx, star) 33 + } 34 + } 35 + 36 func (m *mergedNotifier) NewIssue(ctx context.Context, issue *db.Issue) { 37 for _, notifier := range m.notifiers { 38 notifier.NewIssue(ctx, issue) 39 } 40 } 41 42 + func (m *mergedNotifier) NewFollow(ctx context.Context, follow *db.Follow) { 43 + for _, notifier := range m.notifiers { 44 + notifier.NewFollow(ctx, follow) 45 + } 46 + } 47 + func (m *mergedNotifier) DeleteFollow(ctx context.Context, follow *db.Follow) { 48 for _, notifier := range m.notifiers { 49 + notifier.DeleteFollow(ctx, follow) 50 } 51 } 52 53 + func (m *mergedNotifier) NewPull(ctx context.Context, pull *db.Pull) { 54 + for _, notifier := range m.notifiers { 55 + notifier.NewPull(ctx, pull) 56 + } 57 + } 58 + func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *db.PullComment) { 59 for _, notifier := range m.notifiers { 60 notifier.NewPullComment(ctx, comment) 61 } 62 } 63 + 64 + func (m *mergedNotifier) UpdateProfile(ctx context.Context, profile *db.Profile) { 65 + for _, notifier := range m.notifiers { 66 + notifier.UpdateProfile(ctx, profile) 67 + } 68 + }
+32 -2
appview/notify/notifier.go
··· 7 ) 8 9 type Notifier interface { 10 NewIssue(ctx context.Context, issue *db.Issue) 11 - NewIssueComment(ctx context.Context, comment db.Comment) 12 13 - NewPullComment(ctx context.Context, comment db.PullComment) 14 }
··· 7 ) 8 9 type Notifier interface { 10 + NewRepo(ctx context.Context, repo *db.Repo) 11 + 12 + NewStar(ctx context.Context, star *db.Star) 13 + DeleteStar(ctx context.Context, star *db.Star) 14 + 15 NewIssue(ctx context.Context, issue *db.Issue) 16 + 17 + NewFollow(ctx context.Context, follow *db.Follow) 18 + DeleteFollow(ctx context.Context, follow *db.Follow) 19 + 20 + NewPull(ctx context.Context, pull *db.Pull) 21 + NewPullComment(ctx context.Context, comment *db.PullComment) 22 23 + UpdateProfile(ctx context.Context, profile *db.Profile) 24 } 25 + 26 + // BaseNotifier is a listener that does nothing 27 + type BaseNotifier struct{} 28 + 29 + var _ Notifier = &BaseNotifier{} 30 + 31 + func (m *BaseNotifier) NewRepo(ctx context.Context, repo *db.Repo) {} 32 + 33 + func (m *BaseNotifier) NewStar(ctx context.Context, star *db.Star) {} 34 + func (m *BaseNotifier) DeleteStar(ctx context.Context, star *db.Star) {} 35 + 36 + func (m *BaseNotifier) NewIssue(ctx context.Context, issue *db.Issue) {} 37 + 38 + func (m *BaseNotifier) NewFollow(ctx context.Context, follow *db.Follow) {} 39 + func (m *BaseNotifier) DeleteFollow(ctx context.Context, follow *db.Follow) {} 40 + 41 + func (m *BaseNotifier) NewPull(ctx context.Context, pull *db.Pull) {} 42 + func (m *BaseNotifier) NewPullComment(ctx context.Context, comment *db.PullComment) {} 43 + 44 + func (m *BaseNotifier) UpdateProfile(ctx context.Context, profile *db.Profile) {}
-4
appview/pipelines/pipelines.go
··· 22 23 "github.com/go-chi/chi/v5" 24 "github.com/gorilla/websocket" 25 - "github.com/posthog/posthog-go" 26 ) 27 28 type Pipelines struct { ··· 34 spindlestream *eventconsumer.Consumer 35 db *db.DB 36 enforcer *rbac.Enforcer 37 - posthog posthog.Client 38 logger *slog.Logger 39 } 40 ··· 46 idResolver *idresolver.Resolver, 47 db *db.DB, 48 config *config.Config, 49 - posthog posthog.Client, 50 enforcer *rbac.Enforcer, 51 ) *Pipelines { 52 logger := log.New("pipelines") ··· 58 config: config, 59 spindlestream: spindlestream, 60 db: db, 61 - posthog: posthog, 62 enforcer: enforcer, 63 logger: logger, 64 }
··· 22 23 "github.com/go-chi/chi/v5" 24 "github.com/gorilla/websocket" 25 ) 26 27 type Pipelines struct { ··· 33 spindlestream *eventconsumer.Consumer 34 db *db.DB 35 enforcer *rbac.Enforcer 36 logger *slog.Logger 37 } 38 ··· 44 idResolver *idresolver.Resolver, 45 db *db.DB, 46 config *config.Config, 47 enforcer *rbac.Enforcer, 48 ) *Pipelines { 49 logger := log.New("pipelines") ··· 55 config: config, 56 spindlestream: spindlestream, 57 db: db, 58 enforcer: enforcer, 59 logger: logger, 60 }
+131
appview/posthog/notifier.go
···
··· 1 + package posthog_service 2 + 3 + import ( 4 + "context" 5 + "log" 6 + 7 + "github.com/posthog/posthog-go" 8 + "tangled.sh/tangled.sh/core/appview/db" 9 + "tangled.sh/tangled.sh/core/appview/notify" 10 + ) 11 + 12 + type posthogNotifier struct { 13 + client posthog.Client 14 + notify.BaseNotifier 15 + } 16 + 17 + func NewPosthogNotifier(client posthog.Client) notify.Notifier { 18 + return &posthogNotifier{ 19 + client, 20 + notify.BaseNotifier{}, 21 + } 22 + } 23 + 24 + var _ notify.Notifier = &posthogNotifier{} 25 + 26 + func (n *posthogNotifier) NewRepo(ctx context.Context, repo *db.Repo) { 27 + err := n.client.Enqueue(posthog.Capture{ 28 + DistinctId: repo.Did, 29 + Event: "new_repo", 30 + Properties: posthog.Properties{"repo": repo.Name, "repo_at": repo.RepoAt()}, 31 + }) 32 + if err != nil { 33 + log.Println("failed to enqueue posthog event:", err) 34 + } 35 + } 36 + 37 + func (n *posthogNotifier) NewStar(ctx context.Context, star *db.Star) { 38 + err := n.client.Enqueue(posthog.Capture{ 39 + DistinctId: star.StarredByDid, 40 + Event: "star", 41 + Properties: posthog.Properties{"repo_at": star.RepoAt.String()}, 42 + }) 43 + if err != nil { 44 + log.Println("failed to enqueue posthog event:", err) 45 + } 46 + } 47 + 48 + func (n *posthogNotifier) DeleteStar(ctx context.Context, star *db.Star) { 49 + err := n.client.Enqueue(posthog.Capture{ 50 + DistinctId: star.StarredByDid, 51 + Event: "unstar", 52 + Properties: posthog.Properties{"repo_at": star.RepoAt.String()}, 53 + }) 54 + if err != nil { 55 + log.Println("failed to enqueue posthog event:", err) 56 + } 57 + } 58 + 59 + func (n *posthogNotifier) NewIssue(ctx context.Context, issue *db.Issue) { 60 + err := n.client.Enqueue(posthog.Capture{ 61 + DistinctId: issue.OwnerDid, 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 { 69 + log.Println("failed to enqueue posthog event:", err) 70 + } 71 + } 72 + 73 + func (n *posthogNotifier) NewPull(ctx context.Context, pull *db.Pull) { 74 + err := n.client.Enqueue(posthog.Capture{ 75 + DistinctId: pull.OwnerDid, 76 + Event: "new_pull", 77 + Properties: posthog.Properties{ 78 + "repo_at": pull.RepoAt, 79 + "pull_id": pull.PullId, 80 + }, 81 + }) 82 + if err != nil { 83 + log.Println("failed to enqueue posthog event:", err) 84 + } 85 + } 86 + 87 + func (n *posthogNotifier) NewPullComment(ctx context.Context, comment *db.PullComment) { 88 + err := n.client.Enqueue(posthog.Capture{ 89 + DistinctId: comment.OwnerDid, 90 + Event: "new_pull_comment", 91 + Properties: posthog.Properties{ 92 + "repo_at": comment.RepoAt, 93 + "pull_id": comment.PullId, 94 + }, 95 + }) 96 + if err != nil { 97 + log.Println("failed to enqueue posthog event:", err) 98 + } 99 + } 100 + 101 + func (n *posthogNotifier) NewFollow(ctx context.Context, follow *db.Follow) { 102 + err := n.client.Enqueue(posthog.Capture{ 103 + DistinctId: follow.UserDid, 104 + Event: "follow", 105 + Properties: posthog.Properties{"subject": follow.SubjectDid}, 106 + }) 107 + if err != nil { 108 + log.Println("failed to enqueue posthog event:", err) 109 + } 110 + } 111 + 112 + func (n *posthogNotifier) DeleteFollow(ctx context.Context, follow *db.Follow) { 113 + err := n.client.Enqueue(posthog.Capture{ 114 + DistinctId: follow.UserDid, 115 + Event: "unfollow", 116 + Properties: posthog.Properties{"subject": follow.SubjectDid}, 117 + }) 118 + if err != nil { 119 + log.Println("failed to enqueue posthog event:", err) 120 + } 121 + } 122 + 123 + func (n *posthogNotifier) UpdateProfile(ctx context.Context, profile *db.Profile) { 124 + err := n.client.Enqueue(posthog.Capture{ 125 + DistinctId: profile.Did, 126 + Event: "edit_profile", 127 + }) 128 + if err != nil { 129 + log.Println("failed to enqueue posthog event:", err) 130 + } 131 + }
+14 -29
appview/pulls/pulls.go
··· 18 "tangled.sh/tangled.sh/core/appview/config" 19 "tangled.sh/tangled.sh/core/appview/db" 20 "tangled.sh/tangled.sh/core/appview/idresolver" 21 "tangled.sh/tangled.sh/core/appview/oauth" 22 "tangled.sh/tangled.sh/core/appview/pages" 23 "tangled.sh/tangled.sh/core/appview/reporesolver" ··· 31 lexutil "github.com/bluesky-social/indigo/lex/util" 32 "github.com/go-chi/chi/v5" 33 "github.com/google/uuid" 34 - "github.com/posthog/posthog-go" 35 ) 36 37 type Pulls struct { ··· 41 idResolver *idresolver.Resolver 42 db *db.DB 43 config *config.Config 44 - posthog posthog.Client 45 } 46 47 func New( ··· 51 resolver *idresolver.Resolver, 52 db *db.DB, 53 config *config.Config, 54 - posthog posthog.Client, 55 ) *Pulls { 56 return &Pulls{ 57 oauth: oauth, ··· 60 idResolver: resolver, 61 db: db, 62 config: config, 63 - posthog: posthog, 64 } 65 } 66 ··· 685 return 686 } 687 688 - // Create the pull comment in the database with the commentAt field 689 - commentId, err := db.NewPullComment(tx, &db.PullComment{ 690 OwnerDid: user.Did, 691 RepoAt: f.RepoAt.String(), 692 PullId: pull.PullId, 693 Body: body, 694 CommentAt: atResp.Uri, 695 SubmissionId: pull.Submissions[roundNumber].ID, 696 - }) 697 if err != nil { 698 log.Println("failed to create pull comment", err) 699 s.pages.Notice(w, "pull-comment", "Failed to create comment.") ··· 707 return 708 } 709 710 - if !s.config.Core.Dev { 711 - err = s.posthog.Enqueue(posthog.Capture{ 712 - DistinctId: user.Did, 713 - Event: "new_pull_comment", 714 - Properties: posthog.Properties{"repo_at": f.RepoAt.String(), "pull_id": pull.PullId}, 715 - }) 716 - if err != nil { 717 - log.Println("failed to enqueue posthog event:", err) 718 - } 719 - } 720 721 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", f.OwnerSlashRepo(), pull.PullId, commentId)) 722 return ··· 1050 Patch: patch, 1051 SourceRev: sourceRev, 1052 } 1053 - err = db.NewPull(tx, &db.Pull{ 1054 Title: title, 1055 Body: body, 1056 TargetBranch: targetBranch, ··· 1061 &initialSubmission, 1062 }, 1063 PullSource: pullSource, 1064 - }) 1065 if err != nil { 1066 log.Println("failed to create pull request", err) 1067 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") ··· 1101 return 1102 } 1103 1104 - if !s.config.Core.Dev { 1105 - err = s.posthog.Enqueue(posthog.Capture{ 1106 - DistinctId: user.Did, 1107 - Event: "new_pull", 1108 - Properties: posthog.Properties{"repo_at": f.RepoAt.String(), "pull_id": pullId}, 1109 - }) 1110 - if err != nil { 1111 - log.Println("failed to enqueue posthog event:", err) 1112 - } 1113 - } 1114 1115 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId)) 1116 }
··· 18 "tangled.sh/tangled.sh/core/appview/config" 19 "tangled.sh/tangled.sh/core/appview/db" 20 "tangled.sh/tangled.sh/core/appview/idresolver" 21 + "tangled.sh/tangled.sh/core/appview/notify" 22 "tangled.sh/tangled.sh/core/appview/oauth" 23 "tangled.sh/tangled.sh/core/appview/pages" 24 "tangled.sh/tangled.sh/core/appview/reporesolver" ··· 32 lexutil "github.com/bluesky-social/indigo/lex/util" 33 "github.com/go-chi/chi/v5" 34 "github.com/google/uuid" 35 ) 36 37 type Pulls struct { ··· 41 idResolver *idresolver.Resolver 42 db *db.DB 43 config *config.Config 44 + notifier notify.Notifier 45 } 46 47 func New( ··· 51 resolver *idresolver.Resolver, 52 db *db.DB, 53 config *config.Config, 54 + notifier notify.Notifier, 55 ) *Pulls { 56 return &Pulls{ 57 oauth: oauth, ··· 60 idResolver: resolver, 61 db: db, 62 config: config, 63 + notifier: notifier, 64 } 65 } 66 ··· 685 return 686 } 687 688 + comment := &db.PullComment{ 689 OwnerDid: user.Did, 690 RepoAt: f.RepoAt.String(), 691 PullId: pull.PullId, 692 Body: body, 693 CommentAt: atResp.Uri, 694 SubmissionId: pull.Submissions[roundNumber].ID, 695 + } 696 + 697 + // Create the pull comment in the database with the commentAt field 698 + commentId, err := db.NewPullComment(tx, comment) 699 if err != nil { 700 log.Println("failed to create pull comment", err) 701 s.pages.Notice(w, "pull-comment", "Failed to create comment.") ··· 709 return 710 } 711 712 + s.notifier.NewPullComment(r.Context(), comment) 713 714 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", f.OwnerSlashRepo(), pull.PullId, commentId)) 715 return ··· 1043 Patch: patch, 1044 SourceRev: sourceRev, 1045 } 1046 + pull := &db.Pull{ 1047 Title: title, 1048 Body: body, 1049 TargetBranch: targetBranch, ··· 1054 &initialSubmission, 1055 }, 1056 PullSource: pullSource, 1057 + } 1058 + err = db.NewPull(tx, pull) 1059 if err != nil { 1060 log.Println("failed to create pull request", err) 1061 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") ··· 1095 return 1096 } 1097 1098 + s.notifier.NewPull(r.Context(), pull) 1099 1100 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId)) 1101 }
+4 -4
appview/repo/repo.go
··· 21 "tangled.sh/tangled.sh/core/appview/config" 22 "tangled.sh/tangled.sh/core/appview/db" 23 "tangled.sh/tangled.sh/core/appview/idresolver" 24 "tangled.sh/tangled.sh/core/appview/oauth" 25 "tangled.sh/tangled.sh/core/appview/pages" 26 "tangled.sh/tangled.sh/core/appview/pages/markup" ··· 34 securejoin "github.com/cyphar/filepath-securejoin" 35 "github.com/go-chi/chi/v5" 36 "github.com/go-git/go-git/v5/plumbing" 37 - "github.com/posthog/posthog-go" 38 39 comatproto "github.com/bluesky-social/indigo/api/atproto" 40 lexutil "github.com/bluesky-social/indigo/lex/util" ··· 49 spindlestream *eventconsumer.Consumer 50 db *db.DB 51 enforcer *rbac.Enforcer 52 - posthog posthog.Client 53 } 54 55 func New( ··· 60 idResolver *idresolver.Resolver, 61 db *db.DB, 62 config *config.Config, 63 - posthog posthog.Client, 64 enforcer *rbac.Enforcer, 65 ) *Repo { 66 return &Repo{oauth: oauth, ··· 70 config: config, 71 spindlestream: spindlestream, 72 db: db, 73 - posthog: posthog, 74 enforcer: enforcer, 75 } 76 }
··· 21 "tangled.sh/tangled.sh/core/appview/config" 22 "tangled.sh/tangled.sh/core/appview/db" 23 "tangled.sh/tangled.sh/core/appview/idresolver" 24 + "tangled.sh/tangled.sh/core/appview/notify" 25 "tangled.sh/tangled.sh/core/appview/oauth" 26 "tangled.sh/tangled.sh/core/appview/pages" 27 "tangled.sh/tangled.sh/core/appview/pages/markup" ··· 35 securejoin "github.com/cyphar/filepath-securejoin" 36 "github.com/go-chi/chi/v5" 37 "github.com/go-git/go-git/v5/plumbing" 38 39 comatproto "github.com/bluesky-social/indigo/api/atproto" 40 lexutil "github.com/bluesky-social/indigo/lex/util" ··· 49 spindlestream *eventconsumer.Consumer 50 db *db.DB 51 enforcer *rbac.Enforcer 52 + notifier notify.Notifier 53 } 54 55 func New( ··· 60 idResolver *idresolver.Resolver, 61 db *db.DB, 62 config *config.Config, 63 + notifier notify.Notifier, 64 enforcer *rbac.Enforcer, 65 ) *Repo { 66 return &Repo{oauth: oauth, ··· 70 config: config, 71 spindlestream: spindlestream, 72 db: db, 73 + notifier: notifier, 74 enforcer: enforcer, 75 } 76 }
+11 -24
appview/state/follow.go
··· 7 8 comatproto "github.com/bluesky-social/indigo/api/atproto" 9 lexutil "github.com/bluesky-social/indigo/lex/util" 10 - "github.com/posthog/posthog-go" 11 "tangled.sh/tangled.sh/core/api/tangled" 12 "tangled.sh/tangled.sh/core/appview" 13 "tangled.sh/tangled.sh/core/appview/db" ··· 58 return 59 } 60 61 - err = db.AddFollow(s.db, currentUser.Did, subjectIdent.DID.String(), rkey) 62 if err != nil { 63 log.Println("failed to follow", err) 64 return 65 } 66 67 - log.Println("created atproto record: ", resp.Uri) 68 69 s.pages.FollowFragment(w, pages.FollowFragmentParams{ 70 UserDid: subjectIdent.DID.String(), 71 FollowStatus: db.IsFollowing, 72 }) 73 74 - if !s.config.Core.Dev { 75 - err = s.posthog.Enqueue(posthog.Capture{ 76 - DistinctId: currentUser.Did, 77 - Event: "follow", 78 - Properties: posthog.Properties{"subject": subjectIdent.DID.String()}, 79 - }) 80 - if err != nil { 81 - log.Println("failed to enqueue posthog event:", err) 82 - } 83 - } 84 - 85 return 86 case http.MethodDelete: 87 // find the record in the db ··· 113 FollowStatus: db.IsNotFollowing, 114 }) 115 116 - if !s.config.Core.Dev { 117 - err = s.posthog.Enqueue(posthog.Capture{ 118 - DistinctId: currentUser.Did, 119 - Event: "unfollow", 120 - Properties: posthog.Properties{"subject": subjectIdent.DID.String()}, 121 - }) 122 - if err != nil { 123 - log.Println("failed to enqueue posthog event:", err) 124 - } 125 - } 126 127 return 128 }
··· 7 8 comatproto "github.com/bluesky-social/indigo/api/atproto" 9 lexutil "github.com/bluesky-social/indigo/lex/util" 10 "tangled.sh/tangled.sh/core/api/tangled" 11 "tangled.sh/tangled.sh/core/appview" 12 "tangled.sh/tangled.sh/core/appview/db" ··· 57 return 58 } 59 60 + log.Println("created atproto record: ", resp.Uri) 61 + 62 + follow := &db.Follow{ 63 + UserDid: currentUser.Did, 64 + SubjectDid: subjectIdent.DID.String(), 65 + Rkey: rkey, 66 + } 67 + 68 + err = db.AddFollow(s.db, follow) 69 if err != nil { 70 log.Println("failed to follow", err) 71 return 72 } 73 74 + s.notifier.NewFollow(r.Context(), follow) 75 76 s.pages.FollowFragment(w, pages.FollowFragmentParams{ 77 UserDid: subjectIdent.DID.String(), 78 FollowStatus: db.IsFollowing, 79 }) 80 81 return 82 case http.MethodDelete: 83 // find the record in the db ··· 109 FollowStatus: db.IsNotFollowing, 110 }) 111 112 + s.notifier.DeleteFollow(r.Context(), follow) 113 114 return 115 }
+1 -10
appview/state/profile.go
··· 16 "github.com/bluesky-social/indigo/atproto/syntax" 17 lexutil "github.com/bluesky-social/indigo/lex/util" 18 "github.com/go-chi/chi/v5" 19 - "github.com/posthog/posthog-go" 20 "tangled.sh/tangled.sh/core/api/tangled" 21 "tangled.sh/tangled.sh/core/appview/db" 22 "tangled.sh/tangled.sh/core/appview/pages" ··· 371 return 372 } 373 374 - if !s.config.Core.Dev { 375 - err = s.posthog.Enqueue(posthog.Capture{ 376 - DistinctId: user.Did, 377 - Event: "edit_profile", 378 - }) 379 - if err != nil { 380 - log.Println("failed to enqueue posthog event:", err) 381 - } 382 - } 383 384 s.pages.HxRedirect(w, "/"+user.Did) 385 return
··· 16 "github.com/bluesky-social/indigo/atproto/syntax" 17 lexutil "github.com/bluesky-social/indigo/lex/util" 18 "github.com/go-chi/chi/v5" 19 "tangled.sh/tangled.sh/core/api/tangled" 20 "tangled.sh/tangled.sh/core/appview/db" 21 "tangled.sh/tangled.sh/core/appview/pages" ··· 370 return 371 } 372 373 + s.notifier.UpdateProfile(r.Context(), profile) 374 375 s.pages.HxRedirect(w, "/"+user.Did) 376 return
+4 -4
appview/state/router.go
··· 198 } 199 200 func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { 201 - issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.posthog) 202 return issues.Router(mw) 203 } 204 205 func (s *State) PullsRouter(mw *middleware.Middleware) http.Handler { 206 - pulls := pulls.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.posthog) 207 return pulls.Router(mw) 208 } 209 210 func (s *State) RepoRouter(mw *middleware.Middleware) http.Handler { 211 - repo := repo.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.posthog, s.enforcer) 212 return repo.Router(mw) 213 } 214 215 func (s *State) PipelinesRouter(mw *middleware.Middleware) http.Handler { 216 - pipes := pipelines.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.posthog, s.enforcer) 217 return pipes.Router(mw) 218 }
··· 198 } 199 200 func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { 201 + issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier) 202 return issues.Router(mw) 203 } 204 205 func (s *State) PullsRouter(mw *middleware.Middleware) http.Handler { 206 + pulls := pulls.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier) 207 return pulls.Router(mw) 208 } 209 210 func (s *State) RepoRouter(mw *middleware.Middleware) http.Handler { 211 + repo := repo.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.notifier, s.enforcer) 212 return repo.Router(mw) 213 } 214 215 func (s *State) PipelinesRouter(mw *middleware.Middleware) http.Handler { 216 + pipes := pipelines.New(s.oauth, s.repoResolver, s.pages, s.spindlestream, s.idResolver, s.db, s.config, s.enforcer) 217 return pipes.Router(mw) 218 }
+11 -25
appview/state/star.go
··· 8 comatproto "github.com/bluesky-social/indigo/api/atproto" 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 lexutil "github.com/bluesky-social/indigo/lex/util" 11 - "github.com/posthog/posthog-go" 12 "tangled.sh/tangled.sh/core/api/tangled" 13 "tangled.sh/tangled.sh/core/appview" 14 "tangled.sh/tangled.sh/core/appview/db" ··· 54 log.Println("failed to create atproto record", err) 55 return 56 } 57 58 - err = db.AddStar(s.db, currentUser.Did, subjectUri, rkey) 59 if err != nil { 60 log.Println("failed to star", err) 61 return ··· 66 log.Println("failed to get star count for ", subjectUri) 67 } 68 69 - log.Println("created atproto record: ", resp.Uri) 70 71 s.pages.RepoActionsFragment(w, pages.RepoActionsFragmentParams{ 72 IsStarred: true, ··· 76 }, 77 }) 78 79 - if !s.config.Core.Dev { 80 - err = s.posthog.Enqueue(posthog.Capture{ 81 - DistinctId: currentUser.Did, 82 - Event: "star", 83 - Properties: posthog.Properties{"repo_at": subjectUri.String()}, 84 - }) 85 - if err != nil { 86 - log.Println("failed to enqueue posthog event:", err) 87 - } 88 - } 89 - 90 return 91 case http.MethodDelete: 92 // find the record in the db ··· 119 return 120 } 121 122 s.pages.RepoActionsFragment(w, pages.RepoActionsFragmentParams{ 123 IsStarred: false, 124 RepoAt: subjectUri, ··· 126 StarCount: starCount, 127 }, 128 }) 129 - 130 - if !s.config.Core.Dev { 131 - err = s.posthog.Enqueue(posthog.Capture{ 132 - DistinctId: currentUser.Did, 133 - Event: "unstar", 134 - Properties: posthog.Properties{"repo_at": subjectUri.String()}, 135 - }) 136 - if err != nil { 137 - log.Println("failed to enqueue posthog event:", err) 138 - } 139 - } 140 141 return 142 }
··· 8 comatproto "github.com/bluesky-social/indigo/api/atproto" 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 lexutil "github.com/bluesky-social/indigo/lex/util" 11 "tangled.sh/tangled.sh/core/api/tangled" 12 "tangled.sh/tangled.sh/core/appview" 13 "tangled.sh/tangled.sh/core/appview/db" ··· 53 log.Println("failed to create atproto record", err) 54 return 55 } 56 + log.Println("created atproto record: ", resp.Uri) 57 58 + star := &db.Star{ 59 + StarredByDid: currentUser.Did, 60 + RepoAt: subjectUri, 61 + Rkey: rkey, 62 + } 63 + 64 + err = db.AddStar(s.db, star) 65 if err != nil { 66 log.Println("failed to star", err) 67 return ··· 72 log.Println("failed to get star count for ", subjectUri) 73 } 74 75 + s.notifier.NewStar(r.Context(), star) 76 77 s.pages.RepoActionsFragment(w, pages.RepoActionsFragmentParams{ 78 IsStarred: true, ··· 82 }, 83 }) 84 85 return 86 case http.MethodDelete: 87 // find the record in the db ··· 114 return 115 } 116 117 + s.notifier.DeleteStar(r.Context(), star) 118 + 119 s.pages.RepoActionsFragment(w, pages.RepoActionsFragmentParams{ 120 IsStarred: false, 121 RepoAt: subjectUri, ··· 123 StarCount: starCount, 124 }, 125 }) 126 127 return 128 }
+3 -10
appview/state/state.go
··· 25 "tangled.sh/tangled.sh/core/appview/notify" 26 "tangled.sh/tangled.sh/core/appview/oauth" 27 "tangled.sh/tangled.sh/core/appview/pages" 28 "tangled.sh/tangled.sh/core/appview/reporesolver" 29 "tangled.sh/tangled.sh/core/eventconsumer" 30 "tangled.sh/tangled.sh/core/jetstream" ··· 134 spindlestream.Start(ctx) 135 136 notifier := notify.NewMergedNotifier( 137 ) 138 139 state := &State{ ··· 766 return 767 } 768 769 - if !s.config.Core.Dev { 770 - err = s.posthog.Enqueue(posthog.Capture{ 771 - DistinctId: user.Did, 772 - Event: "new_repo", 773 - Properties: posthog.Properties{"repo": repoName, "repo_at": repo.AtUri}, 774 - }) 775 - if err != nil { 776 - log.Println("failed to enqueue posthog event:", err) 777 - } 778 - } 779 780 s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s", user.Handle, repoName)) 781 return
··· 25 "tangled.sh/tangled.sh/core/appview/notify" 26 "tangled.sh/tangled.sh/core/appview/oauth" 27 "tangled.sh/tangled.sh/core/appview/pages" 28 + posthog_service "tangled.sh/tangled.sh/core/appview/posthog" 29 "tangled.sh/tangled.sh/core/appview/reporesolver" 30 "tangled.sh/tangled.sh/core/eventconsumer" 31 "tangled.sh/tangled.sh/core/jetstream" ··· 135 spindlestream.Start(ctx) 136 137 notifier := notify.NewMergedNotifier( 138 + posthog_service.NewPosthogNotifier(posthog), 139 ) 140 141 state := &State{ ··· 768 return 769 } 770 771 + s.notifier.NewRepo(r.Context(), repo) 772 773 s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s", user.Handle, repoName)) 774 return