Monorepo for Tangled tangled.org

appview: update state, ingester, middleware, and resolver for repo DID #1140

open opened by oyster.cafe targeting master from oyster.cafe/tangled-core: master
Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:3fwecdnvtcscjnrx2p4n7alz/sh.tangled.repo.pull/3mgprvt2eon22
+210 -173
Interdiff #8 #9
+3 -7
appview/ingester.go
··· 125 125 126 126 switch { 127 127 case record.SubjectDid != nil: 128 - star.SubjectDid = *record.SubjectDid 129 128 repo, repoErr := db.GetRepo(i.Db, orm.FilterEq("repo_did", *record.SubjectDid)) 130 129 if repoErr == nil { 131 130 subjectUri = repo.RepoAt() ··· 140 139 star.RepoAt = subjectUri 141 140 repo, repoErr := db.GetRepoByAtUri(i.Db, subjectUri.String()) 142 141 if repoErr == nil && repo.RepoDid != "" { 143 - star.SubjectDid = repo.RepoDid 144 142 if enqErr := db.EnqueuePdsRewrite(i.Db, did, repo.RepoDid, tangled.FeedStarNSID, e.Commit.RKey, *record.Subject); enqErr != nil { 145 143 l.Warn("failed to enqueue PDS rewrite for star", "err", enqErr, "did", did, "repoDid", repo.RepoDid) 146 144 } ··· 289 287 Did: did, 290 288 Rkey: e.Commit.RKey, 291 289 RepoAt: repo.RepoAt(), 292 - RepoDid: repoDid, 293 290 Tag: plumbing.Hash(record.Tag), 294 291 CreatedAt: createdAt, 295 292 BlobCid: cid.Cid(record.Artifact.Ref), ··· 868 865 869 866 issue := models.IssueFromRecord(did, rkey, record) 870 867 871 - if issue.RepoDid == "" && issue.RepoAt == "" { 872 - return fmt.Errorf("issue record has neither repo nor repoDid") 868 + if issue.RepoAt == "" { 869 + return fmt.Errorf("issue record has no repo field") 873 870 } 874 871 875 872 if err := i.Validator.ValidateIssue(&issue); err != nil { 876 873 return fmt.Errorf("failed to validate issue: %w", err) 877 874 } 878 875 879 - if issue.RepoDid == "" && record.Repo != nil { 876 + if record.Repo != nil { 880 877 repo, repoErr := db.GetRepoByAtUri(i.Db, *record.Repo) 881 878 if repoErr == nil && repo.RepoDid != "" { 882 - issue.RepoDid = repo.RepoDid 883 879 if enqErr := db.EnqueuePdsRewrite(i.Db, did, repo.RepoDid, tangled.RepoIssueNSID, rkey, *record.Repo); enqErr != nil { 884 880 l.Warn("failed to enqueue PDS rewrite for issue", "err", enqErr, "did", did, "repoDid", repo.RepoDid) 885 881 }
appview/middleware/middleware.go

This file has not been changed.

+1 -2
appview/reporesolver/resolver.go
··· 85 85 86 86 stats := repo.RepoStats 87 87 if stats == nil { 88 - starCount, starErr := db.GetStarCount(rr.execer, repo.RepoDid, repoAt) 88 + starCount, starErr := db.GetStarCount(rr.execer, repoAt) 89 89 if starErr != nil { 90 90 log.Println("failed to get star count for ", repoAt) 91 91 } ··· 121 121 // this is basically a models.Repo 122 122 OwnerDid: ownerId.DID.String(), 123 123 OwnerHandle: ownerId.Handle.String(), 124 - RepoDid: repo.RepoDid, 125 124 Name: repo.Name, 126 125 Rkey: repo.Rkey, 127 126 Description: repo.Description,
appview/state/git_http.go

This file has not been changed.

-1
appview/state/knotstream.go
··· 267 267 268 268 langs = append(langs, models.RepoLanguage{ 269 269 RepoAt: repo.RepoAt(), 270 - RepoDid: repo.RepoDid, 271 270 Ref: ref.Short(), 272 271 IsDefaultRef: record.Meta.IsDefaultRef, 273 272 Language: l.Lang,
appview/state/router.go

This file has not been changed.

+2 -5
appview/state/star.go
··· 71 71 RepoAt: subjectUri, 72 72 Rkey: rkey, 73 73 } 74 - if repoHasDid { 75 - star.SubjectDid = repo.RepoDid 76 - } 77 74 78 75 err = db.AddStar(s.db, star) 79 76 if err != nil { ··· 81 78 return 82 79 } 83 80 84 - starCount, err := db.GetStarCount(s.db, "", subjectUri) 81 + starCount, err := db.GetStarCount(s.db, subjectUri) 85 82 if err != nil { 86 83 log.Println("failed to get star count for ", subjectUri) 87 84 } ··· 120 117 // this is not an issue, the firehose event might have already done this 121 118 } 122 119 123 - starCount, err := db.GetStarCount(s.db, "", subjectUri) 120 + starCount, err := db.GetStarCount(s.db, subjectUri) 124 121 if err != nil { 125 122 log.Println("failed to get star count for ", subjectUri) 126 123 return
-4
appview/state/state.go
··· 475 475 Name: repoName, 476 476 DefaultBranch: &defaultBranch, 477 477 } 478 - if rd := strings.TrimSpace(r.FormValue("repo_did")); rd != "" { 479 - input.RepoDid = &rd 480 - } 481 - 482 478 createResp, xe := tangled.RepoCreate( 483 479 r.Context(), 484 480 client,
appview/validator/label.go

This file has not been changed.

+2 -2
appview/issues/issues.go
··· 306 306 return 307 307 } 308 308 309 - roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())} 309 + roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())} 310 310 isRepoOwner := roles.IsOwner() 311 311 isCollaborator := roles.IsCollaborator() 312 312 isIssueOwner := user.Active.Did == issue.Did ··· 354 354 return 355 355 } 356 356 357 - roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())} 357 + roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())} 358 358 isRepoOwner := roles.IsOwner() 359 359 isCollaborator := roles.IsCollaborator() 360 360 isIssueOwner := user.Active.Did == issue.Did
+30 -42
appview/pulls/pulls.go
··· 406 406 } 407 407 408 408 // user can only delete branch if they are a collaborator in the repo that the branch belongs to 409 - perms := s.enforcer.GetPermissionsInRepo(user.Active.Did, repo.Knot, repo.DidSlashRepo()) 409 + perms := s.enforcer.GetPermissionsInRepo(user.Active.Did, repo.Knot, repo.RepoIdentifier()) 410 410 if !slices.Contains(perms, "repo:push") { 411 411 return nil 412 412 } ··· 420 420 Host: host, 421 421 } 422 422 423 - resp, err := tangled.RepoBranch(r.Context(), xrpcc, branch, fmt.Sprintf("%s/%s", repo.Did, repo.Name)) 423 + resp, err := tangled.RepoBranch(r.Context(), xrpcc, branch, repo.RepoIdentifier()) 424 424 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 425 425 return nil 426 426 } ··· 436 436 return pages.Unknown 437 437 } 438 438 439 - var knot, ownerDid, repoName string 440 - 439 + var sourceRepo *models.Repo 441 440 if pull.PullSource.RepoAt != nil { 442 - // fork-based pulls 443 - sourceRepo, err := db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String()) 441 + var err error 442 + sourceRepo, err = db.GetRepoByAtUri(s.db, pull.PullSource.RepoAt.String()) 444 443 if err != nil { 445 444 log.Println("failed to get source repo", err) 446 445 return pages.Unknown 447 446 } 448 - 449 - knot = sourceRepo.Knot 450 - ownerDid = sourceRepo.Did 451 - repoName = sourceRepo.Name 452 447 } else { 453 - // pulls within the same repo 454 - knot = repo.Knot 455 - ownerDid = repo.Did 456 - repoName = repo.Name 448 + sourceRepo = repo 457 449 } 458 450 459 451 scheme := "http" 460 452 if !s.config.Core.Dev { 461 453 scheme = "https" 462 454 } 463 - host := fmt.Sprintf("%s://%s", scheme, knot) 455 + host := fmt.Sprintf("%s://%s", scheme, sourceRepo.Knot) 464 456 xrpcc := &indigoxrpc.Client{ 465 457 Host: host, 466 458 } 467 459 468 - didSlashName := fmt.Sprintf("%s/%s", ownerDid, repoName) 469 - branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, didSlashName) 460 + branchResp, err := tangled.RepoBranch(r.Context(), xrpcc, pull.PullSource.Branch, sourceRepo.RepoIdentifier()) 470 461 if err != nil { 471 462 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 472 463 log.Println("failed to call XRPC repo.branches", xrpcerr) ··· 913 904 Host: host, 914 905 } 915 906 916 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 917 - xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 907 + xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier()) 918 908 if err != nil { 919 909 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 920 910 log.Println("failed to call XRPC repo.branches", xrpcerr) ··· 963 953 } 964 954 965 955 // Determine PR type based on input parameters 966 - roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())} 956 + roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())} 967 957 isPushAllowed := roles.IsPushAllowed() 968 958 isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == "" 969 959 isForkBased := fromFork != "" && sourceBranch != "" ··· 1079 1069 Host: host, 1080 1070 } 1081 1071 1082 - didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name) 1083 - xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, didSlashRepo, targetBranch, sourceBranch) 1072 + xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo.RepoIdentifier(), targetBranch, sourceBranch) 1084 1073 if err != nil { 1085 1074 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1086 1075 log.Println("failed to call XRPC repo.compare", xrpcerr) ··· 1189 1178 Host: forkHost, 1190 1179 } 1191 1180 1192 - forkRepoId := fmt.Sprintf("%s/%s", fork.Did, fork.Name) 1193 - forkXrpcBytes, err := tangled.RepoCompare(r.Context(), forkXrpcc, forkRepoId, hiddenRef, sourceBranch) 1181 + forkXrpcBytes, err := tangled.RepoCompare(r.Context(), forkXrpcc, fork.RepoIdentifier(), hiddenRef, sourceBranch) 1194 1182 if err != nil { 1195 1183 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1196 1184 log.Println("failed to call XRPC repo.compare for fork", xrpcerr) ··· 1347 1335 Rkey: rkey, 1348 1336 Record: &lexutil.LexiconTypeDecoder{ 1349 1337 Val: &tangled.RepoPull{ 1350 - Title: title, 1351 - Target: &tangled.RepoPull_Target{ 1352 - Repo: string(repo.RepoAt()), 1353 - Branch: targetBranch, 1354 - }, 1338 + Title: title, 1339 + Target: repoPullTarget(repo, targetBranch), 1355 1340 PatchBlob: blob.Blob, 1356 1341 Source: recordPullSource, 1357 1342 CreatedAt: time.Now().Format(time.RFC3339), ··· 1544 1529 Host: host, 1545 1530 } 1546 1531 1547 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 1548 - xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 1532 + xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier()) 1549 1533 if err != nil { 1550 1534 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1551 1535 log.Println("failed to call XRPC repo.branches", xrpcerr) ··· 1631 1615 Host: sourceHost, 1632 1616 } 1633 1617 1634 - sourceRepo := fmt.Sprintf("%s/%s", forkOwnerDid, repo.Name) 1635 - sourceXrpcBytes, err := tangled.RepoBranches(r.Context(), sourceXrpcc, "", 0, sourceRepo) 1618 + sourceXrpcBytes, err := tangled.RepoBranches(r.Context(), sourceXrpcc, "", 0, repo.RepoIdentifier()) 1636 1619 if err != nil { 1637 1620 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1638 1621 log.Println("failed to call XRPC repo.branches for source", xrpcerr) ··· 1660 1643 Host: targetHost, 1661 1644 } 1662 1645 1663 - targetRepo := fmt.Sprintf("%s/%s", f.Did, f.Name) 1664 - targetXrpcBytes, err := tangled.RepoBranches(r.Context(), targetXrpcc, "", 0, targetRepo) 1646 + targetXrpcBytes, err := tangled.RepoBranches(r.Context(), targetXrpcc, "", 0, f.RepoIdentifier()) 1665 1647 if err != nil { 1666 1648 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1667 1649 log.Println("failed to call XRPC repo.branches for target", xrpcerr) ··· 1771 1753 return 1772 1754 } 1773 1755 1774 - roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())} 1756 + roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())} 1775 1757 if !roles.IsPushAllowed() { 1776 1758 log.Println("unauthorized user") 1777 1759 w.WriteHeader(http.StatusUnauthorized) ··· 1787 1769 Host: host, 1788 1770 } 1789 1771 1790 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 1791 - xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, pull.TargetBranch, pull.PullSource.Branch) 1772 + xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, f.RepoIdentifier(), pull.TargetBranch, pull.PullSource.Branch) 1792 1773 if err != nil { 1793 1774 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1794 1775 log.Println("failed to call XRPC repo.compare", xrpcerr) ··· 1881 1862 forkScheme = "https" 1882 1863 } 1883 1864 forkHost := fmt.Sprintf("%s://%s", forkScheme, forkRepo.Knot) 1884 - forkRepoId := fmt.Sprintf("%s/%s", forkRepo.Did, forkRepo.Name) 1885 - forkXrpcBytes, err := tangled.RepoCompare(r.Context(), &indigoxrpc.Client{Host: forkHost}, forkRepoId, hiddenRef, pull.PullSource.Branch) 1865 + forkXrpcBytes, err := tangled.RepoCompare(r.Context(), &indigoxrpc.Client{Host: forkHost}, forkRepo.RepoIdentifier(), hiddenRef, pull.PullSource.Branch) 1886 1866 if err != nil { 1887 1867 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 1888 1868 log.Println("failed to call XRPC repo.compare for fork", xrpcerr) ··· 2360 2340 } 2361 2341 2362 2342 // auth filter: only owner or collaborators can close 2363 - roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())} 2343 + roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())} 2364 2344 isOwner := roles.IsOwner() 2365 2345 isCollaborator := roles.IsCollaborator() 2366 2346 isPullAuthor := user.Active.Did == pull.OwnerDid ··· 2434 2414 } 2435 2415 2436 2416 // auth filter: only owner or collaborators can close 2437 - roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())} 2417 + roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.RepoIdentifier())} 2438 2418 isOwner := roles.IsOwner() 2439 2419 isCollaborator := roles.IsCollaborator() 2440 2420 isPullAuthor := user.Active.Did == pull.OwnerDid ··· 2559 2539 } 2560 2540 2561 2541 func ptrPullState(s models.PullState) *models.PullState { return &s } 2542 + 2543 + func repoPullTarget(repo *models.Repo, branch string) *tangled.RepoPull_Target { 2544 + s := string(repo.RepoAt()) 2545 + return &tangled.RepoPull_Target{ 2546 + Branch: branch, 2547 + Repo: &s, 2548 + } 2549 + }
+2 -2
appview/repo/archive.go
··· 25 25 scheme = "https" 26 26 } 27 27 host := fmt.Sprintf("%s://%s", scheme, f.Knot) 28 - didSlashRepo := f.DidSlashRepo() 28 + didSlashRepo := f.RepoIdentifier() 29 29 30 30 // build the xrpc url 31 31 u, err := url.Parse(host) ··· 70 70 if link := resp.Header.Get("Link"); link != "" { 71 71 if resolvedRef, err := extractImmutableLink(link); err == nil { 72 72 newLink := fmt.Sprintf("<%s/%s/archive/%s.tar.gz>; rel=\"immutable\"", 73 - rp.config.Core.BaseUrl(), f.DidSlashRepo(), resolvedRef) 73 + rp.config.Core.BaseUrl(), f.RepoIdentifier(), resolvedRef) 74 74 w.Header().Set("Link", newLink) 75 75 } 76 76 }
+18 -9
appview/repo/artifact.go
··· 80 80 Repo: user.Active.Did, 81 81 Rkey: rkey, 82 82 Record: &lexutil.LexiconTypeDecoder{ 83 - Val: &tangled.RepoArtifact{ 84 - Artifact: uploadBlobResp.Blob, 85 - CreatedAt: createdAt.Format(time.RFC3339), 86 - Name: header.Filename, 87 - Repo: f.RepoAt().String(), 88 - Tag: tag.Tag.Hash[:], 89 - }, 83 + Val: repoArtifactRecord(f, uploadBlobResp.Blob, createdAt, header.Filename, tag.Tag.Hash[:]), 90 84 }, 91 85 }) 92 86 if err != nil { ··· 322 316 Host: host, 323 317 } 324 318 325 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 326 - xrpcBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, repo) 319 + xrpcBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, f.RepoIdentifier()) 327 320 if err != nil { 328 321 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 329 322 l.Error("failed to call XRPC repo.tags", "err", xrpcerr) ··· 358 351 359 352 return tag, nil 360 353 } 354 + 355 + func repoArtifactRecord(f *models.Repo, blob *lexutil.LexBlob, createdAt time.Time, name string, tag []byte) *tangled.RepoArtifact { 356 + rec := &tangled.RepoArtifact{ 357 + Artifact: blob, 358 + CreatedAt: createdAt.Format(time.RFC3339), 359 + Name: name, 360 + Tag: tag, 361 + } 362 + if f.RepoDid != "" { 363 + rec.RepoDid = &f.RepoDid 364 + } else { 365 + s := f.RepoAt().String() 366 + rec.Repo = &s 367 + } 368 + return rec 369 + }
+3 -4
appview/repo/blob.go
··· 58 58 xrpcc := &indigoxrpc.Client{ 59 59 Host: host, 60 60 } 61 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 62 - resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo) 61 + resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, f.RepoIdentifier()) 63 62 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 64 63 l.Error("failed to call XRPC repo.blob", "err", xrpcerr) 65 64 rp.pages.Error503(w) ··· 139 138 if !rp.config.Core.Dev { 140 139 scheme = "https" 141 140 } 142 - repo := f.DidSlashRepo() 141 + repo := f.RepoIdentifier() 143 142 baseURL := &url.URL{ 144 143 Scheme: scheme, 145 144 Host: f.Knot, ··· 290 289 scheme = "https" 291 290 } 292 291 293 - repoName := fmt.Sprintf("%s/%s", repo.Did, repo.Name) 292 + repoName := repo.RepoIdentifier() 294 293 baseURL := &url.URL{ 295 294 Scheme: scheme, 296 295 Host: repo.Knot,
+1 -2
appview/repo/branches.go
··· 29 29 xrpcc := &indigoxrpc.Client{ 30 30 Host: host, 31 31 } 32 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 33 - xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 32 + xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier()) 34 33 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 35 34 l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 36 35 rp.pages.Error503(w)
+7 -7
appview/repo/compare.go
··· 36 36 Host: host, 37 37 } 38 38 39 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 40 - branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 39 + repoId := f.RepoIdentifier() 40 + branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repoId) 41 41 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 42 42 l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 43 43 rp.pages.Error503(w) ··· 74 74 head = queryHead 75 75 } 76 76 77 - tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 77 + tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repoId) 78 78 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 79 79 l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 80 80 rp.pages.Error503(w) ··· 149 149 Host: host, 150 150 } 151 151 152 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 152 + repoId := f.RepoIdentifier() 153 153 154 - branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 154 + branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repoId) 155 155 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 156 156 l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 157 157 rp.pages.Error503(w) ··· 165 165 return 166 166 } 167 167 168 - tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 168 + tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repoId) 169 169 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 170 170 l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 171 171 rp.pages.Error503(w) ··· 179 179 return 180 180 } 181 181 182 - compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head) 182 + compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repoId, base, head) 183 183 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 184 184 l.Error("failed to call XRPC repo.compare", "err", xrpcerr) 185 185 rp.pages.Error503(w)
+6 -8
appview/repo/index.go
··· 182 182 183 183 if err != nil || langs == nil { 184 184 // non-fatal, fetch langs from ks via XRPC 185 - didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name) 186 - ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, didSlashRepo) 185 + ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, repo.RepoIdentifier()) 187 186 if err != nil { 188 187 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 189 188 l.Error("failed to call XRPC repo.languages", "err", xrpcerr) ··· 259 258 260 259 // buildIndexResponse creates a RepoIndexResponse by combining multiple xrpc calls in parallel 261 260 func (rp *Repo) buildIndexResponse(ctx context.Context, xrpcc *indigoxrpc.Client, repo *models.Repo, ref string) (*types.RepoIndexResponse, error) { 262 - didSlashRepo := fmt.Sprintf("%s/%s", repo.Did, repo.Name) 261 + repoId := repo.RepoIdentifier() 263 262 264 - // first get branches to determine the ref if not specified 265 - branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, didSlashRepo) 263 + branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, repoId) 266 264 if err != nil { 267 265 return nil, fmt.Errorf("failed to call repoBranches: %w", err) 268 266 } ··· 304 302 305 303 // tags 306 304 wg.Go(func() { 307 - tagsBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, didSlashRepo) 305 + tagsBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, repoId) 308 306 if err != nil { 309 307 errs = errors.Join(errs, fmt.Errorf("failed to call repoTags: %w", err)) 310 308 return ··· 317 315 318 316 // tree/files 319 317 wg.Go(func() { 320 - resp, err := tangled.RepoTree(ctx, xrpcc, "", ref, didSlashRepo) 318 + resp, err := tangled.RepoTree(ctx, xrpcc, "", ref, repoId) 321 319 if err != nil { 322 320 errs = errors.Join(errs, fmt.Errorf("failed to call repoTree: %w", err)) 323 321 return ··· 327 325 328 326 // commits 329 327 wg.Go(func() { 330 - logBytes, err := tangled.RepoLog(ctx, xrpcc, "", 50, "", ref, didSlashRepo) 328 + logBytes, err := tangled.RepoLog(ctx, xrpcc, "", 50, "", ref, repoId) 331 329 if err != nil { 332 330 errs = errors.Join(errs, fmt.Errorf("failed to call repoLog: %w", err)) 333 331 return
+5 -6
appview/repo/log.go
··· 57 57 cursor = strconv.Itoa(offset) 58 58 } 59 59 60 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 61 - xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo) 60 + xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, f.RepoIdentifier()) 62 61 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 63 62 l.Error("failed to call XRPC repo.log", "err", xrpcerr) 64 63 rp.pages.Error503(w) ··· 72 71 return 73 72 } 74 73 75 - tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 74 + repoId := f.RepoIdentifier() 75 + tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repoId) 76 76 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 77 77 l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 78 78 rp.pages.Error503(w) ··· 93 93 } 94 94 } 95 95 96 - branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 96 + branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repoId) 97 97 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 98 98 l.Error("failed to call XRPC repo.branches", "err", xrpcerr) 99 99 rp.pages.Error503(w) ··· 172 172 Host: host, 173 173 } 174 174 175 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 176 - xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo) 175 + xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, f.RepoIdentifier()) 177 176 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 178 177 l.Error("failed to call XRPC repo.diff", "err", xrpcerr) 179 178 rp.pages.Error503(w)
+117 -55
appview/repo/repo.go
··· 35 35 atpclient "github.com/bluesky-social/indigo/atproto/client" 36 36 "github.com/bluesky-social/indigo/atproto/syntax" 37 37 lexutil "github.com/bluesky-social/indigo/lex/util" 38 - securejoin "github.com/cyphar/filepath-securejoin" 38 + 39 39 "github.com/go-chi/chi/v5" 40 40 ) 41 41 ··· 315 315 return 316 316 } 317 317 318 - err = db.SubscribeLabel(tx, &models.RepoLabel{ 318 + if err = db.SubscribeLabel(tx, &models.RepoLabel{ 319 319 RepoAt: f.RepoAt(), 320 320 LabelAt: label.AtUri(), 321 - }) 321 + }); err != nil { 322 + fail("Failed to subscribe to label.", err) 323 + return 324 + } 322 325 323 326 err = tx.Commit() 324 327 if err != nil { ··· 752 755 Repo: currentUser.Active.Did, 753 756 Rkey: rkey, 754 757 Record: &lexutil.LexiconTypeDecoder{ 755 - Val: &tangled.RepoCollaborator{ 756 - Subject: collaboratorIdent.DID.String(), 757 - Repo: string(f.RepoAt()), 758 - CreatedAt: createdAt.Format(time.RFC3339), 759 - }}, 758 + Val: repoCollaboratorRecord(f, collaboratorIdent.DID.String(), createdAt), 759 + }, 760 760 }) 761 761 // invalid record 762 762 if err != nil { ··· 791 791 } 792 792 defer rollback() 793 793 794 - err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.DidSlashRepo()) 794 + err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.RepoIdentifier()) 795 795 if err != nil { 796 796 fail("Failed to add collaborator permissions.", err) 797 797 return ··· 897 897 }() 898 898 899 899 // remove collaborator RBAC 900 - repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(f.DidSlashRepo(), f.Knot) 900 + repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(f.RepoIdentifier(), f.Knot) 901 901 if err != nil { 902 902 rp.pages.Notice(w, noticeId, "Failed to remove collaborators") 903 903 return 904 904 } 905 905 for _, c := range repoCollaborators { 906 906 did := c[0] 907 - rp.enforcer.RemoveCollaborator(did, f.Knot, f.DidSlashRepo()) 907 + rp.enforcer.RemoveCollaborator(did, f.Knot, f.RepoIdentifier()) 908 908 } 909 909 l.Info("removed collaborators") 910 910 911 911 // remove repo RBAC 912 - err = rp.enforcer.RemoveRepo(f.Did, f.Knot, f.DidSlashRepo()) 912 + err = rp.enforcer.RemoveRepo(f.Did, f.Knot, f.RepoIdentifier()) 913 913 if err != nil { 914 914 rp.pages.Notice(w, noticeId, "Failed to update RBAC rules") 915 915 return ··· 1064 1064 uri = "http" 1065 1065 } 1066 1066 1067 - forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.Did, f.Name) 1067 + forkSourceUrl := fmt.Sprintf("%s://%s/%s", uri, f.Knot, f.RepoIdentifier()) 1068 1068 l = l.With("cloneUrl", forkSourceUrl) 1069 1069 1070 - sourceAt := f.RepoAt().String() 1071 - 1072 - // create an atproto record for this fork 1073 1070 rkey := tid.TID() 1071 + 1072 + // TODO: this could coordinate better with the knot to recieve a clone status 1073 + client, err := rp.oauth.ServiceClient( 1074 + r, 1075 + oauth.WithService(targetKnot), 1076 + oauth.WithLxm(tangled.RepoCreateNSID), 1077 + oauth.WithDev(rp.config.Core.Dev), 1078 + oauth.WithTimeout(time.Second*20), 1079 + ) 1080 + if err != nil { 1081 + l.Error("could not create service client", "err", err) 1082 + rp.pages.Notice(w, "repo", "Failed to connect to knot server.") 1083 + return 1084 + } 1085 + 1086 + forkInput := &tangled.RepoCreate_Input{ 1087 + Rkey: rkey, 1088 + Name: forkName, 1089 + Source: &forkSourceUrl, 1090 + } 1091 + createResp, createErr := tangled.RepoCreate( 1092 + r.Context(), 1093 + client, 1094 + forkInput, 1095 + ) 1096 + if err := xrpcclient.HandleXrpcErr(createErr); err != nil { 1097 + rp.pages.Notice(w, "repo", err.Error()) 1098 + return 1099 + } 1100 + 1101 + var repoDid string 1102 + if createResp != nil && createResp.RepoDid != nil { 1103 + repoDid = *createResp.RepoDid 1104 + } 1105 + if repoDid == "" { 1106 + l.Error("knot returned empty repo DID for fork") 1107 + rp.pages.Notice(w, "repo", "Knot failed to mint a repo DID. The knot may need to be upgraded.") 1108 + return 1109 + } 1110 + 1111 + forkSource := f.RepoAt().String() 1112 + if f.RepoDid != "" { 1113 + forkSource = f.RepoDid 1114 + } 1115 + 1074 1116 repo := &models.Repo{ 1075 1117 Did: user.Active.Did, 1076 1118 Name: forkName, 1077 1119 Knot: targetKnot, 1078 1120 Rkey: rkey, 1079 - Source: sourceAt, 1121 + Source: forkSource, 1080 1122 Description: f.Description, 1081 1123 Created: time.Now(), 1082 1124 Labels: rp.config.Label.DefaultLabelDefs, 1125 + RepoDid: repoDid, 1083 1126 } 1084 1127 record := repo.AsRecord() 1085 1128 1129 + cleanupKnot := func() { 1130 + go func() { 1131 + delays := []time.Duration{0, 2 * time.Second, 5 * time.Second} 1132 + for attempt, delay := range delays { 1133 + time.Sleep(delay) 1134 + deleteClient, dErr := rp.oauth.ServiceClient( 1135 + r, 1136 + oauth.WithService(targetKnot), 1137 + oauth.WithLxm(tangled.RepoDeleteNSID), 1138 + oauth.WithDev(rp.config.Core.Dev), 1139 + ) 1140 + if dErr != nil { 1141 + l.Error("failed to create delete client for knot cleanup", "attempt", attempt+1, "err", dErr) 1142 + continue 1143 + } 1144 + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 1145 + if dErr := tangled.RepoDelete(ctx, deleteClient, &tangled.RepoDelete_Input{ 1146 + Did: user.Active.Did, 1147 + Name: forkName, 1148 + Rkey: rkey, 1149 + }); dErr != nil { 1150 + cancel() 1151 + l.Error("failed to clean up fork on knot after rollback", "attempt", attempt+1, "err", dErr) 1152 + continue 1153 + } 1154 + cancel() 1155 + l.Info("successfully cleaned up fork on knot after rollback", "attempt", attempt+1) 1156 + return 1157 + } 1158 + l.Error("exhausted retries for knot cleanup, fork may be orphaned", 1159 + "did", user.Active.Did, "fork", forkName, "knot", targetKnot) 1160 + }() 1161 + } 1162 + 1086 1163 atpClient, err := rp.oauth.AuthorizedClient(r) 1087 1164 if err != nil { 1088 1165 l.Error("failed to create xrpcclient", "err", err) 1166 + cleanupKnot() 1089 1167 rp.pages.Notice(w, "repo", "Failed to fork repository.") 1090 1168 return 1091 1169 } ··· 1100 1178 }) 1101 1179 if err != nil { 1102 1180 l.Error("failed to write to PDS", "err", err) 1181 + cleanupKnot() 1103 1182 rp.pages.Notice(w, "repo", "Failed to announce repository creation.") 1104 1183 return 1105 1184 } ··· 1115 1194 return 1116 1195 } 1117 1196 1118 - // The rollback function reverts a few things on failure: 1119 - // - the pending txn 1120 - // - the ACLs 1121 - // - the atproto record created 1122 1197 rollback := func() { 1123 1198 err1 := tx.Rollback() 1124 1199 err2 := rp.enforcer.E.LoadPolicy() 1125 1200 err3 := rollbackRecord(context.Background(), aturi, atpClient) 1126 1201 1127 - // ignore txn complete errors, this is okay 1128 1202 if errors.Is(err1, sql.ErrTxDone) { 1129 1203 err1 = nil 1130 1204 } 1131 1205 1132 1206 if errs := errors.Join(err1, err2, err3); errs != nil { 1133 1207 l.Error("failed to rollback changes", "errs", errs) 1134 - return 1135 1208 } 1136 - } 1137 - defer rollback() 1138 1209 1139 - // TODO: this could coordinate better with the knot to recieve a clone status 1140 - client, err := rp.oauth.ServiceClient( 1141 - r, 1142 - oauth.WithService(targetKnot), 1143 - oauth.WithLxm(tangled.RepoCreateNSID), 1144 - oauth.WithDev(rp.config.Core.Dev), 1145 - oauth.WithTimeout(time.Second*20), // big repos take time to clone 1146 - ) 1147 - if err != nil { 1148 - l.Error("could not create service client", "err", err) 1149 - rp.pages.Notice(w, "repo", "Failed to connect to knot server.") 1150 - return 1151 - } 1152 - 1153 - err = tangled.RepoCreate( 1154 - r.Context(), 1155 - client, 1156 - &tangled.RepoCreate_Input{ 1157 - Rkey: rkey, 1158 - Source: &forkSourceUrl, 1159 - }, 1160 - ) 1161 - if err := xrpcclient.HandleXrpcErr(err); err != nil { 1162 - rp.pages.Notice(w, "repo", err.Error()) 1163 - return 1210 + if aturi != "" { 1211 + cleanupKnot() 1212 + } 1164 1213 } 1214 + defer rollback() 1165 1215 1166 1216 err = db.AddRepo(tx, repo) 1167 1217 if err != nil { ··· 1170 1220 return 1171 1221 } 1172 1222 1173 - // acls 1174 - p, _ := securejoin.SecureJoin(user.Active.Did, forkName) 1175 - err = rp.enforcer.AddRepo(user.Active.Did, targetKnot, p) 1223 + rbacPath := repo.RepoIdentifier() 1224 + err = rp.enforcer.AddRepo(user.Active.Did, targetKnot, rbacPath) 1176 1225 if err != nil { 1177 1226 l.Error("failed to add ACLs", "err", err) 1178 1227 rp.pages.Notice(w, "repo", "Failed to set up repository permissions.") ··· 1193 1242 return 1194 1243 } 1195 1244 1196 - // reset the ATURI because the transaction completed successfully 1197 1245 aturi = "" 1198 1246 1199 1247 rp.notifier.NewRepo(r.Context(), repo) 1200 - rp.pages.HxLocation(w, fmt.Sprintf("/%s/%s", user.Active.Did, forkName)) 1248 + if repoDid != "" { 1249 + rp.pages.HxLocation(w, fmt.Sprintf("/%s", repoDid)) 1250 + } else { 1251 + rp.pages.HxLocation(w, fmt.Sprintf("/%s/%s", user.Active.Did, forkName)) 1252 + } 1201 1253 } 1202 1254 } 1203 1255 ··· 1222 1274 }) 1223 1275 return err 1224 1276 } 1277 + 1278 + func repoCollaboratorRecord(f *models.Repo, subject string, createdAt time.Time) *tangled.RepoCollaborator { 1279 + rec := &tangled.RepoCollaborator{ 1280 + Subject: subject, 1281 + CreatedAt: createdAt.Format(time.RFC3339), 1282 + } 1283 + s := string(f.RepoAt()) 1284 + rec.Repo = &s 1285 + return rec 1286 + }
+8 -9
appview/repo/settings.go
··· 293 293 // Skip entirely if there is no active domain claim — the site cannot be served anyway. 294 294 ownerClaim, _ := db.GetActiveDomainClaimForDid(rp.db, f.Did) 295 295 if ownerClaim == nil { 296 - rp.logger.Info("skipping deploy: no active domain claim", "repo", f.DidSlashRepo()) 296 + rp.logger.Info("skipping deploy: no active domain claim", "repo", f.RepoIdentifier()) 297 297 } else if rp.cfClient.Enabled() { 298 298 scheme := "http" 299 299 if !rp.config.Core.Dev { ··· 313 313 314 314 deployErr := sites.Deploy(ctx, rp.cfClient, knotHost, f.Did, f.Name, branch, dir) 315 315 if deployErr != nil { 316 - l.Error("sites: initial R2 sync failed", "repo", f.DidSlashRepo(), "err", deployErr) 316 + l.Error("sites: initial R2 sync failed", "repo", f.RepoIdentifier(), "err", deployErr) 317 317 deploy.Status = models.SiteDeployStatusFailure 318 318 deploy.Error = deployErr.Error() 319 319 } else { ··· 321 321 } 322 322 323 323 if err := db.AddSiteDeploy(rp.db, deploy); err != nil { 324 - l.Error("sites: failed to record deploy", "repo", f.DidSlashRepo(), "err", err) 324 + l.Error("sites: failed to record deploy", "repo", f.RepoIdentifier(), "err", err) 325 325 } 326 326 327 327 if deployErr == nil { 328 328 if err := sites.PutDomainMapping(ctx, rp.cfClient, ownerClaim.Domain, f.Did, f.Name, isIndex); err != nil { 329 329 l.Error("sites: KV write failed", "domain", ownerClaim.Domain, "err", err) 330 330 } 331 - rp.logger.Info("site deployed to r2", "repo", f.DidSlashRepo(), "is_index", isIndex) 331 + rp.logger.Info("site deployed to r2", "repo", f.RepoIdentifier(), "is_index", isIndex) 332 332 } 333 333 }() 334 334 } else { 335 - rp.logger.Warn("cloudflare integration is disabled; site won't be deployed", "repo", f.DidSlashRepo()) 335 + rp.logger.Warn("cloudflare integration is disabled; site won't be deployed", "repo", f.RepoIdentifier()) 336 336 } 337 337 338 338 rp.pages.HxRefresh(w) ··· 367 367 go func() { 368 368 ctx := context.Background() 369 369 if err := sites.Delete(ctx, rp.cfClient, f.Did, f.Name); err != nil { 370 - l.Error("sites: R2 delete failed", "repo", f.DidSlashRepo(), "err", err) 370 + l.Error("sites: R2 delete failed", "repo", f.RepoIdentifier(), "err", err) 371 371 } 372 372 if ownerClaim != nil { 373 373 if err := sites.DeleteDomainMapping(ctx, rp.cfClient, ownerClaim.Domain, f.Name); err != nil { ··· 395 395 Host: host, 396 396 } 397 397 398 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 399 - xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) 398 + xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, f.RepoIdentifier()) 400 399 var result types.RepoBranchesResponse 401 400 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 402 401 l.Error("failed to call XRPC repo.branches", "err", xrpcerr) ··· 467 466 user := rp.oauth.GetMultiAccountUser(r) 468 467 469 468 collaborators, err := func(repo *models.Repo) ([]pages.Collaborator, error) { 470 - repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.DidSlashRepo(), repo.Knot) 469 + repoCollaborators, err := rp.enforcer.E.GetImplicitUsersForResourceByDomain(repo.RepoIdentifier(), repo.Knot) 471 470 if err != nil { 472 471 return nil, err 473 472 }
+3 -5
appview/repo/tags.go
··· 35 35 xrpcc := &indigoxrpc.Client{ 36 36 Host: host, 37 37 } 38 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 39 - xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) 38 + xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, f.RepoIdentifier()) 40 39 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 41 40 l.Error("failed to call XRPC repo.tags", "err", xrpcerr) 42 41 rp.pages.Error503(w) ··· 98 97 xrpcc := &indigoxrpc.Client{ 99 98 Host: host, 100 99 } 101 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 102 100 tag := chi.URLParam(r, "tag") 103 101 104 - xrpcBytes, err := tangled.RepoTag(r.Context(), xrpcc, repo, tag) 102 + xrpcBytes, err := tangled.RepoTag(r.Context(), xrpcc, f.RepoIdentifier(), tag) 105 103 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 106 104 // if we don't match an existing tag, and the tag we're trying 107 105 // to match is "latest", resolve to the most recent tag 108 106 if tag == "latest" { 109 - tagsBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 1, repo) 107 + tagsBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 1, f.RepoIdentifier()) 110 108 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 111 109 l.Error("failed to call XRPC repo.tags for latest", "err", xrpcerr) 112 110 rp.pages.Error503(w)
+1 -2
appview/repo/tree.go
··· 41 41 xrpcc := &indigoxrpc.Client{ 42 42 Host: host, 43 43 } 44 - repo := fmt.Sprintf("%s/%s", f.Did, f.Name) 45 - xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo) 44 + xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, f.RepoIdentifier()) 46 45 if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { 47 46 l.Error("failed to call XRPC repo.tree", "err", xrpcerr) 48 47 rp.pages.Error503(w)
+1 -1
appview/strings/strings.go
··· 149 149 showRendered = r.URL.Query().Get("code") != "true" 150 150 } 151 151 152 - starCount, err := db.GetStarCount(s.Db, "", string.AtUri()) 152 + starCount, err := db.GetStarCount(s.Db, string.AtUri()) 153 153 if err != nil { 154 154 l.Error("failed to get star count", "err", err) 155 155 }

History

14 rounds 2 comments
sign up or login to add to the discussion
1 commit
expand
appview: DID-based routing, state/handler/middleware updates
merge conflicts detected
expand
  • appview/db/repos.go:46
expand 0 comments
1 commit
expand
appview: DID-based routing, state/handler/middleware updates
expand 0 comments
1 commit
expand
appview: DID-based routing, state/handler/middleware updates
expand 2 comments

appview/state/state.go:631 won't this eventually redirect to /{owner}/{reponame}?

wdym by eventually? I was thinking to keep this in, so that we don't simply error out if someone does decide to be clever and link to their git repo by repoDID, we should render the page anyway to reward them for being clever instead of punishing heh

1 commit
expand
appview: DID-based routing, state/handler/middleware updates
expand 0 comments
1 commit
expand
appview: DID-based routing, state/handler/middleware updates
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments
1 commit
expand
appview: update state, ingester, middleware, and resolver for repo DID
expand 0 comments