forked from tangled.org/core
Monorepo for Tangled

appview/pages: resolve did on render

Don't pass resolved user handles from http handlers. The page renderer
is capable of resolving DIDs and we are using redis cache, so the
performance won't matter much either.

Signed-off-by: Seongmin Lee <git@boltless.me>

authored by boltless.me and committed by Tangled 4143799e a47c25c0

+28 -8
appview/pages/funcmap.go
··· 22 22 chromahtml "github.com/alecthomas/chroma/v2/formatters/html" 23 23 "github.com/alecthomas/chroma/v2/lexers" 24 24 "github.com/alecthomas/chroma/v2/styles" 25 - "github.com/bluesky-social/indigo/atproto/syntax" 26 25 "github.com/dustin/go-humanize" 27 26 "github.com/go-enry/go-enry/v2" 28 27 "github.com/yuin/goldmark" 29 28 "tangled.org/core/appview/filetree" 29 + "tangled.org/core/appview/models" 30 30 "tangled.org/core/appview/pages/markup" 31 31 "tangled.org/core/crypto" 32 32 ) ··· 71 71 } 72 72 73 73 return identity.Handle.String() 74 + }, 75 + "ownerSlashRepo": func(repo *models.Repo) string { 76 + ownerId, err := p.resolver.ResolveIdent(context.Background(), repo.Did) 77 + if err != nil { 78 + return repo.DidSlashRepo() 79 + } 80 + handle := ownerId.Handle 81 + if handle != "" && !handle.IsInvalidHandle() { 82 + return string(handle) + "/" + repo.Name 83 + } 84 + return repo.DidSlashRepo() 74 85 }, 75 86 "truncateAt30": func(s string) string { 76 87 if len(s) <= 30 { ··· 140 151 } 141 152 142 153 return b 143 - }, 144 - "didOrHandle": func(did, handle string) string { 145 - if handle != "" && handle != syntax.HandleInvalid.String() { 146 - return handle 147 - } else { 148 - return did 149 - } 150 154 }, 151 155 "assoc": func(values ...string) ([][]string, error) { 152 156 if len(values)%2 != 0 { ··· 379 383 } 380 384 } 381 385 386 + func (p *Pages) resolveDid(did string) string { 387 + identity, err := p.resolver.ResolveIdent(context.Background(), did) 388 + 389 + if err != nil { 390 + return did 391 + } 392 + 393 + if identity.Handle.IsInvalidHandle() { 394 + return "handle.invalid" 395 + } 396 + 397 + return identity.Handle.String() 398 + } 399 + 382 400 func (p *Pages) AvatarUrl(handle, size string) string { 383 401 handle = strings.TrimPrefix(handle, "@") 402 + 403 + handle = p.resolveDid(handle) 384 404 385 405 secret := p.avatar.SharedSecret 386 406 h := hmac.New(sha256.New, []byte(secret))
+2 -4
appview/pages/pages.go
··· 492 492 493 493 type ProfileCard struct { 494 494 UserDid string 495 - UserHandle string 496 495 FollowStatus models.FollowStatus 497 496 Punchcard *models.Punchcard 498 497 Profile *models.Profile ··· 841 840 } 842 841 843 842 type Collaborator struct { 844 - Did string 845 - Handle string 846 - Role string 843 + Did string 844 + Role string 847 845 } 848 846 849 847 type RepoSettingsParams struct {
+2 -2
appview/pages/repoinfo/repoinfo.go
··· 9 9 "tangled.org/core/appview/state/userutil" 10 10 ) 11 11 12 - func (r RepoInfo) Owner() string { 12 + func (r RepoInfo) owner() string { 13 13 if r.OwnerHandle != "" { 14 14 return r.OwnerHandle 15 15 } else { ··· 18 18 } 19 19 20 20 func (r RepoInfo) FullName() string { 21 - return path.Join(r.Owner(), r.Name) 21 + return path.Join(r.owner(), r.Name) 22 22 } 23 23 24 24 func (r RepoInfo) OwnerWithoutAt() string {
+8 -7
appview/pages/templates/layouts/profilebase.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }}{{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }}{{ end }} 2 2 3 3 {{ define "extrameta" }} 4 - {{ $avatarUrl := fullAvatar .Card.UserHandle }} 5 - <meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}" /> 4 + {{ $handle := resolve .Card.UserDid }} 5 + {{ $avatarUrl := fullAvatar $handle }} 6 + <meta property="og:title" content="{{ $handle }}" /> 6 7 <meta property="og:type" content="profile" /> 7 - <meta property="og:url" content="https://tangled.org/{{ or .Card.UserHandle .Card.UserDid }}?tab={{ .Active }}" /> 8 - <meta property="og:description" content="{{ or .Card.Profile.Description .Card.UserHandle .Card.UserDid }}" /> 8 + <meta property="og:url" content="https://tangled.org/{{ $handle }}?tab={{ .Active }}" /> 9 + <meta property="og:description" content="{{ or .Card.Profile.Description $handle }}" /> 9 10 <meta property="og:image" content="{{ $avatarUrl }}" /> 10 11 <meta property="og:image:width" content="512" /> 11 12 <meta property="og:image:height" content="512" /> 12 13 13 14 <meta name="twitter:card" content="summary" /> 14 - <meta name="twitter:title" content="{{ or .Card.UserHandle .Card.UserDid }}" /> 15 - <meta name="twitter:description" content="{{ or .Card.Profile.Description .Card.UserHandle .Card.UserDid }}" /> 15 + <meta name="twitter:title" content="{{ $handle }}" /> 16 + <meta name="twitter:description" content="{{ or .Card.Profile.Description $handle }}" /> 16 17 <meta name="twitter:image" content="{{ $avatarUrl }}" /> 17 18 {{ end }} 18 19
+1 -1
appview/pages/templates/repo/empty.html
··· 35 35 36 36 <p><span class="{{$bullet}}">1</span>First, generate a new <a href="https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key" class="underline">SSH key pair</a>.</p> 37 37 <p><span class="{{$bullet}}">2</span>Then add the public key to your account from the <a href="/settings" class="underline">settings</a> page.</p> 38 - <p><span class="{{$bullet}}">3</span>Configure your remote to <code>git@{{ $knot | stripPort }}:{{ .RepoInfo.OwnerHandle }}/{{ .RepoInfo.Name }}</code></p> 38 + <p><span class="{{$bullet}}">3</span>Configure your remote to <code>git@{{ $knot | stripPort }}:{{ resolve .RepoInfo.OwnerDid }}/{{ .RepoInfo.Name }}</code></p> 39 39 <p><span class="{{$bullet}}">4</span>Push!</p> 40 40 </div> 41 41 </div>
+3 -2
appview/pages/templates/repo/fragments/cloneDropdown.html
··· 43 43 44 44 <!-- SSH Clone --> 45 45 <div class="mb-3"> 46 + {{ $repoOwnerHandle := resolve .RepoInfo.OwnerDid }} 46 47 <label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">SSH</label> 47 48 <div class="flex items-center border border-gray-300 dark:border-gray-600 rounded"> 48 49 <code 49 50 class="flex-1 px-3 py-2 text-sm bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-l select-all cursor-pointer whitespace-nowrap overflow-x-auto" 50 51 onclick="window.getSelection().selectAllChildren(this)" 51 - data-url="git@{{ $knot | stripPort }}:{{ .RepoInfo.OwnerHandle }}/{{ .RepoInfo.Name }}" 52 - >git@{{ $knot | stripPort }}:{{ .RepoInfo.OwnerHandle }}/{{ .RepoInfo.Name }}</code> 52 + data-url="git@{{ $knot | stripPort }}:{{ $repoOwnerHandle }}/{{ .RepoInfo.Name }}" 53 + >git@{{ $knot | stripPort }}:{{ $repoOwnerHandle }}/{{ .RepoInfo.Name }}</code> 53 54 <button 54 55 onclick="copyToClipboard(this, this.previousElementSibling.getAttribute('data-url'))" 55 56 class="px-3 py-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 border-l border-gray-300 dark:border-gray-600"
+5 -4
appview/pages/templates/repo/settings/access.html
··· 29 29 {{ template "addCollaboratorButton" . }} 30 30 {{ end }} 31 31 {{ range .Collaborators }} 32 + {{ $handle := resolve .Did }} 32 33 <div class="border border-gray-200 dark:border-gray-700 rounded p-4"> 33 34 <div class="flex items-center gap-3"> 34 35 <img 35 - src="{{ fullAvatar .Handle }}" 36 - alt="{{ .Handle }}" 36 + src="{{ fullAvatar $handle }}" 37 + alt="{{ $handle }}" 37 38 class="rounded-full h-10 w-10 border border-gray-300 dark:border-gray-600 flex-shrink-0"/> 38 39 39 40 <div class="flex-1 min-w-0"> 40 - <a href="/{{ .Handle }}" class="block truncate"> 41 - {{ didOrHandle .Did .Handle }} 41 + <a href="/{{ $handle }}" class="block truncate"> 42 + {{ $handle }} 42 43 </a> 43 44 <p class="text-sm text-gray-500 dark:text-gray-400">{{ .Role }}</p> 44 45 </div>
+6 -5
appview/pages/templates/strings/dashboard.html
··· 1 - {{ define "title" }}strings by {{ or .Card.UserHandle .Card.UserDid }}{{ end }} 1 + {{ define "title" }}strings by {{ resolve .Card.UserDid }}{{ end }} 2 2 3 3 {{ define "extrameta" }} 4 - <meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}" /> 4 + {{ $handle := resolve .Card.UserDid }} 5 + <meta property="og:title" content="{{ $handle }}" /> 5 6 <meta property="og:type" content="profile" /> 6 - <meta property="og:url" content="https://tangled.org/{{ or .Card.UserHandle .Card.UserDid }}" /> 7 - <meta property="og:description" content="{{ or .Card.Profile.Description .Card.UserHandle .Card.UserDid }}" /> 7 + <meta property="og:url" content="https://tangled.org/{{ $handle }}" /> 8 + <meta property="og:description" content="{{ or .Card.Profile.Description $handle }}" /> 8 9 {{ end }} 9 10 10 11 ··· 35 36 {{ $s := index . 1 }} 36 37 <div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800"> 37 38 <div class="font-medium dark:text-white flex gap-2 items-center"> 38 - <a href="/strings/{{ or $root.Card.UserHandle $root.Card.UserDid }}/{{ $s.Rkey }}">{{ $s.Filename }}</a> 39 + <a href="/strings/{{ resolve $root.Card.UserDid }}/{{ $s.Rkey }}">{{ $s.Filename }}</a> 39 40 </div> 40 41 {{ with $s.Description }} 41 42 <div class="text-gray-600 dark:text-gray-300 text-sm">
+3 -3
appview/pages/templates/strings/string.html
··· 1 - {{ define "title" }}{{ .String.Filename }} · by {{ didOrHandle .Owner.DID.String .Owner.Handle.String }}{{ end }} 1 + {{ define "title" }}{{ .String.Filename }} · by {{ resolve .Owner.DID.String }}{{ end }} 2 2 3 3 {{ define "extrameta" }} 4 - {{ $ownerId := didOrHandle .Owner.DID.String .Owner.Handle.String }} 4 + {{ $ownerId := resolve .Owner.DID.String }} 5 5 <meta property="og:title" content="{{ .String.Filename }} · by {{ $ownerId }}" /> 6 6 <meta property="og:type" content="object" /> 7 7 <meta property="og:url" content="https://tangled.org/strings/{{ $ownerId }}/{{ .String.Rkey }}" /> ··· 9 9 {{ end }} 10 10 11 11 {{ define "content" }} 12 - {{ $ownerId := didOrHandle .Owner.DID.String .Owner.Handle.String }} 12 + {{ $ownerId := resolve .Owner.DID.String }} 13 13 <section id="string-header" class="mb-4 py-2 px-6 dark:text-white"> 14 14 <div class="text-lg flex items-center justify-between"> 15 15 <div>
+1 -1
appview/pages/templates/user/followers.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · followers {{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }} · followers {{ end }} 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-followers" class="md:col-span-8 order-2 md:order-2">
+1 -1
appview/pages/templates/user/following.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · following {{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }} · following {{ end }} 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-following" class="md:col-span-8 order-2 md:order-2">
+1 -1
appview/pages/templates/user/fragments/profileCard.html
··· 1 1 {{ define "user/fragments/profileCard" }} 2 - {{ $userIdent := didOrHandle .UserDid .UserHandle }} 2 + {{ $userIdent := resolve .UserDid }} 3 3 <div class="grid grid-cols-3 md:grid-cols-1 gap-1 items-center"> 4 4 <div id="avatar" class="col-span-1 flex justify-center items-center"> 5 5 <div class="w-3/4 aspect-square relative">
+2 -2
appview/pages/templates/user/overview.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }}{{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }}{{ end }} 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-repos" class="md:col-span-4 order-2 md:order-2"> ··· 224 224 {{ define "ownRepos" }} 225 225 <div> 226 226 <div class="text-sm font-bold px-2 pb-4 dark:text-white flex items-center gap-2"> 227 - <a href="/@{{ or $.Card.UserHandle $.Card.UserDid }}?tab=repos" 227 + <a href="/{{ resolve $.Card.UserDid }}?tab=repos" 228 228 class="flex text-black dark:text-white items-center gap-2 no-underline hover:no-underline group"> 229 229 <span>PINNED REPOS</span> 230 230 </a>
+1 -1
appview/pages/templates/user/repos.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · repos {{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }} · repos {{ end }} 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-repos" class="md:col-span-8 order-2 md:order-2">
+1 -1
appview/pages/templates/user/starred.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · repos {{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }} · repos {{ end }} 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-repos" class="md:col-span-8 order-2 md:order-2">
+2 -2
appview/pages/templates/user/strings.html
··· 1 - {{ define "title" }}{{ or .Card.UserHandle .Card.UserDid }} · strings {{ end }} 1 + {{ define "title" }}{{ resolve .Card.UserDid }} · strings {{ end }} 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-strings" class="md:col-span-8 order-2 md:order-2"> ··· 23 23 {{ $s := index . 1 }} 24 24 <div class="py-4 px-6 rounded bg-white dark:bg-gray-800"> 25 25 <div class="font-medium dark:text-white flex gap-2 items-center"> 26 - <a href="/strings/{{ or $root.Card.UserHandle $root.Card.UserDid }}/{{ $s.Rkey }}">{{ $s.Filename }}</a> 26 + <a href="/strings/{{ resolve $root.Card.UserDid }}/{{ $s.Rkey }}">{{ $s.Filename }}</a> 27 27 </div> 28 28 {{ with $s.Description }} 29 29 <div class="text-gray-600 dark:text-gray-300 text-sm">
-14
appview/reporesolver/resolver.go
··· 113 113 114 114 c := pages.Collaborator{ 115 115 Did: did, 116 - Handle: "", 117 116 Role: role, 118 117 } 119 118 collaborators = append(collaborators, c) 120 - } 121 - 122 - // populate all collborators with handles 123 - identsToResolve := make([]string, len(collaborators)) 124 - for i, collab := range collaborators { 125 - identsToResolve[i] = collab.Did 126 - } 127 - 128 - resolvedIdents := f.rr.idResolver.ResolveIdents(ctx, identsToResolve) 129 - for i, resolved := range resolvedIdents { 130 - if resolved != nil { 131 - collaborators[i].Handle = resolved.Handle.String() 132 - } 133 119 } 134 120 135 121 return collaborators, nil
+5 -6
appview/state/profile.go
··· 96 96 97 97 return &pages.ProfileCard{ 98 98 UserDid: did, 99 - UserHandle: ident.Handle.String(), 100 99 Profile: profile, 101 100 FollowStatus: followStatus, 102 101 Stats: pages.ProfileStats{ ··· 119 118 s.pages.Error500(w) 120 119 return 121 120 } 122 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 121 + l = l.With("profileDid", profile.UserDid) 123 122 124 123 repos, err := db.GetRepos( 125 124 s.db, ··· 180 179 s.pages.Error500(w) 181 180 return 182 181 } 183 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 182 + l = l.With("profileDid", profile.UserDid) 184 183 185 184 repos, err := db.GetRepos( 186 185 s.db, ··· 209 208 s.pages.Error500(w) 210 209 return 211 210 } 212 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 211 + l = l.With("profileDid", profile.UserDid) 213 212 214 213 stars, err := db.GetRepoStars(s.db, 0, db.FilterEq("did", profile.UserDid)) 215 214 if err != nil { ··· 238 237 s.pages.Error500(w) 239 238 return 240 239 } 241 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 240 + l = l.With("profileDid", profile.UserDid) 242 241 243 242 strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid)) 244 243 if err != nil { ··· 270 269 if err != nil { 271 270 return nil, err 272 271 } 273 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 272 + l = l.With("profileDid", profile.UserDid) 274 273 275 274 loggedInUser := s.oauth.GetUser(r) 276 275 params := FollowsPageParams{