From 7b60cbfcffca17377b3cf0504676801c21e21a23 Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Fri, 14 Nov 2025 18:15:29 +0000 Subject: [PATCH] appview: use less `OwnerSlashRepo()` in handlers Signed-off-by: Seongmin Lee --- appview/issues/issues.go | 13 +++++++++---- appview/middleware/middleware.go | 4 ++-- appview/pages/repoinfo/repoinfo.go | 4 ++-- appview/pulls/pulls.go | 40 ++++++++++++++++++++++++---------------- appview/repo/archive.go | 4 ++-- appview/repo/artifact.go | 11 +++++++++-- appview/repo/blob.go | 10 ++++++---- appview/repo/branches.go | 2 +- appview/repo/compare.go | 4 ++-- appview/repo/feed.go | 40 +++++++++++++++++++++++----------------- appview/repo/index.go | 4 ++-- appview/repo/log.go | 4 ++-- appview/repo/repo.go | 10 +++++----- appview/repo/settings.go | 4 ++-- appview/repo/tags.go | 2 +- appview/repo/tree.go | 8 +++++--- appview/reporesolver/resolver.go | 40 +++++++++++++++------------------------- 17 file(s) changed, 112 insertion(s)(+), 92 deletion(s)(-) diff --git a/appview/issues/issues.go b/appview/issues/issues.go --- a/appview/issues/issues.go +++ b/appview/issues/issues.go @@ -312,7 +312,8 @@ // notify about the issue closure rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue) - rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId)) return } else { l.Error("user is not permitted to close issue") @@ -362,7 +363,8 @@ // notify about the issue reopen rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue) - rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId)) return } else { l.Error("user is not the owner of the repo") @@ -466,7 +468,8 @@ } } rp.notifier.NewIssueComment(r.Context(), &comment, mentions) - rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), issue.IssueId, commentId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", ownerSlashRepo, issue.IssueId, commentId)) } func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) { @@ -988,7 +991,9 @@ mentions = append(mentions, ident.DID) } } rp.notifier.NewIssue(r.Context(), issue, mentions) - rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId)) + + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId)) return } } diff --git a/appview/middleware/middleware.go b/appview/middleware/middleware.go --- a/appview/middleware/middleware.go +++ b/appview/middleware/middleware.go @@ -164,7 +164,7 @@ ok, err := mw.enforcer.E.Enforce(actor.Did, f.Knot, f.DidSlashRepo(), requiredPerm) if err != nil || !ok { // we need a logged in user - log.Printf("%s does not have perms of a %s in repo %s", actor.Did, requiredPerm, f.OwnerSlashRepo()) + log.Printf("%s does not have perms of a %s in repo %s", actor.Did, requiredPerm, f.DidSlashRepo()) http.Error(w, "Forbiden", http.StatusUnauthorized) return } @@ -327,7 +327,7 @@ mw.pages.ErrorKnot404(w) return } - fullName := f.OwnerHandle() + "/" + f.Name + fullName := reporesolver.GetBaseRepoPath(r, &f.Repo) if r.Header.Get("User-Agent") == "Go-http-client/1.1" { if r.URL.Query().Get("go-get") == "1" { diff --git a/appview/pages/repoinfo/repoinfo.go b/appview/pages/repoinfo/repoinfo.go --- a/appview/pages/repoinfo/repoinfo.go +++ b/appview/pages/repoinfo/repoinfo.go @@ -21,7 +21,7 @@ func (r RepoInfo) FullName() string { return path.Join(r.owner(), r.Name) } -func (r RepoInfo) OwnerWithoutAt() string { +func (r RepoInfo) ownerWithoutAt() string { if r.OwnerHandle != "" { return r.OwnerHandle } else { @@ -30,7 +30,7 @@ } } func (r RepoInfo) FullNameWithoutAt() string { - return path.Join(r.OwnerWithoutAt(), r.Name) + return path.Join(r.ownerWithoutAt(), r.Name) } func (r RepoInfo) GetTabs() [][]string { diff --git a/appview/pulls/pulls.go b/appview/pulls/pulls.go --- a/appview/pulls/pulls.go +++ b/appview/pulls/pulls.go @@ -268,7 +268,7 @@ resp, xe := tangled.RepoMergeCheck( r.Context(), &xrpcc, &tangled.RepoMergeCheck_Input{ - Did: f.OwnerDid(), + Did: f.Did, Name: f.Name, Branch: pull.TargetBranch, Patch: patch, @@ -382,7 +382,7 @@ repoName = sourceRepo.Name } else { // pulls within the same repo knot = f.Knot - ownerDid = f.OwnerDid() + ownerDid = f.Did repoName = f.Name } @@ -802,7 +802,8 @@ } } s.notifier.NewPullComment(r.Context(), comment, mentions) - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", f.OwnerSlashRepo(), pull.PullId, commentId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", ownerSlashRepo, pull.PullId, commentId)) return } } @@ -826,7 +827,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { @@ -991,7 +992,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, targetBranch, sourceBranch) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { @@ -1273,7 +1274,8 @@ } s.notifier.NewPull(r.Context(), pull) - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pullId)) } func (s *Pulls) createStackedPullRequest( @@ -1374,7 +1376,8 @@ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.") return } - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls", f.OwnerSlashRepo())) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls", ownerSlashRepo)) } func (s *Pulls) ValidatePatch(w http.ResponseWriter, r *http.Request) { @@ -1433,7 +1436,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { @@ -1554,7 +1557,7 @@ targetXrpcc := &indigoxrpc.Client{ Host: targetHost, } - targetRepo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + targetRepo := fmt.Sprintf("%s/%s", f.Did, f.Name) targetXrpcBytes, err := tangled.RepoBranches(r.Context(), targetXrpcc, "", 0, targetRepo) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { @@ -1685,7 +1688,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, pull.TargetBranch, pull.PullSource.Branch) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { @@ -1922,7 +1925,8 @@ s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull.") return } - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) } func (s *Pulls) resubmitStackedPullHelper( @@ -2115,7 +2119,8 @@ s.pages.Notice(w, "pull", "Failed to create stacked pull request. Try again later.") return } - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) } func (s *Pulls) MergePull(w http.ResponseWriter, r *http.Request) { @@ -2168,7 +2173,7 @@ } authorName := ident.Handle.String() mergeInput := &tangled.RepoMerge_Input{ - Did: f.OwnerDid(), + Did: f.Did, Name: f.Name, Branch: pull.TargetBranch, Patch: patch, @@ -2233,7 +2238,8 @@ for _, p := range pullsToMerge { s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p) } - s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s/pulls/%d", f.OwnerHandle(), f.Name, pull.PullId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) } func (s *Pulls) ClosePull(w http.ResponseWriter, r *http.Request) { @@ -2305,7 +2311,8 @@ for _, p := range pullsToClose { s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p) } - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) } func (s *Pulls) ReopenPull(w http.ResponseWriter, r *http.Request) { @@ -2378,7 +2385,8 @@ for _, p := range pullsToReopen { s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p) } - s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId)) + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) } func newStack(f *reporesolver.ResolvedRepo, user *oauth.User, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) { diff --git a/appview/repo/archive.go b/appview/repo/archive.go --- a/appview/repo/archive.go +++ b/appview/repo/archive.go @@ -31,8 +31,8 @@ host := fmt.Sprintf("%s://%s", scheme, f.Knot) xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) - archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo) + didSlashRepo := f.DidSlashRepo() + archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, didSlashRepo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.archive", "err", xrpcerr) rp.pages.Error503(w) diff --git a/appview/repo/artifact.go b/appview/repo/artifact.go --- a/appview/repo/artifact.go +++ b/appview/repo/artifact.go @@ -174,7 +174,14 @@ } artifact := artifacts[0] - ownerPds := f.OwnerId.PDSEndpoint() + ownerId, err := rp.idResolver.ResolveIdent(r.Context(), f.Did) + if err != nil { + log.Println("failed to resolve repo owner did", f.Did, err) + http.Error(w, "repository owner not found", http.StatusNotFound) + return + } + + ownerPds := ownerId.PDSEndpoint() url, _ := url.Parse(fmt.Sprintf("%s/xrpc/com.atproto.sync.getBlob", ownerPds)) q := url.Query() q.Set("cid", artifact.BlobCid.String()) @@ -305,7 +312,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoTags(ctx, xrpcc, "", 0, repo) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { diff --git a/appview/repo/blob.go b/appview/repo/blob.go --- a/appview/repo/blob.go +++ b/appview/repo/blob.go @@ -54,7 +54,7 @@ host := fmt.Sprintf("%s://%s", scheme, f.Knot) xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Repo.Name) resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.blob", "err", xrpcerr) @@ -62,9 +62,11 @@ rp.pages.Error503(w) return } + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) + // Use XRPC response directly instead of converting to internal types var breadcrumbs [][]string - breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), url.PathEscape(ref))}) + breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", ownerSlashRepo, url.PathEscape(ref))}) if filePath != "" { for idx, elem := range strings.Split(filePath, "/") { breadcrumbs = append(breadcrumbs, []string{elem, fmt.Sprintf("%s/%s", breadcrumbs[idx][1], url.PathEscape(elem))}) @@ -105,7 +107,7 @@ scheme := "http" if !rp.config.Core.Dev { scheme = "https" } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Repo.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Repo.Name) baseURL := &url.URL{ Scheme: scheme, Host: f.Knot, @@ -256,7 +258,7 @@ if !config.Core.Dev { scheme = "https" } - repoName := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repoName := fmt.Sprintf("%s/%s", f.Did, f.Name) baseURL := &url.URL{ Scheme: scheme, Host: f.Knot, diff --git a/appview/repo/branches.go b/appview/repo/branches.go --- a/appview/repo/branches.go +++ b/appview/repo/branches.go @@ -29,7 +29,7 @@ host := fmt.Sprintf("%s://%s", scheme, f.Knot) xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.branches", "err", xrpcerr) diff --git a/appview/repo/compare.go b/appview/repo/compare.go --- a/appview/repo/compare.go +++ b/appview/repo/compare.go @@ -36,7 +36,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.branches", "err", xrpcerr) @@ -151,7 +151,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { diff --git a/appview/repo/feed.go b/appview/repo/feed.go --- a/appview/repo/feed.go +++ b/appview/repo/feed.go @@ -11,16 +11,16 @@ "tangled.org/core/appview/db" "tangled.org/core/appview/models" "tangled.org/core/appview/pagination" - "tangled.org/core/appview/reporesolver" + "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/gorilla/feeds" ) -func (rp *Repo) getRepoFeed(ctx context.Context, f *reporesolver.ResolvedRepo) (*feeds.Feed, error) { +func (rp *Repo) getRepoFeed(ctx context.Context, repo *models.Repo, ownerSlashRepo string) (*feeds.Feed, error) { const feedLimitPerType = 100 - pulls, err := db.GetPullsWithLimit(rp.db, feedLimitPerType, db.FilterEq("repo_at", f.RepoAt())) + pulls, err := db.GetPullsWithLimit(rp.db, feedLimitPerType, db.FilterEq("repo_at", repo.RepoAt())) if err != nil { return nil, err } @@ -28,21 +28,21 @@ issues, err := db.GetIssuesPaginated( rp.db, pagination.Page{Limit: feedLimitPerType}, - db.FilterEq("repo_at", f.RepoAt()), + db.FilterEq("repo_at", repo.RepoAt()), ) if err != nil { return nil, err } feed := &feeds.Feed{ - Title: fmt.Sprintf("activity feed for %s", f.OwnerSlashRepo()), - Link: &feeds.Link{Href: fmt.Sprintf("%s/%s", rp.config.Core.AppviewHost, f.OwnerSlashRepo()), Type: "text/html", Rel: "alternate"}, + Title: fmt.Sprintf("activity feed for @%s", ownerSlashRepo), + Link: &feeds.Link{Href: fmt.Sprintf("%s/%s", rp.config.Core.AppviewHost, ownerSlashRepo), Type: "text/html", Rel: "alternate"}, Items: make([]*feeds.Item, 0), Updated: time.UnixMilli(0), } for _, pull := range pulls { - items, err := rp.createPullItems(ctx, pull, f) + items, err := rp.createPullItems(ctx, pull, repo, ownerSlashRepo) if err != nil { return nil, err } @@ -50,7 +50,7 @@ feed.Items = append(feed.Items, items...) } for _, issue := range issues { - item, err := rp.createIssueItem(ctx, issue, f) + item, err := rp.createIssueItem(ctx, issue, repo, ownerSlashRepo) if err != nil { return nil, err } @@ -71,7 +71,7 @@ return feed, nil } -func (rp *Repo) createPullItems(ctx context.Context, pull *models.Pull, f *reporesolver.ResolvedRepo) ([]*feeds.Item, error) { +func (rp *Repo) createPullItems(ctx context.Context, pull *models.Pull, repo *models.Repo, ownerSlashRepo string) ([]*feeds.Item, error) { owner, err := rp.idResolver.ResolveIdent(ctx, pull.OwnerDid) if err != nil { return nil, err @@ -80,12 +80,12 @@ var items []*feeds.Item state := rp.getPullState(pull) - description := rp.buildPullDescription(owner.Handle, state, pull, f.OwnerSlashRepo()) + description := rp.buildPullDescription(owner.Handle, state, pull, ownerSlashRepo) mainItem := &feeds.Item{ Title: fmt.Sprintf("[PR #%d] %s", pull.PullId, pull.Title), Description: description, - Link: &feeds.Link{Href: fmt.Sprintf("%s/%s/pulls/%d", rp.config.Core.AppviewHost, f.OwnerSlashRepo(), pull.PullId)}, + Link: &feeds.Link{Href: fmt.Sprintf("%s/%s/pulls/%d", rp.config.Core.AppviewHost, ownerSlashRepo, pull.PullId)}, Created: pull.Created, Author: &feeds.Author{Name: fmt.Sprintf("@%s", owner.Handle)}, } @@ -98,8 +98,8 @@ } roundItem := &feeds.Item{ Title: fmt.Sprintf("[PR #%d] %s (round #%d)", pull.PullId, pull.Title, round.RoundNumber), - Description: fmt.Sprintf("@%s submitted changes (at round #%d) on PR #%d in %s", owner.Handle, round.RoundNumber, pull.PullId, f.OwnerSlashRepo()), - Link: &feeds.Link{Href: fmt.Sprintf("%s/%s/pulls/%d/round/%d/", rp.config.Core.AppviewHost, f.OwnerSlashRepo(), pull.PullId, round.RoundNumber)}, + Description: fmt.Sprintf("@%s submitted changes (at round #%d) on PR #%d in @%s", owner.Handle, round.RoundNumber, pull.PullId, ownerSlashRepo), + Link: &feeds.Link{Href: fmt.Sprintf("%s/%s/pulls/%d/round/%d/", rp.config.Core.AppviewHost, ownerSlashRepo, pull.PullId, round.RoundNumber)}, Created: round.Created, Author: &feeds.Author{Name: fmt.Sprintf("@%s", owner.Handle)}, } @@ -109,7 +109,7 @@ return items, nil } -func (rp *Repo) createIssueItem(ctx context.Context, issue models.Issue, f *reporesolver.ResolvedRepo) (*feeds.Item, error) { +func (rp *Repo) createIssueItem(ctx context.Context, issue models.Issue, repo *models.Repo, ownerSlashRepo string) (*feeds.Item, error) { owner, err := rp.idResolver.ResolveIdent(ctx, issue.Did) if err != nil { return nil, err @@ -122,8 +122,8 @@ } return &feeds.Item{ Title: fmt.Sprintf("[Issue #%d] %s", issue.IssueId, issue.Title), - Description: fmt.Sprintf("@%s %s issue #%d in %s", owner.Handle, state, issue.IssueId, f.OwnerSlashRepo()), - Link: &feeds.Link{Href: fmt.Sprintf("%s/%s/issues/%d", rp.config.Core.AppviewHost, f.OwnerSlashRepo(), issue.IssueId)}, + Description: fmt.Sprintf("@%s %s issue #%d in @%s", owner.Handle, state, issue.IssueId, ownerSlashRepo), + Link: &feeds.Link{Href: fmt.Sprintf("%s/%s/issues/%d", rp.config.Core.AppviewHost, ownerSlashRepo, issue.IssueId)}, Created: issue.Created, Author: &feeds.Author{Name: fmt.Sprintf("@%s", owner.Handle)}, }, nil @@ -152,8 +152,14 @@ if err != nil { log.Println("failed to fully resolve repo:", err) return } + repoOwnerId, ok := r.Context().Value("resolvedId").(identity.Identity) + if !ok || repoOwnerId.Handle.IsInvalidHandle() { + log.Println("failed to get resolved repo owner id") + return + } + ownerSlashRepo := repoOwnerId.Handle.String() + "/" + f.Name - feed, err := rp.getRepoFeed(r.Context(), f) + feed, err := rp.getRepoFeed(r.Context(), &f.Repo, ownerSlashRepo) if err != nil { log.Println("failed to get repo feed:", err) rp.pages.Error500(w) diff --git a/appview/repo/index.go b/appview/repo/index.go --- a/appview/repo/index.go +++ b/appview/repo/index.go @@ -179,7 +179,7 @@ ) if err != nil || langs == nil { // non-fatal, fetch langs from ks via XRPC - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) ls, err := tangled.RepoLanguages(ctx, xrpcc, currentRef, repo) if err != nil { if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { @@ -256,7 +256,7 @@ } // buildIndexResponse creates a RepoIndexResponse by combining multiple xrpc calls in parallel func (rp *Repo) buildIndexResponse(ctx context.Context, xrpcc *indigoxrpc.Client, f *reporesolver.ResolvedRepo, ref string) (*types.RepoIndexResponse, error) { - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) // first get branches to determine the ref if not specified branchesBytes, err := tangled.RepoBranches(ctx, xrpcc, "", 0, repo) diff --git a/appview/repo/log.go b/appview/repo/log.go --- a/appview/repo/log.go +++ b/appview/repo/log.go @@ -57,7 +57,7 @@ offset := (page - 1) * int(limit) cursor = strconv.Itoa(offset) } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.log", "err", xrpcerr) @@ -174,7 +174,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.diff", "err", xrpcerr) diff --git a/appview/repo/repo.go b/appview/repo/repo.go --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -864,7 +864,7 @@ err = tangled.RepoDelete( r.Context(), client, &tangled.RepoDelete_Input{ - Did: f.OwnerDid(), + Did: f.Did, Name: f.Name, Rkey: f.Rkey, }, @@ -902,14 +902,14 @@ } l.Info("removed collaborators") // remove repo RBAC - err = rp.enforcer.RemoveRepo(f.OwnerDid(), f.Knot, f.DidSlashRepo()) + err = rp.enforcer.RemoveRepo(f.Did, f.Knot, f.DidSlashRepo()) if err != nil { rp.pages.Notice(w, noticeId, "Failed to update RBAC rules") return } // remove repo from db - err = db.RemoveRepo(tx, f.OwnerDid(), f.Name) + err = db.RemoveRepo(tx, f.Did, f.Name) if err != nil { rp.pages.Notice(w, noticeId, "Failed to update appview") return @@ -930,7 +930,7 @@ http.Error(w, err.Error(), http.StatusInternalServerError) return } - rp.pages.HxRedirect(w, fmt.Sprintf("/%s", f.OwnerDid())) + rp.pages.HxRedirect(w, fmt.Sprintf("/%s", f.Did)) } func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) { @@ -1058,7 +1058,7 @@ if rp.config.Core.Dev { uri = "http" } - forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.OwnerDid(), f.Repo.Name) + forkSourceUrl := fmt.Sprintf("%s://%s/%s/%s", uri, f.Knot, f.Did, f.Repo.Name) l = l.With("cloneUrl", forkSourceUrl) sourceAt := f.RepoAt().String() diff --git a/appview/repo/settings.go b/appview/repo/settings.go --- a/appview/repo/settings.go +++ b/appview/repo/settings.go @@ -194,7 +194,7 @@ xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.branches", "err", xrpcerr) @@ -292,7 +292,7 @@ f, err := rp.repoResolver.Resolve(r) user := rp.oauth.GetUser(r) // all spindles that the repo owner is a member of - spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid()) + spindles, err := rp.enforcer.GetSpindlesForUser(f.Did) if err != nil { l.Error("failed to fetch spindles", "err", err) return diff --git a/appview/repo/tags.go b/appview/repo/tags.go --- a/appview/repo/tags.go +++ b/appview/repo/tags.go @@ -31,7 +31,7 @@ host := fmt.Sprintf("%s://%s", scheme, f.Knot) xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tags", "err", xrpcerr) diff --git a/appview/repo/tree.go b/appview/repo/tree.go --- a/appview/repo/tree.go +++ b/appview/repo/tree.go @@ -9,6 +9,7 @@ "time" "tangled.org/core/api/tangled" "tangled.org/core/appview/pages" + "tangled.org/core/appview/reporesolver" xrpcclient "tangled.org/core/appview/xrpcclient" "tangled.org/core/types" @@ -39,7 +40,7 @@ host := fmt.Sprintf("%s://%s", scheme, f.Knot) xrpcc := &indigoxrpc.Client{ Host: host, } - repo := fmt.Sprintf("%s/%s", f.OwnerDid(), f.Name) + repo := fmt.Sprintf("%s/%s", f.Did, f.Name) xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo) if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil { l.Error("failed to call XRPC repo.tree", "err", xrpcerr) @@ -79,16 +80,17 @@ if xrpcResp.Readme != nil { result.ReadmeFileName = xrpcResp.Readme.Filename result.Readme = xrpcResp.Readme.Contents } + ownerSlashRepo := reporesolver.GetBaseRepoPath(r, &f.Repo) // redirects tree paths trying to access a blob; in this case the result.Files is unpopulated, // so we can safely redirect to the "parent" (which is the same file). if len(result.Files) == 0 && result.Parent == treePath { - redirectTo := fmt.Sprintf("/%s/blob/%s/%s", f.OwnerSlashRepo(), url.PathEscape(ref), result.Parent) + redirectTo := fmt.Sprintf("/%s/blob/%s/%s", ownerSlashRepo, url.PathEscape(ref), result.Parent) http.Redirect(w, r, redirectTo, http.StatusFound) return } user := rp.oauth.GetUser(r) var breadcrumbs [][]string - breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), url.PathEscape(ref))}) + breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", ownerSlashRepo, url.PathEscape(ref))}) if treePath != "" { for idx, elem := range strings.Split(treePath, "/") { breadcrumbs = append(breadcrumbs, []string{elem, fmt.Sprintf("%s/%s", breadcrumbs[idx][1], url.PathEscape(elem))}) diff --git a/appview/reporesolver/resolver.go b/appview/reporesolver/resolver.go --- a/appview/reporesolver/resolver.go +++ b/appview/reporesolver/resolver.go @@ -12,7 +12,6 @@ "regexp" "strings" "github.com/bluesky-social/indigo/atproto/identity" - securejoin "github.com/cyphar/filepath-securejoin" "github.com/go-chi/chi/v5" "tangled.org/core/appview/config" "tangled.org/core/appview/db" @@ -44,6 +43,18 @@ func New(config *config.Config, enforcer *rbac.Enforcer, resolver *idresolver.Resolver, execer db.Execer) *RepoResolver { return &RepoResolver{config: config, enforcer: enforcer, idResolver: resolver, execer: execer} } +// NOTE: this... should not even be here. the entire package will be removed in future refactor +func GetBaseRepoPath(r *http.Request, repo *models.Repo) string { + var ( + user = chi.URLParam(r, "user") + name = chi.URLParam(r, "repo") + ) + if user == "" || name == "" { + return repo.DidSlashRepo() + } + return path.Join(user, name) +} + func (rr *RepoResolver) Resolve(r *http.Request) (*ResolvedRepo, error) { repo, ok := r.Context().Value("repo").(*models.Repo) if !ok { @@ -67,27 +78,6 @@ Ref: ref, rr: rr, }, nil -} - -func (f *ResolvedRepo) OwnerDid() string { - return f.OwnerId.DID.String() -} - -func (f *ResolvedRepo) OwnerHandle() string { - return f.OwnerId.Handle.String() -} - -func (f *ResolvedRepo) OwnerSlashRepo() string { - handle := f.OwnerId.Handle - - var p string - if handle != "" && !handle.IsInvalidHandle() { - p, _ = securejoin.SecureJoin(fmt.Sprintf("@%s", handle), f.Name) - } else { - p, _ = securejoin.SecureJoin(f.OwnerDid(), f.Name) - } - - return p } func (f *ResolvedRepo) Collaborators(ctx context.Context) ([]pages.Collaborator, error) { @@ -168,10 +158,10 @@ knot := f.Knot repoInfo := repoinfo.RepoInfo{ - OwnerDid: f.OwnerDid(), - OwnerHandle: f.OwnerHandle(), + OwnerDid: f.OwnerId.DID.String(), + OwnerHandle: f.OwnerId.Handle.String(), Name: f.Name, - Rkey: f.Repo.Rkey, + Rkey: f.Rkey, RepoAt: repoAt, Description: f.Description, Website: f.Website, -- tangled.sh