From ea4ade0412ad13ec8a66c01b69ce9ab88008f69f Mon Sep 17 00:00:00 2001 From: Seongmin Lee Date: Sat, 04 Apr 2026 11:35:13 +0000 Subject: [PATCH] appview/{pages,state/comment}: redirect to correct location Introduce aturi->url maker in `pages.Pages`. This can be used throughout the codebase later. Signed-off-by: Seongmin Lee --- appview/pages/url.go | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ appview/state/comment.go | 9 ++++++--- 2 file(s) changed, 119 insertion(s)(+), 3 deletion(s)(-) diff --git a/appview/pages/url.go b/appview/pages/url.go new file mode 100644 --- /dev/null +++ b/appview/pages/url.go @@ -0,0 +1,113 @@ +package pages + +import ( + "context" + "database/sql" + "fmt" + "path" + "strconv" + + "github.com/bluesky-social/indigo/atproto/syntax" + "tangled.org/core/api/tangled" + "tangled.org/core/appview/db" + "tangled.org/core/appview/models" + "tangled.org/core/orm" +) + +func (p *Pages) MakeCommentUrl(ctx context.Context, uri syntax.ATURI) (string, error) { + comment, err := db.GetComment(p.db, orm.FilterEq("at_uri", uri)) + if err != nil { + return "", fmt.Errorf("failed to get comment: %w", err) + } + subjectUri := syntax.ATURI(comment.Subject.Uri) + switch subjectUri.Collection() { + case tangled.RepoIssueNSID: + issueUrl, err := p.MakeIssueUrl(ctx, subjectUri) + if err != nil { + return "", fmt.Errorf("failed to make issue url: %w", err) + } + return issueUrl + fmt.Sprintf("#comment-%s", comment.Rkey), nil + case tangled.RepoPullNSID: + if comment.PullRoundIdx == nil { + return "", fmt.Errorf("comment.pullRoundIdx is missing") + } + pullUrl, err := p.MakePullUrl(ctx, subjectUri, *comment.PullRoundIdx) + if err != nil { + return "", fmt.Errorf("failed to make pull url: %w", err) + } + return pullUrl + fmt.Sprintf("#comment-%s", comment.Rkey), nil + case tangled.StringNSID: + stringUrl, err := p.MakeStringUrl(ctx, subjectUri) + if err != nil { + return "", fmt.Errorf("failed to make string url: %w", err) + } + return stringUrl + fmt.Sprintf("#comment-%s", comment.Rkey), nil + default: + return "", fmt.Errorf("unknown subject collection '%s'", subjectUri.Collection()) + } +} + +func (p *Pages) MakeIssueUrl(ctx context.Context, uri syntax.ATURI) (string, error) { + issue, err := func(uri syntax.ATURI) (*models.Issue, error) { + issues, err := db.GetIssues(p.db, orm.FilterEq("at_uri", uri)) + if err != nil { + return nil, err + } + if len(issues) != 1 { + return nil, sql.ErrNoRows + } + return &issues[0], nil + }(uri) + if err != nil { + return "", fmt.Errorf("failed to get issue: %w", err) + } + repoUrl, err := p.makeRepoUrlInner(ctx, issue.Repo) + if err != nil { + return "", fmt.Errorf("failed to make repo url: %w", err) + } + return path.Join(repoUrl, "issues", strconv.FormatInt(issue.Id, 10)), nil +} + +func (p *Pages) MakePullUrl(ctx context.Context, uri syntax.ATURI, roundIdx int) (string, error) { + pull, err := db.GetPull(p.db, orm.FilterEq("at_uri", uri)) + if err != nil { + return "", fmt.Errorf("failed to get pull: %w", err) + } + repoUrl, err := p.makeRepoUrlInner(ctx, pull.Repo) + if err != nil { + return "", fmt.Errorf("failed to make repo url: %w", err) + } + return path.Join(repoUrl, "pulls", strconv.Itoa(pull.ID), "rounds", strconv.Itoa(roundIdx)), nil +} + +func (p *Pages) makeRepoUrlInner(ctx context.Context, repo *models.Repo) (string, error) { + owner := repo.Did + ownerIdentity, err := p.resolver.Directory().LookupDID(ctx, syntax.DID(repo.Did)) + if err == nil && !ownerIdentity.Handle.IsInvalidHandle() { + owner = ownerIdentity.Handle.String() + } + return path.Join("/", owner, repo.Slug()), nil +} + +func (p *Pages) MakeStringUrl(ctx context.Context, uri syntax.ATURI) (string, error) { + string_, err := func(uri syntax.ATURI) (*models.String, error) { + strings, err := db.GetStrings(p.db, 1, orm.FilterEq("at_uri", uri)) + if err != nil { + return nil, err + } + if len(strings) != 1 { + return nil, sql.ErrNoRows + } + return &strings[0], nil + }(uri) + if err != nil { + return "", fmt.Errorf("failed to get string: %w", err) + } + + owner := string_.Did.String() + ownerIdentity, err := p.resolver.Directory().LookupDID(ctx, string_.Did) + if err == nil && !ownerIdentity.Handle.IsInvalidHandle() { + owner = ownerIdentity.Handle.String() + } + return path.Join("/strings", owner, string_.Rkey), nil +} diff --git a/appview/state/comment.go b/appview/state/comment.go --- a/appview/state/comment.go +++ b/appview/state/comment.go @@ -311,9 +311,12 @@ return } - // TODO: return comment or reply-comment fragment - // onattach, htmx-callback to focus on comment. - s.pages.HxRefresh(w) + target, err := s.pages.MakeCommentUrl(ctx, comment.AtUri()) + if err != nil { + s.pages.HxRefresh(w) + } + + s.pages.HxLocation(w, target) } func (s *State) EditComment(w http.ResponseWriter, r *http.Request) { -- tangled.sh