···288 foreign key (at_uri) references repos(at_uri) on delete cascade
289 );
29000000000000000000000000000291 create table if not exists migrations (
292 id integer primary key autoincrement,
293 name text unique
···288 foreign key (at_uri) references repos(at_uri) on delete cascade
289 );
290291+ create table if not exists oauth_requests (
292+ id integer primary key autoincrement,
293+ auth_server_iss text not null,
294+ state text not null,
295+ did text not null,
296+ handle text not null,
297+ pds_url text not null,
298+ pkce_verifier text not null,
299+ dpop_auth_server_nonce text not null,
300+ dpop_private_jwk text not null
301+ );
302+303+ create table if not exists oauth_sessions (
304+ id integer primary key autoincrement,
305+ did text not null,
306+ handle text not null,
307+ pds_url text not null,
308+ auth_server_iss text not null,
309+ access_jwt text not null,
310+ refresh_jwt text not null,
311+ dpop_pds_nonce text,
312+ dpop_auth_server_nonce text not null,
313+ dpop_private_jwk text not null,
314+ expiry text not null
315+ );
316+317 create table if not exists migrations (
318 id integer primary key autoincrement,
319 name text unique
···20 return func(next http.Handler) http.Handler {
21 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 // requires auth also
23- actor := s.auth.GetUser(r)
24 if actor == nil {
25 // we need a logged in user
26 log.Printf("not logged in, redirecting")
···54 return func(next http.Handler) http.Handler {
55 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56 // requires auth also
57- actor := s.auth.GetUser(r)
58 if actor == nil {
59 // we need a logged in user
60 log.Printf("not logged in, redirecting")
···20 return func(next http.Handler) http.Handler {
21 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 // requires auth also
23+ actor := s.oauth.GetUser(r)
24 if actor == nil {
25 // we need a logged in user
26 log.Printf("not logged in, redirecting")
···54 return func(next http.Handler) http.Handler {
55 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56 // requires auth also
57+ actor := s.oauth.GetUser(r)
58 if actor == nil {
59 // we need a logged in user
60 log.Printf("not logged in, redirecting")
+17-12
appview/state/profile.go
···119 log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err)
120 }
121122- loggedInUser := s.auth.GetUser(r)
123 followStatus := db.IsNotFollowing
124 if loggedInUser != nil {
125 followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
···161 log.Printf("getting repos for %s: %s", ident.DID.String(), err)
162 }
163164- loggedInUser := s.auth.GetUser(r)
165 followStatus := db.IsNotFollowing
166 if loggedInUser != nil {
167 followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
···190}
191192func (s *State) GetAvatarUri(handle string) string {
193- secret := s.config.AvatarSharedSecret
194 h := hmac.New(sha256.New, []byte(secret))
195 h.Write([]byte(handle))
196 signature := hex.EncodeToString(h.Sum(nil))
197- return fmt.Sprintf("%s/%s/%s", s.config.AvatarHost, signature, handle)
198}
199200func (s *State) UpdateProfileBio(w http.ResponseWriter, r *http.Request) {
201- user := s.auth.GetUser(r)
202203 err := r.ParseForm()
204 if err != nil {
···246}
247248func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) {
249- user := s.auth.GetUser(r)
250251 err := r.ParseForm()
252 if err != nil {
···286}
287288func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *http.Request) {
289- user := s.auth.GetUser(r)
290 tx, err := s.db.BeginTx(r.Context(), nil)
291 if err != nil {
292 log.Println("failed to start transaction", err)
···294 return
295 }
296297- client, _ := s.auth.AuthorizedClient(r)
00000298299 // yeah... lexgen dose not support syntax.ATURI in the record for some reason,
300 // nor does it support exact size arrays
···308 vanityStats = append(vanityStats, string(v.Kind))
309 }
310311- ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.ActorProfileNSID, user.Did, "self")
312 var cid *string
313 if ex != nil {
314 cid = ex.Cid
315 }
316317- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
318 Collection: tangled.ActorProfileNSID,
319 Repo: user.Did,
320 Rkey: "self",
···347}
348349func (s *State) EditBioFragment(w http.ResponseWriter, r *http.Request) {
350- user := s.auth.GetUser(r)
351352 profile, err := db.GetProfile(s.db, user.Did)
353 if err != nil {
···361}
362363func (s *State) EditPinsFragment(w http.ResponseWriter, r *http.Request) {
364- user := s.auth.GetUser(r)
365366 profile, err := db.GetProfile(s.db, user.Did)
367 if err != nil {
···119 log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err)
120 }
121122+ loggedInUser := s.oauth.GetUser(r)
123 followStatus := db.IsNotFollowing
124 if loggedInUser != nil {
125 followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
···161 log.Printf("getting repos for %s: %s", ident.DID.String(), err)
162 }
163164+ loggedInUser := s.oauth.GetUser(r)
165 followStatus := db.IsNotFollowing
166 if loggedInUser != nil {
167 followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
···190}
191192func (s *State) GetAvatarUri(handle string) string {
193+ secret := s.config.Avatar.SharedSecret
194 h := hmac.New(sha256.New, []byte(secret))
195 h.Write([]byte(handle))
196 signature := hex.EncodeToString(h.Sum(nil))
197+ return fmt.Sprintf("%s/%s/%s", s.config.Avatar.Host, signature, handle)
198}
199200func (s *State) UpdateProfileBio(w http.ResponseWriter, r *http.Request) {
201+ user := s.oauth.GetUser(r)
202203 err := r.ParseForm()
204 if err != nil {
···246}
247248func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) {
249+ user := s.oauth.GetUser(r)
250251 err := r.ParseForm()
252 if err != nil {
···286}
287288func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *http.Request) {
289+ user := s.oauth.GetUser(r)
290 tx, err := s.db.BeginTx(r.Context(), nil)
291 if err != nil {
292 log.Println("failed to start transaction", err)
···294 return
295 }
296297+ client, err := s.oauth.AuthorizedClient(r)
298+ if err != nil {
299+ log.Println("failed to get authorized client", err)
300+ s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.")
301+ return
302+ }
303304 // yeah... lexgen dose not support syntax.ATURI in the record for some reason,
305 // nor does it support exact size arrays
···313 vanityStats = append(vanityStats, string(v.Kind))
314 }
315316+ ex, _ := client.RepoGetRecord(r.Context(), "", tangled.ActorProfileNSID, user.Did, "self")
317 var cid *string
318 if ex != nil {
319 cid = ex.Cid
320 }
321322+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
323 Collection: tangled.ActorProfileNSID,
324 Repo: user.Did,
325 Rkey: "self",
···352}
353354func (s *State) EditBioFragment(w http.ResponseWriter, r *http.Request) {
355+ user := s.oauth.GetUser(r)
356357 profile, err := db.GetProfile(s.db, user.Did)
358 if err != nil {
···366}
367368func (s *State) EditPinsFragment(w http.ResponseWriter, r *http.Request) {
369+ user := s.oauth.GetUser(r)
370371 profile, err := db.GetProfile(s.db, user.Did)
372 if err != nil {
+76-51
appview/state/pull.go
···1314 "tangled.sh/tangled.sh/core/api/tangled"
15 "tangled.sh/tangled.sh/core/appview"
16- "tangled.sh/tangled.sh/core/appview/auth"
17 "tangled.sh/tangled.sh/core/appview/db"
018 "tangled.sh/tangled.sh/core/appview/pages"
19 "tangled.sh/tangled.sh/core/patchutil"
20 "tangled.sh/tangled.sh/core/types"
···29func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
30 switch r.Method {
31 case http.MethodGet:
32- user := s.auth.GetUser(r)
33 f, err := s.fullyResolvedRepo(r)
34 if err != nil {
35 log.Println("failed to get repo and knot", err)
···73}
7475func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
76- user := s.auth.GetUser(r)
77 f, err := s.fullyResolvedRepo(r)
78 if err != nil {
79 log.Println("failed to get repo and knot", err)
···143 }
144 }
145146- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
147 if err != nil {
148 log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err)
149 return types.MergeCheckResponse{
···215 repoName = f.RepoName
216 }
217218- us, err := NewUnsignedClient(knot, s.config.Dev)
219 if err != nil {
220 log.Printf("failed to setup client for %s; ignoring: %v", knot, err)
221 return pages.Unknown
···250}
251252func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
253- user := s.auth.GetUser(r)
254 f, err := s.fullyResolvedRepo(r)
255 if err != nil {
256 log.Println("failed to get repo and knot", err)
···298}
299300func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
301- user := s.auth.GetUser(r)
302303 f, err := s.fullyResolvedRepo(r)
304 if err != nil {
···355 interdiff := patchutil.Interdiff(previousPatch, currentPatch)
356357 s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
358- LoggedInUser: s.auth.GetUser(r),
359 RepoInfo: f.RepoInfo(s, user),
360 Pull: pull,
361 Round: roundIdInt,
···397}
398399func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
400- user := s.auth.GetUser(r)
401 params := r.URL.Query()
402403 state := db.PullOpen
···451 }
452453 s.pages.RepoPulls(w, pages.RepoPullsParams{
454- LoggedInUser: s.auth.GetUser(r),
455 RepoInfo: f.RepoInfo(s, user),
456 Pulls: pulls,
457 DidHandleMap: didHandleMap,
···461}
462463func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
464- user := s.auth.GetUser(r)
465 f, err := s.fullyResolvedRepo(r)
466 if err != nil {
467 log.Println("failed to get repo and knot", err)
···519 }
520521 atUri := f.RepoAt.String()
522- client, _ := s.auth.AuthorizedClient(r)
523- atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
00000524 Collection: tangled.RepoPullCommentNSID,
525 Repo: user.Did,
526 Rkey: appview.TID(),
···568}
569570func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
571- user := s.auth.GetUser(r)
572 f, err := s.fullyResolvedRepo(r)
573 if err != nil {
574 log.Println("failed to get repo and knot", err)
···577578 switch r.Method {
579 case http.MethodGet:
580- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
581 if err != nil {
582 log.Printf("failed to create unsigned client for %s", f.Knot)
583 s.pages.Error503(w)
···646 return
647 }
648649- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
650 if err != nil {
651 log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
652 s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
···689 }
690}
691692-func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, sourceBranch string) {
693 pullSource := &db.PullSource{
694 Branch: sourceBranch,
695 }
···698 }
699700 // Generate a patch using /compare
701- ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
702 if err != nil {
703 log.Printf("failed to create signed client for %s: %s", f.Knot, err)
704 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···723 s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource)
724}
725726-func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, patch string) {
727 if !patchutil.IsPatchValid(patch) {
728 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
729 return
···732 s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil)
733}
734735-func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
736 fork, err := db.GetForkByDid(s.db, user.Did, forkRepo)
737 if errors.Is(err, sql.ErrNoRows) {
738 s.pages.Notice(w, "pull", "No such fork.")
···750 return
751 }
752753- sc, err := NewSignedClient(fork.Knot, secret, s.config.Dev)
754 if err != nil {
755 log.Println("failed to create signed client:", err)
756 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
757 return
758 }
759760- us, err := NewUnsignedClient(fork.Knot, s.config.Dev)
761 if err != nil {
762 log.Println("failed to create unsigned client:", err)
763 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···816 w http.ResponseWriter,
817 r *http.Request,
818 f *FullyResolvedRepo,
819- user *auth.User,
820 title, body, targetBranch string,
821 patch string,
822 sourceRev string,
···870 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
871 return
872 }
873- client, _ := s.auth.AuthorizedClient(r)
00000874 pullId, err := db.NextPullId(s.db, f.RepoAt)
875 if err != nil {
876 log.Println("failed to get pull id", err)
···878 return
879 }
880881- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
882 Collection: tangled.RepoPullNSID,
883 Repo: user.Did,
884 Rkey: rkey,
···929}
930931func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
932- user := s.auth.GetUser(r)
933 f, err := s.fullyResolvedRepo(r)
934 if err != nil {
935 log.Println("failed to get repo and knot", err)
···942}
943944func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
945- user := s.auth.GetUser(r)
946 f, err := s.fullyResolvedRepo(r)
947 if err != nil {
948 log.Println("failed to get repo and knot", err)
949 return
950 }
951952- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
953 if err != nil {
954 log.Printf("failed to create unsigned client for %s", f.Knot)
955 s.pages.Error503(w)
···982}
983984func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
985- user := s.auth.GetUser(r)
986 f, err := s.fullyResolvedRepo(r)
987 if err != nil {
988 log.Println("failed to get repo and knot", err)
···1002}
10031004func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
1005- user := s.auth.GetUser(r)
10061007 f, err := s.fullyResolvedRepo(r)
1008 if err != nil {
···1019 return
1020 }
10211022- sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Dev)
1023 if err != nil {
1024 log.Printf("failed to create unsigned client for %s", repo.Knot)
1025 s.pages.Error503(w)
···1046 return
1047 }
10481049- targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
1050 if err != nil {
1051 log.Printf("failed to create unsigned client for target knot %s", f.Knot)
1052 s.pages.Error503(w)
···1081}
10821083func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) {
1084- user := s.auth.GetUser(r)
1085 f, err := s.fullyResolvedRepo(r)
1086 if err != nil {
1087 log.Println("failed to get repo and knot", err)
···1117}
11181119func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
1120- user := s.auth.GetUser(r)
11211122 pull, ok := r.Context().Value("pull").(*db.Pull)
1123 if !ok {
···1159 s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")
1160 return
1161 }
1162- client, _ := s.auth.AuthorizedClient(r)
0000011631164- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1165 if err != nil {
1166 // failed to get record
1167 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
1168 return
1169 }
11701171- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1172 Collection: tangled.RepoPullNSID,
1173 Repo: user.Did,
1174 Rkey: pull.Rkey,
···1200}
12011202func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
1203- user := s.auth.GetUser(r)
12041205 pull, ok := r.Context().Value("pull").(*db.Pull)
1206 if !ok {
···1227 return
1228 }
12291230- ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
1231 if err != nil {
1232 log.Printf("failed to create client for %s: %s", f.Knot, err)
1233 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···1268 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1269 return
1270 }
1271- client, _ := s.auth.AuthorizedClient(r)
0000012721273- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1274 if err != nil {
1275 // failed to get record
1276 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···1280 recordPullSource := &tangled.RepoPull_Source{
1281 Branch: pull.PullSource.Branch,
1282 }
1283- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1284 Collection: tangled.RepoPullNSID,
1285 Repo: user.Did,
1286 Rkey: pull.Rkey,
···1313}
13141315func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
1316- user := s.auth.GetUser(r)
13171318 pull, ok := r.Context().Value("pull").(*db.Pull)
1319 if !ok {
···1342 }
13431344 // extract patch by performing compare
1345- ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Dev)
1346 if err != nil {
1347 log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)
1348 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···1357 }
13581359 // update the hidden tracking branch to latest
1360- signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Dev)
1361 if err != nil {
1362 log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)
1363 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···1406 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1407 return
1408 }
1409- client, _ := s.auth.AuthorizedClient(r)
0000014101411- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1412 if err != nil {
1413 // failed to get record
1414 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···1420 Branch: pull.PullSource.Branch,
1421 Repo: &repoAt,
1422 }
1423- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1424 Collection: tangled.RepoPullNSID,
1425 Repo: user.Did,
1426 Rkey: pull.Rkey,
···1503 log.Printf("failed to get primary email: %s", err)
1504 }
15051506- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
1507 if err != nil {
1508 log.Printf("failed to create signed client for %s: %s", f.Knot, err)
1509 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
···1533}
15341535func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
1536- user := s.auth.GetUser(r)
15371538 f, err := s.fullyResolvedRepo(r)
1539 if err != nil {
···1587}
15881589func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) {
1590- user := s.auth.GetUser(r)
15911592 f, err := s.fullyResolvedRepo(r)
1593 if err != nil {
···1314 "tangled.sh/tangled.sh/core/api/tangled"
15 "tangled.sh/tangled.sh/core/appview"
016 "tangled.sh/tangled.sh/core/appview/db"
17+ "tangled.sh/tangled.sh/core/appview/oauth"
18 "tangled.sh/tangled.sh/core/appview/pages"
19 "tangled.sh/tangled.sh/core/patchutil"
20 "tangled.sh/tangled.sh/core/types"
···29func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
30 switch r.Method {
31 case http.MethodGet:
32+ user := s.oauth.GetUser(r)
33 f, err := s.fullyResolvedRepo(r)
34 if err != nil {
35 log.Println("failed to get repo and knot", err)
···73}
7475func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
76+ user := s.oauth.GetUser(r)
77 f, err := s.fullyResolvedRepo(r)
78 if err != nil {
79 log.Println("failed to get repo and knot", err)
···143 }
144 }
145146+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
147 if err != nil {
148 log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err)
149 return types.MergeCheckResponse{
···215 repoName = f.RepoName
216 }
217218+ us, err := NewUnsignedClient(knot, s.config.Core.Dev)
219 if err != nil {
220 log.Printf("failed to setup client for %s; ignoring: %v", knot, err)
221 return pages.Unknown
···250}
251252func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
253+ user := s.oauth.GetUser(r)
254 f, err := s.fullyResolvedRepo(r)
255 if err != nil {
256 log.Println("failed to get repo and knot", err)
···298}
299300func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
301+ user := s.oauth.GetUser(r)
302303 f, err := s.fullyResolvedRepo(r)
304 if err != nil {
···355 interdiff := patchutil.Interdiff(previousPatch, currentPatch)
356357 s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
358+ LoggedInUser: s.oauth.GetUser(r),
359 RepoInfo: f.RepoInfo(s, user),
360 Pull: pull,
361 Round: roundIdInt,
···397}
398399func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
400+ user := s.oauth.GetUser(r)
401 params := r.URL.Query()
402403 state := db.PullOpen
···451 }
452453 s.pages.RepoPulls(w, pages.RepoPullsParams{
454+ LoggedInUser: s.oauth.GetUser(r),
455 RepoInfo: f.RepoInfo(s, user),
456 Pulls: pulls,
457 DidHandleMap: didHandleMap,
···461}
462463func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
464+ user := s.oauth.GetUser(r)
465 f, err := s.fullyResolvedRepo(r)
466 if err != nil {
467 log.Println("failed to get repo and knot", err)
···519 }
520521 atUri := f.RepoAt.String()
522+ client, err := s.oauth.AuthorizedClient(r)
523+ if err != nil {
524+ log.Println("failed to get authorized client", err)
525+ s.pages.Notice(w, "pull-comment", "Failed to create comment.")
526+ return
527+ }
528+ atResp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
529 Collection: tangled.RepoPullCommentNSID,
530 Repo: user.Did,
531 Rkey: appview.TID(),
···573}
574575func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
576+ user := s.oauth.GetUser(r)
577 f, err := s.fullyResolvedRepo(r)
578 if err != nil {
579 log.Println("failed to get repo and knot", err)
···582583 switch r.Method {
584 case http.MethodGet:
585+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
586 if err != nil {
587 log.Printf("failed to create unsigned client for %s", f.Knot)
588 s.pages.Error503(w)
···651 return
652 }
653654+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
655 if err != nil {
656 log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
657 s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
···694 }
695}
696697+func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, title, body, targetBranch, sourceBranch string) {
698 pullSource := &db.PullSource{
699 Branch: sourceBranch,
700 }
···703 }
704705 // Generate a patch using /compare
706+ ksClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
707 if err != nil {
708 log.Printf("failed to create signed client for %s: %s", f.Knot, err)
709 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···728 s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource)
729}
730731+func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, title, body, targetBranch, patch string) {
732 if !patchutil.IsPatchValid(patch) {
733 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
734 return
···737 s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil)
738}
739740+func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
741 fork, err := db.GetForkByDid(s.db, user.Did, forkRepo)
742 if errors.Is(err, sql.ErrNoRows) {
743 s.pages.Notice(w, "pull", "No such fork.")
···755 return
756 }
757758+ sc, err := NewSignedClient(fork.Knot, secret, s.config.Core.Dev)
759 if err != nil {
760 log.Println("failed to create signed client:", err)
761 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
762 return
763 }
764765+ us, err := NewUnsignedClient(fork.Knot, s.config.Core.Dev)
766 if err != nil {
767 log.Println("failed to create unsigned client:", err)
768 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
···821 w http.ResponseWriter,
822 r *http.Request,
823 f *FullyResolvedRepo,
824+ user *oauth.User,
825 title, body, targetBranch string,
826 patch string,
827 sourceRev string,
···875 s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
876 return
877 }
878+ client, err := s.oauth.AuthorizedClient(r)
879+ if err != nil {
880+ log.Println("failed to get authorized client", err)
881+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
882+ return
883+ }
884 pullId, err := db.NextPullId(s.db, f.RepoAt)
885 if err != nil {
886 log.Println("failed to get pull id", err)
···888 return
889 }
890891+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
892 Collection: tangled.RepoPullNSID,
893 Repo: user.Did,
894 Rkey: rkey,
···939}
940941func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
942+ user := s.oauth.GetUser(r)
943 f, err := s.fullyResolvedRepo(r)
944 if err != nil {
945 log.Println("failed to get repo and knot", err)
···952}
953954func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
955+ user := s.oauth.GetUser(r)
956 f, err := s.fullyResolvedRepo(r)
957 if err != nil {
958 log.Println("failed to get repo and knot", err)
959 return
960 }
961962+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
963 if err != nil {
964 log.Printf("failed to create unsigned client for %s", f.Knot)
965 s.pages.Error503(w)
···992}
993994func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
995+ user := s.oauth.GetUser(r)
996 f, err := s.fullyResolvedRepo(r)
997 if err != nil {
998 log.Println("failed to get repo and knot", err)
···1012}
10131014func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
1015+ user := s.oauth.GetUser(r)
10161017 f, err := s.fullyResolvedRepo(r)
1018 if err != nil {
···1029 return
1030 }
10311032+ sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Core.Dev)
1033 if err != nil {
1034 log.Printf("failed to create unsigned client for %s", repo.Knot)
1035 s.pages.Error503(w)
···1056 return
1057 }
10581059+ targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
1060 if err != nil {
1061 log.Printf("failed to create unsigned client for target knot %s", f.Knot)
1062 s.pages.Error503(w)
···1091}
10921093func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) {
1094+ user := s.oauth.GetUser(r)
1095 f, err := s.fullyResolvedRepo(r)
1096 if err != nil {
1097 log.Println("failed to get repo and knot", err)
···1127}
11281129func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
1130+ user := s.oauth.GetUser(r)
11311132 pull, ok := r.Context().Value("pull").(*db.Pull)
1133 if !ok {
···1169 s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")
1170 return
1171 }
1172+ client, err := s.oauth.AuthorizedClient(r)
1173+ if err != nil {
1174+ log.Println("failed to get authorized client", err)
1175+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1176+ return
1177+ }
11781179+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1180 if err != nil {
1181 // failed to get record
1182 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
1183 return
1184 }
11851186+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1187 Collection: tangled.RepoPullNSID,
1188 Repo: user.Did,
1189 Rkey: pull.Rkey,
···1215}
12161217func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
1218+ user := s.oauth.GetUser(r)
12191220 pull, ok := r.Context().Value("pull").(*db.Pull)
1221 if !ok {
···1242 return
1243 }
12441245+ ksClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
1246 if err != nil {
1247 log.Printf("failed to create client for %s: %s", f.Knot, err)
1248 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···1283 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1284 return
1285 }
1286+ client, err := s.oauth.AuthorizedClient(r)
1287+ if err != nil {
1288+ log.Println("failed to authorize client")
1289+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1290+ return
1291+ }
12921293+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1294 if err != nil {
1295 // failed to get record
1296 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···1300 recordPullSource := &tangled.RepoPull_Source{
1301 Branch: pull.PullSource.Branch,
1302 }
1303+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1304 Collection: tangled.RepoPullNSID,
1305 Repo: user.Did,
1306 Rkey: pull.Rkey,
···1333}
13341335func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
1336+ user := s.oauth.GetUser(r)
13371338 pull, ok := r.Context().Value("pull").(*db.Pull)
1339 if !ok {
···1362 }
13631364 // extract patch by performing compare
1365+ ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Core.Dev)
1366 if err != nil {
1367 log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)
1368 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···1377 }
13781379 // update the hidden tracking branch to latest
1380+ signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev)
1381 if err != nil {
1382 log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)
1383 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
···1426 s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1427 return
1428 }
1429+ client, err := s.oauth.AuthorizedClient(r)
1430+ if err != nil {
1431+ log.Println("failed to get client")
1432+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
1433+ return
1434+ }
14351436+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1437 if err != nil {
1438 // failed to get record
1439 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···1445 Branch: pull.PullSource.Branch,
1446 Repo: &repoAt,
1447 }
1448+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1449 Collection: tangled.RepoPullNSID,
1450 Repo: user.Did,
1451 Rkey: pull.Rkey,
···1528 log.Printf("failed to get primary email: %s", err)
1529 }
15301531+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
1532 if err != nil {
1533 log.Printf("failed to create signed client for %s: %s", f.Knot, err)
1534 s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
···1558}
15591560func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
1561+ user := s.oauth.GetUser(r)
15621563 f, err := s.fullyResolvedRepo(r)
1564 if err != nil {
···1612}
16131614func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) {
1615+ user := s.oauth.GetUser(r)
16161617 f, err := s.fullyResolvedRepo(r)
1618 if err != nil {
+98-60
appview/state/repo.go
···1819 "tangled.sh/tangled.sh/core/api/tangled"
20 "tangled.sh/tangled.sh/core/appview"
21- "tangled.sh/tangled.sh/core/appview/auth"
22 "tangled.sh/tangled.sh/core/appview/db"
023 "tangled.sh/tangled.sh/core/appview/pages"
24 "tangled.sh/tangled.sh/core/appview/pages/markup"
25 "tangled.sh/tangled.sh/core/appview/pages/repoinfo"
···45 return
46 }
4748- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
49 if err != nil {
50 log.Printf("failed to create unsigned client for %s", f.Knot)
51 s.pages.Error503(w)
···119120 emails := uniqueEmails(commitsTrunc)
121122- user := s.auth.GetUser(r)
123 s.pages.RepoIndexPage(w, pages.RepoIndexParams{
124 LoggedInUser: user,
125 RepoInfo: f.RepoInfo(s, user),
···150151 ref := chi.URLParam(r, "ref")
152153- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
154 if err != nil {
155 log.Println("failed to create unsigned client", err)
156 return
···190 tagMap[hash] = append(tagMap[hash], tag.Name)
191 }
192193- user := s.auth.GetUser(r)
194 s.pages.RepoLog(w, pages.RepoLogParams{
195 LoggedInUser: user,
196 TagMap: tagMap,
···209 return
210 }
211212- user := s.auth.GetUser(r)
213 s.pages.EditRepoDescriptionFragment(w, pages.RepoDescriptionParams{
214 RepoInfo: f.RepoInfo(s, user),
215 })
···232 return
233 }
234235- user := s.auth.GetUser(r)
236237 switch r.Method {
238 case http.MethodGet:
···241 })
242 return
243 case http.MethodPut:
244- user := s.auth.GetUser(r)
245 newDescription := r.FormValue("description")
246- client, _ := s.auth.AuthorizedClient(r)
00000247248 // optimistic update
249 err = db.UpdateDescription(s.db, string(repoAt), newDescription)
···256 // this is a bit of a pain because the golang atproto impl does not allow nil SwapRecord field
257 //
258 // SwapRecord is optional and should happen automagically, but given that it does not, we have to perform two requests
259- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoNSID, user.Did, rkey)
260 if err != nil {
261 // failed to get record
262 s.pages.Notice(w, "repo-notice", "Failed to update description, no record found on PDS.")
263 return
264 }
265- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
266 Collection: tangled.RepoNSID,
267 Repo: user.Did,
268 Rkey: rkey,
···303 }
304 ref := chi.URLParam(r, "ref")
305 protocol := "http"
306- if !s.config.Dev {
307 protocol = "https"
308 }
309···331 return
332 }
333334- user := s.auth.GetUser(r)
335 s.pages.RepoCommit(w, pages.RepoCommitParams{
336 LoggedInUser: user,
337 RepoInfo: f.RepoInfo(s, user),
···351 ref := chi.URLParam(r, "ref")
352 treePath := chi.URLParam(r, "*")
353 protocol := "http"
354- if !s.config.Dev {
355 protocol = "https"
356 }
357 resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, treePath))
···380 return
381 }
382383- user := s.auth.GetUser(r)
384385 var breadcrumbs [][]string
386 breadcrumbs = append(breadcrumbs, []string{f.RepoName, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), ref)})
···411 return
412 }
413414- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
415 if err != nil {
416 log.Println("failed to create unsigned client", err)
417 return
···451 }
452 }
453454- user := s.auth.GetUser(r)
455 s.pages.RepoTags(w, pages.RepoTagsParams{
456 LoggedInUser: user,
457 RepoInfo: f.RepoInfo(s, user),
···469 return
470 }
471472- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
473 if err != nil {
474 log.Println("failed to create unsigned client", err)
475 return
···511 return strings.Compare(a.Name, b.Name) * -1
512 })
513514- user := s.auth.GetUser(r)
515 s.pages.RepoBranches(w, pages.RepoBranchesParams{
516 LoggedInUser: user,
517 RepoInfo: f.RepoInfo(s, user),
···530 ref := chi.URLParam(r, "ref")
531 filePath := chi.URLParam(r, "*")
532 protocol := "http"
533- if !s.config.Dev {
534 protocol = "https"
535 }
536 resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
···568 showRendered = r.URL.Query().Get("code") != "true"
569 }
570571- user := s.auth.GetUser(r)
572 s.pages.RepoBlob(w, pages.RepoBlobParams{
573 LoggedInUser: user,
574 RepoInfo: f.RepoInfo(s, user),
···591 filePath := chi.URLParam(r, "*")
592593 protocol := "http"
594- if !s.config.Dev {
595 protocol = "https"
596 }
597 resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
···652 return
653 }
654655- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
656 if err != nil {
657 log.Println("failed to create client to ", f.Knot)
658 return
···714}
715716func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) {
717- user := s.auth.GetUser(r)
718719 f, err := s.fullyResolvedRepo(r)
720 if err != nil {
···723 }
724725 // remove record from pds
726- xrpcClient, _ := s.auth.AuthorizedClient(r)
0000727 repoRkey := f.RepoAt.RecordKey().String()
728- _, err = comatproto.RepoDeleteRecord(r.Context(), xrpcClient, &comatproto.RepoDeleteRecord_Input{
729 Collection: tangled.RepoNSID,
730 Repo: user.Did,
731 Rkey: repoRkey,
···743 return
744 }
745746- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
747 if err != nil {
748 log.Println("failed to create client to ", f.Knot)
749 return
···838 return
839 }
840841- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
842 if err != nil {
843 log.Println("failed to create client to ", f.Knot)
844 return
···868 switch r.Method {
869 case http.MethodGet:
870 // for now, this is just pubkeys
871- user := s.auth.GetUser(r)
872 repoCollaborators, err := f.Collaborators(r.Context(), s)
873 if err != nil {
874 log.Println("failed to get collaborators", err)
···884885 var branchNames []string
886 var defaultBranch string
887- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
888 if err != nil {
889 log.Println("failed to create unsigned client", err)
890 } else {
···1008 return collaborators, nil
1009}
10101011-func (f *FullyResolvedRepo) RepoInfo(s *State, u *auth.User) repoinfo.RepoInfo {
1012 isStarred := false
1013 if u != nil {
1014 isStarred = db.GetStarStatus(s.db, u.Did, syntax.ATURI(f.RepoAt))
···10511052 knot := f.Knot
1053 var disableFork bool
1054- us, err := NewUnsignedClient(knot, s.config.Dev)
1055 if err != nil {
1056 log.Printf("failed to create unsigned client for %s: %v", knot, err)
1057 } else {
···1105}
11061107func (s *State) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
1108- user := s.auth.GetUser(r)
1109 f, err := s.fullyResolvedRepo(r)
1110 if err != nil {
1111 log.Println("failed to get repo and knot", err)
···1159}
11601161func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
1162- user := s.auth.GetUser(r)
1163 f, err := s.fullyResolvedRepo(r)
1164 if err != nil {
1165 log.Println("failed to get repo and knot", err)
···11951196 closed := tangled.RepoIssueStateClosed
11971198- client, _ := s.auth.AuthorizedClient(r)
1199- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
00001200 Collection: tangled.RepoIssueStateNSID,
1201 Repo: user.Did,
1202 Rkey: appview.TID(),
···1214 return
1215 }
12161217- err := db.CloseIssue(s.db, f.RepoAt, issueIdInt)
1218 if err != nil {
1219 log.Println("failed to close issue", err)
1220 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
···1231}
12321233func (s *State) ReopenIssue(w http.ResponseWriter, r *http.Request) {
1234- user := s.auth.GetUser(r)
1235 f, err := s.fullyResolvedRepo(r)
1236 if err != nil {
1237 log.Println("failed to get repo and knot", err)
···1279}
12801281func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) {
1282- user := s.auth.GetUser(r)
1283 f, err := s.fullyResolvedRepo(r)
1284 if err != nil {
1285 log.Println("failed to get repo and knot", err)
···1330 }
13311332 atUri := f.RepoAt.String()
1333- client, _ := s.auth.AuthorizedClient(r)
1334- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
000001335 Collection: tangled.RepoIssueCommentNSID,
1336 Repo: user.Did,
1337 Rkey: rkey,
···1358}
13591360func (s *State) IssueComment(w http.ResponseWriter, r *http.Request) {
1361- user := s.auth.GetUser(r)
1362 f, err := s.fullyResolvedRepo(r)
1363 if err != nil {
1364 log.Println("failed to get repo and knot", err)
···1417}
14181419func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
1420- user := s.auth.GetUser(r)
1421 f, err := s.fullyResolvedRepo(r)
1422 if err != nil {
1423 log.Println("failed to get repo and knot", err)
···1469 case http.MethodPost:
1470 // extract form value
1471 newBody := r.FormValue("body")
1472- client, _ := s.auth.AuthorizedClient(r)
000001473 rkey := comment.Rkey
14741475 // optimistic update
···1484 // rkey is optional, it was introduced later
1485 if comment.Rkey != "" {
1486 // update the record on pds
1487- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, rkey)
1488 if err != nil {
1489 // failed to get record
1490 log.Println(err, rkey)
···1499 createdAt := record["createdAt"].(string)
1500 commentIdInt64 := int64(commentIdInt)
15011502- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1503 Collection: tangled.RepoIssueCommentNSID,
1504 Repo: user.Did,
1505 Rkey: rkey,
···1542}
15431544func (s *State) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
1545- user := s.auth.GetUser(r)
1546 f, err := s.fullyResolvedRepo(r)
1547 if err != nil {
1548 log.Println("failed to get repo and knot", err)
···15991600 // delete from pds
1601 if comment.Rkey != "" {
1602- client, _ := s.auth.AuthorizedClient(r)
1603- _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
000001604 Collection: tangled.GraphFollowNSID,
1605 Repo: user.Did,
1606 Rkey: comment.Rkey,
···1647 page = pagination.FirstPage()
1648 }
16491650- user := s.auth.GetUser(r)
1651 f, err := s.fullyResolvedRepo(r)
1652 if err != nil {
1653 log.Println("failed to get repo and knot", err)
···1676 }
16771678 s.pages.RepoIssues(w, pages.RepoIssuesParams{
1679- LoggedInUser: s.auth.GetUser(r),
1680 RepoInfo: f.RepoInfo(s, user),
1681 Issues: issues,
1682 DidHandleMap: didHandleMap,
···1687}
16881689func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) {
1690- user := s.auth.GetUser(r)
16911692 f, err := s.fullyResolvedRepo(r)
1693 if err != nil {
···1735 return
1736 }
17371738- client, _ := s.auth.AuthorizedClient(r)
000001739 atUri := f.RepoAt.String()
1740- resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1741 Collection: tangled.RepoIssueNSID,
1742 Repo: user.Did,
1743 Rkey: appview.TID(),
···1770}
17711772func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
1773- user := s.auth.GetUser(r)
1774 f, err := s.fullyResolvedRepo(r)
1775 if err != nil {
1776 log.Printf("failed to resolve source repo: %v", err)
···17791780 switch r.Method {
1781 case http.MethodGet:
1782- user := s.auth.GetUser(r)
1783 knots, err := s.enforcer.GetDomainsForUser(user.Did)
1784 if err != nil {
1785 s.pages.Notice(w, "repo", "Invalid user account.")
···1829 return
1830 }
18311832- client, err := NewSignedClient(knot, secret, s.config.Dev)
1833 if err != nil {
1834 s.pages.Notice(w, "repo", "Failed to reach knot server.")
1835 return
1836 }
18371838 var uri string
1839- if s.config.Dev {
1840 uri = "http"
1841 } else {
1842 uri = "https"
···1883 // continue
1884 }
18851886- xrpcClient, _ := s.auth.AuthorizedClient(r)
0000018871888 createdAt := time.Now().Format(time.RFC3339)
1889- atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{
1890 Collection: tangled.RepoNSID,
1891 Repo: user.Did,
1892 Rkey: rkey,
···1819 "tangled.sh/tangled.sh/core/api/tangled"
20 "tangled.sh/tangled.sh/core/appview"
021 "tangled.sh/tangled.sh/core/appview/db"
22+ "tangled.sh/tangled.sh/core/appview/oauth"
23 "tangled.sh/tangled.sh/core/appview/pages"
24 "tangled.sh/tangled.sh/core/appview/pages/markup"
25 "tangled.sh/tangled.sh/core/appview/pages/repoinfo"
···45 return
46 }
4748+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
49 if err != nil {
50 log.Printf("failed to create unsigned client for %s", f.Knot)
51 s.pages.Error503(w)
···119120 emails := uniqueEmails(commitsTrunc)
121122+ user := s.oauth.GetUser(r)
123 s.pages.RepoIndexPage(w, pages.RepoIndexParams{
124 LoggedInUser: user,
125 RepoInfo: f.RepoInfo(s, user),
···150151 ref := chi.URLParam(r, "ref")
152153+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
154 if err != nil {
155 log.Println("failed to create unsigned client", err)
156 return
···190 tagMap[hash] = append(tagMap[hash], tag.Name)
191 }
192193+ user := s.oauth.GetUser(r)
194 s.pages.RepoLog(w, pages.RepoLogParams{
195 LoggedInUser: user,
196 TagMap: tagMap,
···209 return
210 }
211212+ user := s.oauth.GetUser(r)
213 s.pages.EditRepoDescriptionFragment(w, pages.RepoDescriptionParams{
214 RepoInfo: f.RepoInfo(s, user),
215 })
···232 return
233 }
234235+ user := s.oauth.GetUser(r)
236237 switch r.Method {
238 case http.MethodGet:
···241 })
242 return
243 case http.MethodPut:
244+ user := s.oauth.GetUser(r)
245 newDescription := r.FormValue("description")
246+ client, err := s.oauth.AuthorizedClient(r)
247+ if err != nil {
248+ log.Println("failed to get client")
249+ s.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
250+ return
251+ }
252253 // optimistic update
254 err = db.UpdateDescription(s.db, string(repoAt), newDescription)
···261 // this is a bit of a pain because the golang atproto impl does not allow nil SwapRecord field
262 //
263 // SwapRecord is optional and should happen automagically, but given that it does not, we have to perform two requests
264+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoNSID, user.Did, rkey)
265 if err != nil {
266 // failed to get record
267 s.pages.Notice(w, "repo-notice", "Failed to update description, no record found on PDS.")
268 return
269 }
270+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
271 Collection: tangled.RepoNSID,
272 Repo: user.Did,
273 Rkey: rkey,
···308 }
309 ref := chi.URLParam(r, "ref")
310 protocol := "http"
311+ if !s.config.Core.Dev {
312 protocol = "https"
313 }
314···336 return
337 }
338339+ user := s.oauth.GetUser(r)
340 s.pages.RepoCommit(w, pages.RepoCommitParams{
341 LoggedInUser: user,
342 RepoInfo: f.RepoInfo(s, user),
···356 ref := chi.URLParam(r, "ref")
357 treePath := chi.URLParam(r, "*")
358 protocol := "http"
359+ if !s.config.Core.Dev {
360 protocol = "https"
361 }
362 resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, treePath))
···385 return
386 }
387388+ user := s.oauth.GetUser(r)
389390 var breadcrumbs [][]string
391 breadcrumbs = append(breadcrumbs, []string{f.RepoName, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), ref)})
···416 return
417 }
418419+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
420 if err != nil {
421 log.Println("failed to create unsigned client", err)
422 return
···456 }
457 }
458459+ user := s.oauth.GetUser(r)
460 s.pages.RepoTags(w, pages.RepoTagsParams{
461 LoggedInUser: user,
462 RepoInfo: f.RepoInfo(s, user),
···474 return
475 }
476477+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
478 if err != nil {
479 log.Println("failed to create unsigned client", err)
480 return
···516 return strings.Compare(a.Name, b.Name) * -1
517 })
518519+ user := s.oauth.GetUser(r)
520 s.pages.RepoBranches(w, pages.RepoBranchesParams{
521 LoggedInUser: user,
522 RepoInfo: f.RepoInfo(s, user),
···535 ref := chi.URLParam(r, "ref")
536 filePath := chi.URLParam(r, "*")
537 protocol := "http"
538+ if !s.config.Core.Dev {
539 protocol = "https"
540 }
541 resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
···573 showRendered = r.URL.Query().Get("code") != "true"
574 }
575576+ user := s.oauth.GetUser(r)
577 s.pages.RepoBlob(w, pages.RepoBlobParams{
578 LoggedInUser: user,
579 RepoInfo: f.RepoInfo(s, user),
···596 filePath := chi.URLParam(r, "*")
597598 protocol := "http"
599+ if !s.config.Core.Dev {
600 protocol = "https"
601 }
602 resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
···657 return
658 }
659660+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
661 if err != nil {
662 log.Println("failed to create client to ", f.Knot)
663 return
···719}
720721func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) {
722+ user := s.oauth.GetUser(r)
723724 f, err := s.fullyResolvedRepo(r)
725 if err != nil {
···728 }
729730 // remove record from pds
731+ xrpcClient, err := s.oauth.AuthorizedClient(r)
732+ if err != nil {
733+ log.Println("failed to get authorized client", err)
734+ return
735+ }
736 repoRkey := f.RepoAt.RecordKey().String()
737+ _, err = xrpcClient.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
738 Collection: tangled.RepoNSID,
739 Repo: user.Did,
740 Rkey: repoRkey,
···752 return
753 }
754755+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
756 if err != nil {
757 log.Println("failed to create client to ", f.Knot)
758 return
···847 return
848 }
849850+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
851 if err != nil {
852 log.Println("failed to create client to ", f.Knot)
853 return
···877 switch r.Method {
878 case http.MethodGet:
879 // for now, this is just pubkeys
880+ user := s.oauth.GetUser(r)
881 repoCollaborators, err := f.Collaborators(r.Context(), s)
882 if err != nil {
883 log.Println("failed to get collaborators", err)
···893894 var branchNames []string
895 var defaultBranch string
896+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
897 if err != nil {
898 log.Println("failed to create unsigned client", err)
899 } else {
···1017 return collaborators, nil
1018}
10191020+func (f *FullyResolvedRepo) RepoInfo(s *State, u *oauth.User) repoinfo.RepoInfo {
1021 isStarred := false
1022 if u != nil {
1023 isStarred = db.GetStarStatus(s.db, u.Did, syntax.ATURI(f.RepoAt))
···10601061 knot := f.Knot
1062 var disableFork bool
1063+ us, err := NewUnsignedClient(knot, s.config.Core.Dev)
1064 if err != nil {
1065 log.Printf("failed to create unsigned client for %s: %v", knot, err)
1066 } else {
···1114}
11151116func (s *State) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
1117+ user := s.oauth.GetUser(r)
1118 f, err := s.fullyResolvedRepo(r)
1119 if err != nil {
1120 log.Println("failed to get repo and knot", err)
···1168}
11691170func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
1171+ user := s.oauth.GetUser(r)
1172 f, err := s.fullyResolvedRepo(r)
1173 if err != nil {
1174 log.Println("failed to get repo and knot", err)
···12041205 closed := tangled.RepoIssueStateClosed
12061207+ client, err := s.oauth.AuthorizedClient(r)
1208+ if err != nil {
1209+ log.Println("failed to get authorized client", err)
1210+ return
1211+ }
1212+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1213 Collection: tangled.RepoIssueStateNSID,
1214 Repo: user.Did,
1215 Rkey: appview.TID(),
···1227 return
1228 }
12291230+ err = db.CloseIssue(s.db, f.RepoAt, issueIdInt)
1231 if err != nil {
1232 log.Println("failed to close issue", err)
1233 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
···1244}
12451246func (s *State) ReopenIssue(w http.ResponseWriter, r *http.Request) {
1247+ user := s.oauth.GetUser(r)
1248 f, err := s.fullyResolvedRepo(r)
1249 if err != nil {
1250 log.Println("failed to get repo and knot", err)
···1292}
12931294func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) {
1295+ user := s.oauth.GetUser(r)
1296 f, err := s.fullyResolvedRepo(r)
1297 if err != nil {
1298 log.Println("failed to get repo and knot", err)
···1343 }
13441345 atUri := f.RepoAt.String()
1346+ client, err := s.oauth.AuthorizedClient(r)
1347+ if err != nil {
1348+ log.Println("failed to get authorized client", err)
1349+ s.pages.Notice(w, "issue-comment", "Failed to create comment.")
1350+ return
1351+ }
1352+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1353 Collection: tangled.RepoIssueCommentNSID,
1354 Repo: user.Did,
1355 Rkey: rkey,
···1376}
13771378func (s *State) IssueComment(w http.ResponseWriter, r *http.Request) {
1379+ user := s.oauth.GetUser(r)
1380 f, err := s.fullyResolvedRepo(r)
1381 if err != nil {
1382 log.Println("failed to get repo and knot", err)
···1435}
14361437func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
1438+ user := s.oauth.GetUser(r)
1439 f, err := s.fullyResolvedRepo(r)
1440 if err != nil {
1441 log.Println("failed to get repo and knot", err)
···1487 case http.MethodPost:
1488 // extract form value
1489 newBody := r.FormValue("body")
1490+ client, err := s.oauth.AuthorizedClient(r)
1491+ if err != nil {
1492+ log.Println("failed to get authorized client", err)
1493+ s.pages.Notice(w, "issue-comment", "Failed to create comment.")
1494+ return
1495+ }
1496 rkey := comment.Rkey
14971498 // optimistic update
···1507 // rkey is optional, it was introduced later
1508 if comment.Rkey != "" {
1509 // update the record on pds
1510+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoIssueCommentNSID, user.Did, rkey)
1511 if err != nil {
1512 // failed to get record
1513 log.Println(err, rkey)
···1522 createdAt := record["createdAt"].(string)
1523 commentIdInt64 := int64(commentIdInt)
15241525+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1526 Collection: tangled.RepoIssueCommentNSID,
1527 Repo: user.Did,
1528 Rkey: rkey,
···1565}
15661567func (s *State) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
1568+ user := s.oauth.GetUser(r)
1569 f, err := s.fullyResolvedRepo(r)
1570 if err != nil {
1571 log.Println("failed to get repo and knot", err)
···16221623 // delete from pds
1624 if comment.Rkey != "" {
1625+ client, err := s.oauth.AuthorizedClient(r)
1626+ if err != nil {
1627+ log.Println("failed to get authorized client", err)
1628+ s.pages.Notice(w, "issue-comment", "Failed to delete comment.")
1629+ return
1630+ }
1631+ _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
1632 Collection: tangled.GraphFollowNSID,
1633 Repo: user.Did,
1634 Rkey: comment.Rkey,
···1675 page = pagination.FirstPage()
1676 }
16771678+ user := s.oauth.GetUser(r)
1679 f, err := s.fullyResolvedRepo(r)
1680 if err != nil {
1681 log.Println("failed to get repo and knot", err)
···1704 }
17051706 s.pages.RepoIssues(w, pages.RepoIssuesParams{
1707+ LoggedInUser: s.oauth.GetUser(r),
1708 RepoInfo: f.RepoInfo(s, user),
1709 Issues: issues,
1710 DidHandleMap: didHandleMap,
···1715}
17161717func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) {
1718+ user := s.oauth.GetUser(r)
17191720 f, err := s.fullyResolvedRepo(r)
1721 if err != nil {
···1763 return
1764 }
17651766+ client, err := s.oauth.AuthorizedClient(r)
1767+ if err != nil {
1768+ log.Println("failed to get authorized client", err)
1769+ s.pages.Notice(w, "issues", "Failed to create issue.")
1770+ return
1771+ }
1772 atUri := f.RepoAt.String()
1773+ resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1774 Collection: tangled.RepoIssueNSID,
1775 Repo: user.Did,
1776 Rkey: appview.TID(),
···1803}
18041805func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
1806+ user := s.oauth.GetUser(r)
1807 f, err := s.fullyResolvedRepo(r)
1808 if err != nil {
1809 log.Printf("failed to resolve source repo: %v", err)
···18121813 switch r.Method {
1814 case http.MethodGet:
1815+ user := s.oauth.GetUser(r)
1816 knots, err := s.enforcer.GetDomainsForUser(user.Did)
1817 if err != nil {
1818 s.pages.Notice(w, "repo", "Invalid user account.")
···1862 return
1863 }
18641865+ client, err := NewSignedClient(knot, secret, s.config.Core.Dev)
1866 if err != nil {
1867 s.pages.Notice(w, "repo", "Failed to reach knot server.")
1868 return
1869 }
18701871 var uri string
1872+ if s.config.Core.Dev {
1873 uri = "http"
1874 } else {
1875 uri = "https"
···1916 // continue
1917 }
19181919+ xrpcClient, err := s.oauth.AuthorizedClient(r)
1920+ if err != nil {
1921+ log.Println("failed to get authorized client", err)
1922+ s.pages.Notice(w, "repo", "Failed to create repository.")
1923+ return
1924+ }
19251926 createdAt := time.Now().Format(time.RFC3339)
1927+ atresp, err := xrpcClient.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
1928 Collection: tangled.RepoNSID,
1929 Repo: user.Did,
1930 Rkey: rkey,
+3-3
appview/state/repo_util.go
···12 "github.com/bluesky-social/indigo/atproto/syntax"
13 "github.com/go-chi/chi/v5"
14 "github.com/go-git/go-git/v5/plumbing/object"
15- "tangled.sh/tangled.sh/core/appview/auth"
16 "tangled.sh/tangled.sh/core/appview/db"
017 "tangled.sh/tangled.sh/core/appview/pages/repoinfo"
18)
19···45 ref := chi.URLParam(r, "ref")
4647 if ref == "" {
48- us, err := NewUnsignedClient(knot, s.config.Dev)
49 if err != nil {
50 return nil, err
51 }
···73 }, nil
74}
7576-func RolesInRepo(s *State, u *auth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo {
77 if u != nil {
78 r := s.enforcer.GetPermissionsInRepo(u.Did, f.Knot, f.DidSlashRepo())
79 return repoinfo.RolesInRepo{r}
···12 "github.com/bluesky-social/indigo/atproto/syntax"
13 "github.com/go-chi/chi/v5"
14 "github.com/go-git/go-git/v5/plumbing/object"
015 "tangled.sh/tangled.sh/core/appview/db"
16+ "tangled.sh/tangled.sh/core/appview/oauth"
17 "tangled.sh/tangled.sh/core/appview/pages/repoinfo"
18)
19···45 ref := chi.URLParam(r, "ref")
4647 if ref == "" {
48+ us, err := NewUnsignedClient(knot, s.config.Core.Dev)
49 if err != nil {
50 return nil, err
51 }
···73 }, nil
74}
7576+func RolesInRepo(s *State, u *oauth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo {
77 if u != nil {
78 r := s.enforcer.GetPermissionsInRepo(u.Did, f.Knot, f.DidSlashRepo())
79 return repoinfo.RolesInRepo{r}