Monorepo for Tangled tangled.org
858
fork

Configure Feed

Select the types of activity you want to include in your feed.

appview/oauth,notify: DID-based PDS record rewriting #274

open opened by oyster.cafe targeting master from lt/repo-rename-by-rkey
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:3fwecdnvtcscjnrx2p4n7alz/sh.tangled.repo.pull/3mjm6w2jh5x22
+212 -108
Diff #4
+87 -44
appview/migration/migrate_add_repo_did.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "encoding/json" 5 6 "fmt" 6 7 "strings" 7 8 ··· 14 15 ) 15 16 16 17 func (s *Migration) migrateAddRepoDid(ctx context.Context, client *atclient.APIClient, did syntax.DID, record syntax.ATURI) error { 17 - // TODO: use agnostic.RepoGetRecord instead 18 + if record.Collection().String() == tangled.FeedStarNSID { 19 + return s.migrateAddRepoDidStar(ctx, client, did, record) 20 + } 21 + 18 22 ex, err := comatproto.RepoGetRecord(ctx, client, "", record.Collection().String(), did.String(), record.RecordKey().String()) 19 23 if err != nil { 20 24 return fmt.Errorf("pds: %w", err) ··· 22 26 23 27 val := ex.Value.Val 24 28 25 - switch record.Collection() { 29 + switch record.Collection().String() { 26 30 case tangled.RepoNSID: 27 31 rec, ok := val.(*tangled.Repo) 28 32 if !ok { ··· 39 43 if !ok { 40 44 return fmt.Errorf("unexpected type for issue record") 41 45 } 42 - if rec.Repo != nil { 43 - repoAt := *rec.Repo 44 - repo, err := db.GetRepoByAtUri(s.db, repoAt) 45 - if err != nil { 46 - return fmt.Errorf("db: failed to query repo: %w", err) 47 - } 48 - rec.RepoDid = &repo.RepoDid 46 + if strings.HasPrefix(rec.Repo, "did:") { 47 + return nil 49 48 } 49 + repo, err := db.GetRepoByAtUri(s.db, rec.Repo) 50 + if err != nil { 51 + return fmt.Errorf("db: failed to query repo by at_uri %q: %w", rec.Repo, err) 52 + } 53 + rec.Repo = repo.RepoDid 50 54 51 55 case tangled.RepoPullNSID: 52 56 rec, ok := val.(*tangled.RepoPull) 53 57 if !ok { 54 58 return fmt.Errorf("unexpected type for pull record") 55 59 } 56 - if rec.Target != nil && rec.Target.Repo != nil { 57 - repoAt := *rec.Target.Repo 58 - repo, err := db.GetRepoByAtUri(s.db, repoAt) 60 + if rec.Target == nil { 61 + return fmt.Errorf("pull record has nil target") 62 + } 63 + if !strings.HasPrefix(rec.Target.Repo, "did:") { 64 + repo, err := db.GetRepoByAtUri(s.db, rec.Target.Repo) 59 65 if err != nil { 60 - return fmt.Errorf("db: failed to query repo: %w", err) 66 + return fmt.Errorf("db: failed to query target repo by at_uri %q: %w", rec.Target.Repo, err) 61 67 } 62 - rec.Target.RepoDid = &repo.RepoDid 68 + rec.Target.Repo = repo.RepoDid 63 69 } 64 - if rec.Source != nil && rec.Source.Repo != nil { 65 - repoAt := *rec.Source.Repo 66 - repo, err := db.GetRepoByAtUri(s.db, repoAt) 67 - if err != nil { 68 - return fmt.Errorf("db: failed to query repo: %w", err) 70 + if rec.Source != nil && rec.Source.Repo != nil && !strings.HasPrefix(*rec.Source.Repo, "did:") { 71 + sourceRepo, srcErr := db.GetRepoByAtUri(s.db, *rec.Source.Repo) 72 + if srcErr == nil && sourceRepo.RepoDid != "" { 73 + rec.Source.Repo = &sourceRepo.RepoDid 69 74 } 70 - rec.Source.RepoDid = &repo.RepoDid 71 75 } 72 76 73 77 case tangled.RepoCollaboratorNSID: ··· 75 79 if !ok { 76 80 return fmt.Errorf("unexpected type for collaborator record") 77 81 } 78 - if rec.Repo != nil { 79 - repoAt := *rec.Repo 80 - repo, err := db.GetRepoByAtUri(s.db, repoAt) 81 - if err != nil { 82 - return fmt.Errorf("db: failed to query repo: %w", err) 83 - } 84 - rec.RepoDid = &repo.RepoDid 82 + if strings.HasPrefix(rec.Repo, "did:") { 83 + return nil 84 + } 85 + repo, err := db.GetRepoByAtUri(s.db, rec.Repo) 86 + if err != nil { 87 + return fmt.Errorf("db: failed to query repo by at_uri %q: %w", rec.Repo, err) 85 88 } 89 + rec.Repo = repo.RepoDid 86 90 87 91 case tangled.RepoArtifactNSID: 88 92 rec, ok := val.(*tangled.RepoArtifact) ··· 90 94 return fmt.Errorf("unexpected type for artifact record") 91 95 } 92 96 if rec.Repo != nil { 93 - repoAt := *rec.Repo 94 - repo, err := db.GetRepoByAtUri(s.db, repoAt) 97 + repo, err := db.GetRepoByAtUri(s.db, *rec.Repo) 95 98 if err != nil { 96 - return fmt.Errorf("db: failed to query repo: %w", err) 99 + return fmt.Errorf("db: failed to query repo by at_uri %q: %w", *rec.Repo, err) 97 100 } 98 101 rec.RepoDid = &repo.RepoDid 99 102 } 100 103 101 - case tangled.FeedStarNSID: 102 - rec, ok := val.(*tangled.FeedStar) 103 - if !ok { 104 - return fmt.Errorf("unexpected type for star record") 105 - } 106 - if rec.Subject != nil { 107 - repoAt := *rec.Subject 108 - repo, err := db.GetRepoByAtUri(s.db, repoAt) 109 - if err != nil { 110 - return fmt.Errorf("db: failed to query repo: %w", err) 111 - } 112 - rec.SubjectDid = &repo.RepoDid 113 - } 114 - 115 104 case tangled.ActorProfileNSID: 116 105 rec, ok := val.(*tangled.ActorProfile) 117 106 if !ok { ··· 149 138 150 139 return nil 151 140 } 141 + 142 + func (s *Migration) migrateAddRepoDidStar(ctx context.Context, client *atclient.APIClient, did syntax.DID, record syntax.ATURI) error { 143 + var raw struct { 144 + Cid *string `json:"cid,omitempty"` 145 + Uri string `json:"uri"` 146 + Value json.RawMessage `json:"value"` 147 + } 148 + params := map[string]any{ 149 + "collection": record.Collection().String(), 150 + "repo": did.String(), 151 + "rkey": record.RecordKey().String(), 152 + } 153 + if err := client.LexDo(ctx, lexutil.Query, "", "com.atproto.repo.getRecord", params, nil, &raw); err != nil { 154 + return fmt.Errorf("get record: %w", err) 155 + } 156 + 157 + var legacy struct { 158 + CreatedAt string `json:"createdAt"` 159 + Subject *string `json:"subject,omitempty"` 160 + } 161 + if err := json.Unmarshal(raw.Value, &legacy); err != nil { 162 + return fmt.Errorf("decode old star fields: %w", err) 163 + } 164 + if legacy.Subject == nil { 165 + return fmt.Errorf("star record has no subject field") 166 + } 167 + 168 + repo, err := db.GetRepoByAtUri(s.db, *legacy.Subject) 169 + if err != nil { 170 + return fmt.Errorf("db: failed to query repo by at_uri %q: %w", *legacy.Subject, err) 171 + } 172 + if repo.RepoDid == "" { 173 + return fmt.Errorf("repo has no repoDid: %s", *legacy.Subject) 174 + } 175 + 176 + newRecord := &tangled.FeedStar{ 177 + CreatedAt: legacy.CreatedAt, 178 + Subject: &tangled.FeedStar_Subject{ 179 + FeedStar_Repo: &tangled.FeedStar_Repo{Did: repo.RepoDid}, 180 + }, 181 + } 182 + 183 + _, err = comatproto.RepoPutRecord(ctx, client, &comatproto.RepoPutRecord_Input{ 184 + Repo: did.String(), 185 + Collection: record.Collection().String(), 186 + Rkey: record.RecordKey().String(), 187 + SwapRecord: raw.Cid, 188 + Record: &lexutil.LexiconTypeDecoder{Val: newRecord}, 189 + }) 190 + if err != nil { 191 + return fmt.Errorf("put record: %w", err) 192 + } 193 + return nil 194 + }
+15 -14
appview/notify/db/db.go
··· 5 5 "slices" 6 6 7 7 "github.com/bluesky-social/indigo/atproto/syntax" 8 - "tangled.org/core/api/tangled" 9 8 "tangled.org/core/appview/db" 10 9 "tangled.org/core/appview/models" 11 10 "tangled.org/core/appview/notify" ··· 40 39 // no-op for now 41 40 } 42 41 42 + func (n *databaseNotifier) RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) { 43 + } 44 + 43 45 func (n *databaseNotifier) NewStar(ctx context.Context, star *models.Star) { 44 46 l := log.FromContext(ctx) 45 47 46 - if star.RepoAt.Collection().String() != tangled.RepoNSID { 47 - // skip string stars for now 48 + if star.SubjectType != models.StarSubjectRepo { 48 49 return 49 50 } 50 - var err error 51 - repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(star.RepoAt))) 51 + 52 + repo, err := db.GetRepo(n.db, orm.FilterEq("repo_did", star.Subject)) 52 53 if err != nil { 53 54 l.Error("failed to get repos", "err", err) 54 55 return ··· 58 59 recipients := sets.Singleton(syntax.DID(repo.Did)) 59 60 eventType := models.NotificationTypeRepoStarred 60 61 entityType := "repo" 61 - entityId := star.RepoAt.String() 62 + entityId := star.Subject 62 63 repoId := &repo.Id 63 64 var issueId *int64 64 65 var pullId *int64 ··· 83 84 func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) { 84 85 l := log.FromContext(ctx) 85 86 86 - collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt())) 87 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_did", string(issue.RepoDid))) 87 88 if err != nil { 88 89 l.Error("failed to fetch collaborators", "err", err) 89 90 return ··· 240 241 func (n *databaseNotifier) NewPull(ctx context.Context, pull *models.Pull) { 241 242 l := log.FromContext(ctx) 242 243 243 - repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(pull.RepoAt))) 244 + repo, err := db.GetRepo(n.db, orm.FilterEq("repo_did", string(pull.RepoDid))) 244 245 if err != nil { 245 246 l.Error("failed to get repos", "err", err) 246 247 return 247 248 } 248 - collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", repo.RepoAt())) 249 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_did", string(pull.RepoDid))) 249 250 if err != nil { 250 251 l.Error("failed to fetch collaborators", "err", err) 251 252 return ··· 285 286 l := log.FromContext(ctx) 286 287 287 288 pull, err := db.GetPull(n.db, 288 - orm.FilterEq("repo_at", syntax.ATURI(comment.RepoAt)), 289 + orm.FilterEq("repo_did", comment.RepoDid), 289 290 orm.FilterEq("pull_id", comment.PullId), 290 291 ) 291 292 if err != nil { ··· 293 294 return 294 295 } 295 296 296 - repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", comment.RepoAt)) 297 + repo, err := db.GetRepo(n.db, orm.FilterEq("repo_did", comment.RepoDid)) 297 298 if err != nil { 298 299 l.Error("failed to get repos", "err", err) 299 300 return ··· 371 372 func (n *databaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) { 372 373 l := log.FromContext(ctx) 373 374 374 - collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt())) 375 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_did", string(issue.RepoDid))) 375 376 if err != nil { 376 377 l.Error("failed to fetch collaborators", "err", err) 377 378 return ··· 419 420 l := log.FromContext(ctx) 420 421 421 422 // Get repo details 422 - repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(pull.RepoAt))) 423 + repo, err := db.GetRepo(n.db, orm.FilterEq("repo_did", string(pull.RepoDid))) 423 424 if err != nil { 424 425 l.Error("failed to get repos", "err", err) 425 426 return 426 427 } 427 428 428 - collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", repo.RepoAt())) 429 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_did", string(pull.RepoDid))) 429 430 if err != nil { 430 431 l.Error("failed to fetch collaborators", "err", err) 431 432 return
+5
appview/notify/logging/notifier.go
··· 31 31 l.inner.DeleteRepo(ctx, repo) 32 32 } 33 33 34 + func (l *loggingNotifier) RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) { 35 + ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "RenameRepo")) 36 + l.inner.RenameRepo(ctx, actor, oldRepo, newRepo) 37 + } 38 + 34 39 func (l *loggingNotifier) NewStar(ctx context.Context, star *models.Star) { 35 40 ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewStar")) 36 41 l.inner.NewStar(ctx, star)
+4
appview/notify/merged_notifier.go
··· 38 38 m.fanout(func(n Notifier) { n.DeleteRepo(ctx, repo) }) 39 39 } 40 40 41 + func (m *mergedNotifier) RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) { 42 + m.fanout(func(n Notifier) { n.RenameRepo(ctx, actor, oldRepo, newRepo) }) 43 + } 44 + 41 45 func (m *mergedNotifier) NewStar(ctx context.Context, star *models.Star) { 42 46 m.fanout(func(n Notifier) { n.NewStar(ctx, star) }) 43 47 }
+3
appview/notify/notifier.go
··· 10 10 type Notifier interface { 11 11 NewRepo(ctx context.Context, repo *models.Repo) 12 12 DeleteRepo(ctx context.Context, repo *models.Repo) 13 + RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) 13 14 14 15 NewStar(ctx context.Context, star *models.Star) 15 16 DeleteStar(ctx context.Context, star *models.Star) ··· 47 48 48 49 func (m *BaseNotifier) NewRepo(ctx context.Context, repo *models.Repo) {} 49 50 func (m *BaseNotifier) DeleteRepo(ctx context.Context, repo *models.Repo) {} 51 + func (m *BaseNotifier) RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) { 52 + } 50 53 51 54 func (m *BaseNotifier) NewStar(ctx context.Context, star *models.Star) {} 52 55 func (m *BaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {}
+34 -12
appview/notify/posthog/notifier.go
··· 35 35 } 36 36 } 37 37 38 + func (n *posthogNotifier) RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) { 39 + err := n.client.Enqueue(posthog.Capture{ 40 + DistinctId: actor.String(), 41 + Event: "repo_renamed", 42 + Properties: posthog.Properties{ 43 + "repo_at": newRepo.RepoAt(), 44 + "owner": newRepo.Did, 45 + "old_name": oldRepo.Name, 46 + "new_name": newRepo.Name, 47 + }, 48 + }) 49 + if err != nil { 50 + log.Println("failed to enqueue posthog event:", err) 51 + } 52 + } 53 + 38 54 func (n *posthogNotifier) NewStar(ctx context.Context, star *models.Star) { 39 55 err := n.client.Enqueue(posthog.Capture{ 40 56 DistinctId: star.Did, 41 57 Event: "star", 42 - Properties: posthog.Properties{"repo_at": star.RepoAt.String()}, 58 + Properties: posthog.Properties{ 59 + "subject_type": string(star.SubjectType), 60 + "subject": star.Subject, 61 + }, 43 62 }) 44 63 if err != nil { 45 64 log.Println("failed to enqueue posthog event:", err) ··· 50 69 err := n.client.Enqueue(posthog.Capture{ 51 70 DistinctId: star.Did, 52 71 Event: "unstar", 53 - Properties: posthog.Properties{"repo_at": star.RepoAt.String()}, 72 + Properties: posthog.Properties{ 73 + "subject_type": string(star.SubjectType), 74 + "subject": star.Subject, 75 + }, 54 76 }) 55 77 if err != nil { 56 78 log.Println("failed to enqueue posthog event:", err) ··· 62 84 DistinctId: issue.Did, 63 85 Event: "new_issue", 64 86 Properties: posthog.Properties{ 65 - "repo_at": issue.RepoAt.String(), 87 + "repo_did": string(issue.RepoDid), 66 88 "issue_id": issue.IssueId, 67 89 "mentions": mentions, 68 90 }, ··· 77 99 DistinctId: pull.OwnerDid, 78 100 Event: "new_pull", 79 101 Properties: posthog.Properties{ 80 - "repo_at": pull.RepoAt, 81 - "pull_id": pull.PullId, 102 + "repo_did": string(pull.RepoDid), 103 + "pull_id": pull.PullId, 82 104 }, 83 105 }) 84 106 if err != nil { ··· 91 113 DistinctId: comment.OwnerDid, 92 114 Event: "new_pull_comment", 93 115 Properties: posthog.Properties{ 94 - "repo_at": comment.RepoAt, 116 + "repo_did": comment.RepoDid, 95 117 "pull_id": comment.PullId, 96 118 "mentions": mentions, 97 119 }, ··· 106 128 DistinctId: pull.OwnerDid, 107 129 Event: "pull_closed", 108 130 Properties: posthog.Properties{ 109 - "repo_at": pull.RepoAt, 110 - "pull_id": pull.PullId, 131 + "repo_did": string(pull.RepoDid), 132 + "pull_id": pull.PullId, 111 133 }, 112 134 }) 113 135 if err != nil { ··· 216 238 DistinctId: issue.Did, 217 239 Event: event, 218 240 Properties: posthog.Properties{ 219 - "repo_at": issue.RepoAt.String(), 241 + "repo_did": string(issue.RepoDid), 220 242 "actor": actor, 221 243 "issue_id": issue.IssueId, 222 244 }, ··· 243 265 DistinctId: pull.OwnerDid, 244 266 Event: event, 245 267 Properties: posthog.Properties{ 246 - "repo_at": pull.RepoAt, 247 - "pull_id": pull.PullId, 248 - "actor": actor, 268 + "repo_did": string(pull.RepoDid), 269 + "pull_id": pull.PullId, 270 + "actor": actor, 249 271 }, 250 272 }) 251 273 if err != nil {
+64 -38
appview/notify/webhook/notifier.go
··· 14 14 "time" 15 15 16 16 "github.com/avast/retry-go/v4" 17 + "github.com/bluesky-social/indigo/atproto/syntax" 17 18 "github.com/google/uuid" 18 19 "tangled.org/core/appview/db" 19 20 "tangled.org/core/appview/models" ··· 41 42 var _ notify.Notifier = &Notifier{} 42 43 43 44 func (w *Notifier) Push(ctx context.Context, repo *models.Repo, ref, oldSha, newSha, committerDid string) { 44 - webhooks, err := db.GetActiveWebhooksForRepo(w.db, repo.RepoAt()) 45 + webhooks, err := w.activeWebhooksForEvent(repo.RepoDid, models.WebhookEventPush) 45 46 if err != nil { 46 - w.logger.Error("failed to get webhooks for repo", "repo", repo.RepoAt(), "err", err) 47 + w.logger.Error("failed to get webhooks for repo", "repo_did", repo.RepoDid, "err", err) 48 + return 49 + } 50 + if len(webhooks) == 0 { 47 51 return 48 52 } 49 53 50 - var pushWebhooks []models.Webhook 54 + payload := w.buildPushPayload(repo, ref, oldSha, newSha, committerDid) 55 + payloadBytes, err := json.Marshal(payload) 56 + if err != nil { 57 + w.logger.Error("failed to marshal push payload", "repo_did", repo.RepoDid, "err", err) 58 + return 59 + } 60 + 61 + userAgent := "Tangled-Hook/" + newSha[:7] 51 62 for _, webhook := range webhooks { 52 - if webhook.HasEvent(models.WebhookEventPush) { 53 - pushWebhooks = append(pushWebhooks, webhook) 54 - } 63 + go w.sendWebhook(ctx, webhook, string(models.WebhookEventPush), payload.Repository.FullName, userAgent, payloadBytes) 55 64 } 65 + } 56 66 57 - if len(pushWebhooks) == 0 { 67 + func (w *Notifier) RenameRepo(ctx context.Context, actor syntax.DID, oldRepo, newRepo *models.Repo) { 68 + webhooks, err := w.activeWebhooksForEvent(newRepo.RepoDid, models.WebhookEventRepoRenamed) 69 + if err != nil { 70 + w.logger.Error("failed to get webhooks for repo", "repo_did", newRepo.RepoDid, "err", err) 71 + return 72 + } 73 + if len(webhooks) == 0 { 58 74 return 59 75 } 60 76 61 - payload, err := w.buildPushPayload(repo, ref, oldSha, newSha, committerDid) 77 + payload := &models.WebhookRenamePayload{ 78 + OldName: oldRepo.Name, 79 + NewName: newRepo.Name, 80 + Repository: buildWebhookRepository(newRepo), 81 + Sender: models.WebhookUser{Did: actor.String()}, 82 + } 83 + payloadBytes, err := json.Marshal(payload) 62 84 if err != nil { 63 - w.logger.Error("failed to build push payload", "repo", repo.RepoAt(), "err", err) 85 + w.logger.Error("failed to marshal rename payload", "repo_did", newRepo.RepoDid, "err", err) 64 86 return 65 87 } 66 88 67 - for _, webhook := range pushWebhooks { 68 - go w.sendWebhook(ctx, webhook, string(models.WebhookEventPush), payload) 89 + userAgent := "Tangled-Hook/rename" 90 + for _, webhook := range webhooks { 91 + go w.sendWebhook(ctx, webhook, string(models.WebhookEventRepoRenamed), payload.Repository.FullName, userAgent, payloadBytes) 69 92 } 70 93 } 71 94 72 - func (w *Notifier) buildPushPayload(repo *models.Repo, ref, oldSha, newSha, committerDid string) (*models.WebhookPayload, error) { 73 - owner := repo.Did 74 - 75 - pusher := committerDid 76 - if committerDid == "" { 77 - pusher = owner 95 + func (w *Notifier) activeWebhooksForEvent(repoDid string, event models.WebhookEvent) ([]models.Webhook, error) { 96 + webhooks, err := db.GetActiveWebhooksForRepo(w.db, repoDid) 97 + if err != nil { 98 + return nil, err 78 99 } 100 + var matching []models.Webhook 101 + for _, webhook := range webhooks { 102 + if webhook.HasEvent(event) { 103 + matching = append(matching, webhook) 104 + } 105 + } 106 + return matching, nil 107 + } 79 108 109 + func buildWebhookRepository(repo *models.Repo) models.WebhookRepository { 80 110 repository := models.WebhookRepository{ 81 111 Name: repo.Name, 82 - FullName: fmt.Sprintf("%s/%s", repo.Did, repo.Name), 112 + FullName: fmt.Sprintf("%s/%s", repo.Did, repo.Rkey), 83 113 Description: repo.Description, 84 114 Fork: repo.Source != "", 85 - HtmlUrl: fmt.Sprintf("https://%s/%s/%s", repo.Knot, repo.Did, repo.Name), 86 - CloneUrl: fmt.Sprintf("https://%s/%s/%s", repo.Knot, repo.Did, repo.Name), 87 - SshUrl: fmt.Sprintf("ssh://git@%s/%s/%s", repo.Knot, repo.Did, repo.Name), 115 + HtmlUrl: fmt.Sprintf("https://%s/%s/%s", repo.Knot, repo.Did, repo.Rkey), 116 + CloneUrl: fmt.Sprintf("https://%s/%s/%s", repo.Knot, repo.Did, repo.Rkey), 117 + SshUrl: fmt.Sprintf("ssh://git@%s/%s/%s", repo.Knot, repo.Did, repo.Rkey), 88 118 CreatedAt: repo.Created.Format(time.RFC3339), 89 119 UpdatedAt: repo.Created.Format(time.RFC3339), 90 120 Owner: models.WebhookUser{ 91 - Did: owner, 121 + Did: repo.Did, 92 122 }, 93 123 } 94 - 95 124 if repo.Website != "" { 96 125 repository.Website = repo.Website 97 126 } ··· 99 128 repository.StarsCount = repo.RepoStats.StarCount 100 129 repository.OpenIssues = repo.RepoStats.IssueCount.Open 101 130 } 131 + return repository 132 + } 102 133 103 - payload := &models.WebhookPayload{ 134 + func (w *Notifier) buildPushPayload(repo *models.Repo, ref, oldSha, newSha, committerDid string) *models.WebhookPayload { 135 + pusher := committerDid 136 + if committerDid == "" { 137 + pusher = repo.Did 138 + } 139 + return &models.WebhookPayload{ 104 140 Ref: ref, 105 141 Before: oldSha, 106 142 After: newSha, 107 - Repository: repository, 143 + Repository: buildWebhookRepository(repo), 108 144 Pusher: models.WebhookUser{ 109 145 Did: pusher, 110 146 }, 111 147 } 112 - 113 - return payload, nil 114 148 } 115 149 116 - func (w *Notifier) sendWebhook(ctx context.Context, webhook models.Webhook, event string, payload *models.WebhookPayload) { 150 + func (w *Notifier) sendWebhook(ctx context.Context, webhook models.Webhook, event, repoFullName, userAgent string, payloadBytes []byte) { 117 151 deliveryId := uuid.New().String() 118 152 119 - payloadBytes, err := json.Marshal(payload) 120 - if err != nil { 121 - w.logger.Error("failed to marshal webhook payload", "webhook_id", webhook.Id, "err", err) 122 - return 123 - } 124 - 125 153 req, err := http.NewRequestWithContext(ctx, "POST", webhook.Url, bytes.NewReader(payloadBytes)) 126 154 if err != nil { 127 155 w.logger.Error("failed to create webhook request", "webhook_id", webhook.Id, "err", err) 128 156 return 129 157 } 130 158 131 - shortSha := payload.After[:7] 132 - 133 159 req.Header.Set("Content-Type", "application/json") 134 - req.Header.Set("User-Agent", "Tangled-Hook/"+shortSha) 160 + req.Header.Set("User-Agent", userAgent) 135 161 req.Header.Set("X-Tangled-Event", event) 136 162 req.Header.Set("X-Tangled-Hook-ID", fmt.Sprintf("%d", webhook.Id)) 137 163 req.Header.Set("X-Tangled-Delivery", deliveryId) 138 - req.Header.Set("X-Tangled-Repo", payload.Repository.FullName) 164 + req.Header.Set("X-Tangled-Repo", repoFullName) 139 165 140 166 if webhook.Secret != "" { 141 167 signature := w.computeSignature(payloadBytes, webhook.Secret)

History

9 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
merge conflicts detected
expand
  • api/tangled/cbor_gen.go:866
  • api/tangled/feedstar.go:5
  • api/tangled/gitrefUpdate.go:29
  • api/tangled/repocollaborator.go:19
  • api/tangled/repoissue.go:22
  • api/tangled/repopull.go:39
  • api/tangled/tangledrepo.go:24
  • cmd/cborgen/cborgen.go:17
  • knotserver/xrpc/merge.go:118
  • lexicons/feed/star.json:10
  • lexicons/git/refUpdate.json:11
  • lexicons/issue/issue.json:9
  • lexicons/pulls/pull.json:65
  • lexicons/repo/collaborator.json:11
  • lexicons/repo/repo.json:6
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments
1 commit
expand
appview/oauth,notify: DID-based PDS record rewriting
expand 0 comments