appview/pages: resolve did on render #801

merged
opened by boltless.me targeting master from sl/yurolxtlpsmz

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

+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 "tangled.org/core/appview/filetree" 28 + "tangled.org/core/appview/models" 29 29 "tangled.org/core/appview/pages/markup" 30 30 "tangled.org/core/crypto" 31 31 ) ··· 71 71 72 72 return identity.Handle.String() 73 73 }, 74 + "ownerSlashRepo": func(repo *models.Repo) string { 75 + ownerId, err := p.resolver.ResolveIdent(context.Background(), repo.Did) 76 + if err != nil { 77 + return repo.DidSlashRepo() 78 + } 79 + handle := ownerId.Handle 80 + if handle != "" && !handle.IsInvalidHandle() { 81 + return string(handle)+"/"+repo.Name 82 + } 83 + return repo.DidSlashRepo() 84 + }, 74 85 "truncateAt30": func(s string) string { 75 86 if len(s) <= 30 { 76 87 return s ··· 131 142 132 143 return b 133 144 }, 134 - "didOrHandle": func(did, handle string) string { 135 - if handle != "" && handle != syntax.HandleInvalid.String() { 136 - return handle 137 - } else { 138 - return did 139 - } 140 - }, 141 145 "assoc": func(values ...string) ([][]string, error) { 142 146 if len(values)%2 != 0 { 143 147 return nil, fmt.Errorf("invalid assoc call, must have an even number of arguments") ··· 369 373 } 370 374 } 371 375 376 + func (p *Pages) resolveDid(did string) string { 377 + identity, err := p.resolver.ResolveIdent(context.Background(), did) 378 + 379 + if err != nil { 380 + return did 381 + } 382 + 383 + if identity.Handle.IsInvalidHandle() { 384 + return "handle.invalid" 385 + } 386 + 387 + return identity.Handle.String() 388 + } 389 + 372 390 func (p *Pages) AvatarUrl(handle, size string) string { 373 391 handle = strings.TrimPrefix(handle, "@") 374 392 393 + handle = p.resolveDid(handle) 394 + 375 395 secret := p.avatar.SharedSecret 376 396 h := hmac.New(sha256.New, []byte(secret)) 377 397 h.Write([]byte(handle))
-2
appview/pages/pages.go
··· 482 482 483 483 type ProfileCard struct { 484 484 UserDid string 485 - UserHandle string 486 485 FollowStatus models.FollowStatus 487 486 Punchcard *models.Punchcard 488 487 Profile *models.Profile ··· 832 831 833 832 type Collaborator struct { 834 833 Did string 835 - Handle string 836 834 Role string 837 835 } 838 836
+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 119 } 121 120 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 - } 134 - 135 121 return collaborators, nil 136 122 } 137 123
+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.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid)) 215 214 if err != nil { ··· 240 239 s.pages.Error500(w) 241 240 return 242 241 } 243 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 242 + l = l.With("profileDid", profile.UserDid) 244 243 245 244 strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid)) 246 245 if err != nil { ··· 272 271 if err != nil { 273 272 return nil, err 274 273 } 275 - l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle) 274 + l = l.With("profileDid", profile.UserDid) 276 275 277 276 loggedInUser := s.oauth.GetUser(r) 278 277 params := FollowsPageParams{