+28
-8
appview/pages/funcmap.go
+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
)
···
70
70
}
71
71
72
72
return identity.Handle.String()
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()
73
84
},
74
85
"truncateAt30": func(s string) string {
75
86
if len(s) <= 30 {
···
130
141
}
131
142
132
143
return b
133
-
},
134
-
"didOrHandle": func(did, handle string) string {
135
-
if handle != "" && handle != syntax.HandleInvalid.String() {
136
-
return handle
137
-
} else {
138
-
return did
139
-
}
140
144
},
141
145
"assoc": func(values ...string) ([][]string, error) {
142
146
if len(values)%2 != 0 {
···
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, "@")
392
+
393
+
handle = p.resolveDid(handle)
374
394
375
395
secret := p.avatar.SharedSecret
376
396
h := hmac.New(sha256.New, []byte(secret))
+2
-4
appview/pages/pages.go
+2
-4
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
···
831
830
}
832
831
833
832
type Collaborator struct {
834
-
Did string
835
-
Handle string
836
-
Role string
833
+
Did string
834
+
Role string
837
835
}
838
836
839
837
type RepoSettingsParams struct {
+2
-2
appview/pages/repoinfo/repoinfo.go
+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
+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
+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
+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
+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
+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
+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
-1
appview/pages/templates/user/followers.html
+1
-1
appview/pages/templates/user/following.html
+1
-1
appview/pages/templates/user/following.html
+1
-1
appview/pages/templates/user/fragments/profileCard.html
+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
+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
-1
appview/pages/templates/user/repos.html
+1
-1
appview/pages/templates/user/starred.html
+1
-1
appview/pages/templates/user/starred.html
+2
-2
appview/pages/templates/user/strings.html
+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
-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
+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{