-13
.editorconfig
-13
.editorconfig
+9
-4
appview/issues/issues.go
+9
-4
appview/issues/issues.go
···
312
// notify about the issue closure
313
rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue)
314
315
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId))
316
return
317
} else {
318
l.Error("user is not permitted to close issue")
···
362
// notify about the issue reopen
363
rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue)
364
365
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId))
366
return
367
} else {
368
l.Error("user is not the owner of the repo")
···
466
}
467
rp.notifier.NewIssueComment(r.Context(), &comment, mentions)
468
469
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", f.OwnerSlashRepo(), issue.IssueId, commentId))
470
}
471
472
func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) {
···
970
}
971
}
972
rp.notifier.NewIssue(r.Context(), issue, mentions)
973
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId))
974
return
975
}
976
}
···
312
// notify about the issue closure
313
rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue)
314
315
+
ownerSlashRepo := rp.repoResolver.GetBaseRepoPath(r, &f.Repo)
316
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
317
return
318
} else {
319
l.Error("user is not permitted to close issue")
···
363
// notify about the issue reopen
364
rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue)
365
366
+
ownerSlashRepo := rp.repoResolver.GetBaseRepoPath(r, &f.Repo)
367
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
368
return
369
} else {
370
l.Error("user is not the owner of the repo")
···
468
}
469
rp.notifier.NewIssueComment(r.Context(), &comment, mentions)
470
471
+
ownerSlashRepo := rp.repoResolver.GetBaseRepoPath(r, &f.Repo)
472
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d#comment-%d", ownerSlashRepo, issue.IssueId, commentId))
473
}
474
475
func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) {
···
973
}
974
}
975
rp.notifier.NewIssue(r.Context(), issue, mentions)
976
+
977
+
ownerSlashRepo := rp.repoResolver.GetBaseRepoPath(r, &f.Repo)
978
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
979
return
980
}
981
}
+2
-2
appview/middleware/middleware.go
+2
-2
appview/middleware/middleware.go
···
164
ok, err := mw.enforcer.E.Enforce(actor.Did, f.Knot, f.DidSlashRepo(), requiredPerm)
165
if err != nil || !ok {
166
// we need a logged in user
167
-
log.Printf("%s does not have perms of a %s in repo %s", actor.Did, requiredPerm, f.OwnerSlashRepo())
168
http.Error(w, "Forbiden", http.StatusUnauthorized)
169
return
170
}
···
327
return
328
}
329
330
-
fullName := f.OwnerHandle() + "/" + f.Name
331
332
if r.Header.Get("User-Agent") == "Go-http-client/1.1" {
333
if r.URL.Query().Get("go-get") == "1" {
···
164
ok, err := mw.enforcer.E.Enforce(actor.Did, f.Knot, f.DidSlashRepo(), requiredPerm)
165
if err != nil || !ok {
166
// we need a logged in user
167
+
log.Printf("%s does not have perms of a %s in repo %s", actor.Did, requiredPerm, f.DidSlashRepo())
168
http.Error(w, "Forbiden", http.StatusUnauthorized)
169
return
170
}
···
327
return
328
}
329
330
+
fullName := mw.repoResolver.GetBaseRepoPath(r, &f.Repo)
331
332
if r.Header.Get("User-Agent") == "Go-http-client/1.1" {
333
if r.URL.Query().Get("go-get") == "1" {
+28
-8
appview/pages/funcmap.go
+28
-8
appview/pages/funcmap.go
···
22
chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
23
"github.com/alecthomas/chroma/v2/lexers"
24
"github.com/alecthomas/chroma/v2/styles"
25
-
"github.com/bluesky-social/indigo/atproto/syntax"
26
"github.com/dustin/go-humanize"
27
"github.com/go-enry/go-enry/v2"
28
"tangled.org/core/appview/filetree"
29
"tangled.org/core/appview/pages/markup"
30
"tangled.org/core/crypto"
31
)
···
70
}
71
72
return identity.Handle.String()
73
},
74
"truncateAt30": func(s string) string {
75
if len(s) <= 30 {
···
130
}
131
132
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
},
141
"assoc": func(values ...string) ([][]string, error) {
142
if len(values)%2 != 0 {
···
369
}
370
}
371
372
func (p *Pages) AvatarUrl(handle, size string) string {
373
handle = strings.TrimPrefix(handle, "@")
374
375
secret := p.avatar.SharedSecret
376
h := hmac.New(sha256.New, []byte(secret))
···
22
chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
23
"github.com/alecthomas/chroma/v2/lexers"
24
"github.com/alecthomas/chroma/v2/styles"
25
"github.com/dustin/go-humanize"
26
"github.com/go-enry/go-enry/v2"
27
"tangled.org/core/appview/filetree"
28
+
"tangled.org/core/appview/models"
29
"tangled.org/core/appview/pages/markup"
30
"tangled.org/core/crypto"
31
)
···
70
}
71
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()
84
},
85
"truncateAt30": func(s string) string {
86
if len(s) <= 30 {
···
141
}
142
143
return b
144
},
145
"assoc": func(values ...string) ([][]string, error) {
146
if len(values)%2 != 0 {
···
373
}
374
}
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
+
390
func (p *Pages) AvatarUrl(handle, size string) string {
391
handle = strings.TrimPrefix(handle, "@")
392
+
393
+
handle = p.resolveDid(handle)
394
395
secret := p.avatar.SharedSecret
396
h := hmac.New(sha256.New, []byte(secret))
-2
appview/pages/pages.go
-2
appview/pages/pages.go
+4
-4
appview/pages/repoinfo/repoinfo.go
+4
-4
appview/pages/repoinfo/repoinfo.go
···
9
"tangled.org/core/appview/state/userutil"
10
)
11
12
-
func (r RepoInfo) Owner() string {
13
if r.OwnerHandle != "" {
14
return r.OwnerHandle
15
} else {
···
18
}
19
20
func (r RepoInfo) FullName() string {
21
-
return path.Join(r.Owner(), r.Name)
22
}
23
24
-
func (r RepoInfo) OwnerWithoutAt() string {
25
if r.OwnerHandle != "" {
26
return r.OwnerHandle
27
} else {
···
30
}
31
32
func (r RepoInfo) FullNameWithoutAt() string {
33
-
return path.Join(r.OwnerWithoutAt(), r.Name)
34
}
35
36
func (r RepoInfo) GetTabs() [][]string {
···
9
"tangled.org/core/appview/state/userutil"
10
)
11
12
+
func (r RepoInfo) owner() string {
13
if r.OwnerHandle != "" {
14
return r.OwnerHandle
15
} else {
···
18
}
19
20
func (r RepoInfo) FullName() string {
21
+
return path.Join(r.owner(), r.Name)
22
}
23
24
+
func (r RepoInfo) ownerWithoutAt() string {
25
if r.OwnerHandle != "" {
26
return r.OwnerHandle
27
} else {
···
30
}
31
32
func (r RepoInfo) FullNameWithoutAt() string {
33
+
return path.Join(r.ownerWithoutAt(), r.Name)
34
}
35
36
func (r RepoInfo) GetTabs() [][]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 }}
2
3
{{ define "extrameta" }}
4
-
{{ $avatarUrl := fullAvatar .Card.UserHandle }}
5
-
<meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}" />
6
<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 }}" />
9
<meta property="og:image" content="{{ $avatarUrl }}" />
10
<meta property="og:image:width" content="512" />
11
<meta property="og:image:height" content="512" />
12
13
<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 }}" />
16
<meta name="twitter:image" content="{{ $avatarUrl }}" />
17
{{ end }}
18
···
1
+
{{ define "title" }}{{ resolve .Card.UserDid }}{{ end }}
2
3
{{ define "extrameta" }}
4
+
{{ $handle := resolve .Card.UserDid }}
5
+
{{ $avatarUrl := fullAvatar $handle }}
6
+
<meta property="og:title" content="{{ $handle }}" />
7
<meta property="og:type" content="profile" />
8
+
<meta property="og:url" content="https://tangled.org/{{ $handle }}?tab={{ .Active }}" />
9
+
<meta property="og:description" content="{{ or .Card.Profile.Description $handle }}" />
10
<meta property="og:image" content="{{ $avatarUrl }}" />
11
<meta property="og:image:width" content="512" />
12
<meta property="og:image:height" content="512" />
13
14
<meta name="twitter:card" content="summary" />
15
+
<meta name="twitter:title" content="{{ $handle }}" />
16
+
<meta name="twitter:description" content="{{ or .Card.Profile.Description $handle }}" />
17
<meta name="twitter:image" content="{{ $avatarUrl }}" />
18
{{ end }}
19
+1
-1
appview/pages/templates/repo/empty.html
+1
-1
appview/pages/templates/repo/empty.html
···
35
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
<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>
39
<p><span class="{{$bullet}}">4</span>Push!</p>
40
</div>
41
</div>
···
35
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
<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 }}:{{ resolve .RepoInfo.OwnerDid }}/{{ .RepoInfo.Name }}</code></p>
39
<p><span class="{{$bullet}}">4</span>Push!</p>
40
</div>
41
</div>
+3
-2
appview/pages/templates/repo/fragments/cloneDropdown.html
+3
-2
appview/pages/templates/repo/fragments/cloneDropdown.html
···
43
44
<!-- SSH Clone -->
45
<div class="mb-3">
46
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">SSH</label>
47
<div class="flex items-center border border-gray-300 dark:border-gray-600 rounded">
48
<code
49
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
onclick="window.getSelection().selectAllChildren(this)"
51
-
data-url="git@{{ $knot | stripPort }}:{{ .RepoInfo.OwnerHandle }}/{{ .RepoInfo.Name }}"
52
-
>git@{{ $knot | stripPort }}:{{ .RepoInfo.OwnerHandle }}/{{ .RepoInfo.Name }}</code>
53
<button
54
onclick="copyToClipboard(this, this.previousElementSibling.getAttribute('data-url'))"
55
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"
···
43
44
<!-- SSH Clone -->
45
<div class="mb-3">
46
+
{{ $repoOwnerHandle := resolve .RepoInfo.OwnerDid }}
47
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">SSH</label>
48
<div class="flex items-center border border-gray-300 dark:border-gray-600 rounded">
49
<code
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"
51
onclick="window.getSelection().selectAllChildren(this)"
52
+
data-url="git@{{ $knot | stripPort }}:{{ $repoOwnerHandle }}/{{ .RepoInfo.Name }}"
53
+
>git@{{ $knot | stripPort }}:{{ $repoOwnerHandle }}/{{ .RepoInfo.Name }}</code>
54
<button
55
onclick="copyToClipboard(this, this.previousElementSibling.getAttribute('data-url'))"
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
{{ template "addCollaboratorButton" . }}
30
{{ end }}
31
{{ range .Collaborators }}
32
<div class="border border-gray-200 dark:border-gray-700 rounded p-4">
33
<div class="flex items-center gap-3">
34
<img
35
-
src="{{ fullAvatar .Handle }}"
36
-
alt="{{ .Handle }}"
37
class="rounded-full h-10 w-10 border border-gray-300 dark:border-gray-600 flex-shrink-0"/>
38
39
<div class="flex-1 min-w-0">
40
-
<a href="/{{ .Handle }}" class="block truncate">
41
-
{{ didOrHandle .Did .Handle }}
42
</a>
43
<p class="text-sm text-gray-500 dark:text-gray-400">{{ .Role }}</p>
44
</div>
···
29
{{ template "addCollaboratorButton" . }}
30
{{ end }}
31
{{ range .Collaborators }}
32
+
{{ $handle := resolve .Did }}
33
<div class="border border-gray-200 dark:border-gray-700 rounded p-4">
34
<div class="flex items-center gap-3">
35
<img
36
+
src="{{ fullAvatar $handle }}"
37
+
alt="{{ $handle }}"
38
class="rounded-full h-10 w-10 border border-gray-300 dark:border-gray-600 flex-shrink-0"/>
39
40
<div class="flex-1 min-w-0">
41
+
<a href="/{{ $handle }}" class="block truncate">
42
+
{{ $handle }}
43
</a>
44
<p class="text-sm text-gray-500 dark:text-gray-400">{{ .Role }}</p>
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 }}
2
3
{{ define "extrameta" }}
4
-
<meta property="og:title" content="{{ or .Card.UserHandle .Card.UserDid }}" />
5
<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 }}" />
8
{{ end }}
9
10
···
35
{{ $s := index . 1 }}
36
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800">
37
<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
</div>
40
{{ with $s.Description }}
41
<div class="text-gray-600 dark:text-gray-300 text-sm">
···
1
+
{{ define "title" }}strings by {{ resolve .Card.UserDid }}{{ end }}
2
3
{{ define "extrameta" }}
4
+
{{ $handle := resolve .Card.UserDid }}
5
+
<meta property="og:title" content="{{ $handle }}" />
6
<meta property="og:type" content="profile" />
7
+
<meta property="og:url" content="https://tangled.org/{{ $handle }}" />
8
+
<meta property="og:description" content="{{ or .Card.Profile.Description $handle }}" />
9
{{ end }}
10
11
···
36
{{ $s := index . 1 }}
37
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800">
38
<div class="font-medium dark:text-white flex gap-2 items-center">
39
+
<a href="/strings/{{ resolve $root.Card.UserDid }}/{{ $s.Rkey }}">{{ $s.Filename }}</a>
40
</div>
41
{{ with $s.Description }}
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 }}
2
3
{{ define "extrameta" }}
4
-
{{ $ownerId := didOrHandle .Owner.DID.String .Owner.Handle.String }}
5
<meta property="og:title" content="{{ .String.Filename }} · by {{ $ownerId }}" />
6
<meta property="og:type" content="object" />
7
<meta property="og:url" content="https://tangled.org/strings/{{ $ownerId }}/{{ .String.Rkey }}" />
···
9
{{ end }}
10
11
{{ define "content" }}
12
-
{{ $ownerId := didOrHandle .Owner.DID.String .Owner.Handle.String }}
13
<section id="string-header" class="mb-4 py-2 px-6 dark:text-white">
14
<div class="text-lg flex items-center justify-between">
15
<div>
···
1
+
{{ define "title" }}{{ .String.Filename }} · by {{ resolve .Owner.DID.String }}{{ end }}
2
3
{{ define "extrameta" }}
4
+
{{ $ownerId := resolve .Owner.DID.String }}
5
<meta property="og:title" content="{{ .String.Filename }} · by {{ $ownerId }}" />
6
<meta property="og:type" content="object" />
7
<meta property="og:url" content="https://tangled.org/strings/{{ $ownerId }}/{{ .String.Rkey }}" />
···
9
{{ end }}
10
11
{{ define "content" }}
12
+
{{ $ownerId := resolve .Owner.DID.String }}
13
<section id="string-header" class="mb-4 py-2 px-6 dark:text-white">
14
<div class="text-lg flex items-center justify-between">
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
+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 }}
2
3
{{ define "profileContent" }}
4
<div id="all-repos" class="md:col-span-4 order-2 md:order-2">
···
224
{{ define "ownRepos" }}
225
<div>
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"
228
class="flex text-black dark:text-white items-center gap-2 no-underline hover:no-underline group">
229
<span>PINNED REPOS</span>
230
</a>
···
1
+
{{ define "title" }}{{ resolve .Card.UserDid }}{{ end }}
2
3
{{ define "profileContent" }}
4
<div id="all-repos" class="md:col-span-4 order-2 md:order-2">
···
224
{{ define "ownRepos" }}
225
<div>
226
<div class="text-sm font-bold px-2 pb-4 dark:text-white flex items-center gap-2">
227
+
<a href="/{{ resolve $.Card.UserDid }}?tab=repos"
228
class="flex text-black dark:text-white items-center gap-2 no-underline hover:no-underline group">
229
<span>PINNED REPOS</span>
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 }}
2
3
{{ define "profileContent" }}
4
<div id="all-strings" class="md:col-span-8 order-2 md:order-2">
···
23
{{ $s := index . 1 }}
24
<div class="py-4 px-6 rounded bg-white dark:bg-gray-800">
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>
27
</div>
28
{{ with $s.Description }}
29
<div class="text-gray-600 dark:text-gray-300 text-sm">
···
1
+
{{ define "title" }}{{ resolve .Card.UserDid }} · strings {{ end }}
2
3
{{ define "profileContent" }}
4
<div id="all-strings" class="md:col-span-8 order-2 md:order-2">
···
23
{{ $s := index . 1 }}
24
<div class="py-4 px-6 rounded bg-white dark:bg-gray-800">
25
<div class="font-medium dark:text-white flex gap-2 items-center">
26
+
<a href="/strings/{{ resolve $root.Card.UserDid }}/{{ $s.Rkey }}">{{ $s.Filename }}</a>
27
</div>
28
{{ with $s.Description }}
29
<div class="text-gray-600 dark:text-gray-300 text-sm">
+16
-8
appview/pulls/pulls.go
+16
-8
appview/pulls/pulls.go
···
800
}
801
s.notifier.NewPullComment(r.Context(), comment, mentions)
802
803
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", f.OwnerSlashRepo(), pull.PullId, commentId))
804
return
805
}
806
}
···
1271
1272
s.notifier.NewPull(r.Context(), pull)
1273
1274
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pullId))
1275
}
1276
1277
func (s *Pulls) createStackedPullRequest(
···
1372
return
1373
}
1374
1375
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls", f.OwnerSlashRepo()))
1376
}
1377
1378
func (s *Pulls) ValidatePatch(w http.ResponseWriter, r *http.Request) {
···
1920
return
1921
}
1922
1923
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
1924
}
1925
1926
func (s *Pulls) resubmitStackedPullHelper(
···
2113
return
2114
}
2115
2116
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
2117
}
2118
2119
func (s *Pulls) MergePull(w http.ResponseWriter, r *http.Request) {
···
2231
s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2232
}
2233
2234
-
s.pages.HxLocation(w, fmt.Sprintf("/@%s/%s/pulls/%d", f.OwnerHandle(), f.Name, pull.PullId))
2235
}
2236
2237
func (s *Pulls) ClosePull(w http.ResponseWriter, r *http.Request) {
···
2303
s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2304
}
2305
2306
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
2307
}
2308
2309
func (s *Pulls) ReopenPull(w http.ResponseWriter, r *http.Request) {
···
2376
s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2377
}
2378
2379
-
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", f.OwnerSlashRepo(), pull.PullId))
2380
}
2381
2382
func newStack(f *reporesolver.ResolvedRepo, user *oauth.User, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) {
···
800
}
801
s.notifier.NewPullComment(r.Context(), comment, mentions)
802
803
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
804
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d#comment-%d", ownerSlashRepo, pull.PullId, commentId))
805
return
806
}
807
}
···
1272
1273
s.notifier.NewPull(r.Context(), pull)
1274
1275
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
1276
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pullId))
1277
}
1278
1279
func (s *Pulls) createStackedPullRequest(
···
1374
return
1375
}
1376
1377
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
1378
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls", ownerSlashRepo))
1379
}
1380
1381
func (s *Pulls) ValidatePatch(w http.ResponseWriter, r *http.Request) {
···
1923
return
1924
}
1925
1926
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
1927
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
1928
}
1929
1930
func (s *Pulls) resubmitStackedPullHelper(
···
2117
return
2118
}
2119
2120
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
2121
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2122
}
2123
2124
func (s *Pulls) MergePull(w http.ResponseWriter, r *http.Request) {
···
2236
s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2237
}
2238
2239
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
2240
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2241
}
2242
2243
func (s *Pulls) ClosePull(w http.ResponseWriter, r *http.Request) {
···
2309
s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2310
}
2311
2312
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
2313
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2314
}
2315
2316
func (s *Pulls) ReopenPull(w http.ResponseWriter, r *http.Request) {
···
2383
s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2384
}
2385
2386
+
ownerSlashRepo := s.repoResolver.GetBaseRepoPath(r, &f.Repo)
2387
+
s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2388
}
2389
2390
func newStack(f *reporesolver.ResolvedRepo, user *oauth.User, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) {
+3
-1
appview/repo/blob.go
+3
-1
appview/repo/blob.go
···
62
return
63
}
64
65
// Use XRPC response directly instead of converting to internal types
66
var breadcrumbs [][]string
67
-
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), url.PathEscape(ref))})
68
if filePath != "" {
69
for idx, elem := range strings.Split(filePath, "/") {
70
breadcrumbs = append(breadcrumbs, []string{elem, fmt.Sprintf("%s/%s", breadcrumbs[idx][1], url.PathEscape(elem))})
···
62
return
63
}
64
65
+
ownerSlashRepo := rp.repoResolver.GetBaseRepoPath(r, &f.Repo)
66
+
67
// Use XRPC response directly instead of converting to internal types
68
var breadcrumbs [][]string
69
+
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", ownerSlashRepo, url.PathEscape(ref))})
70
if filePath != "" {
71
for idx, elem := range strings.Split(filePath, "/") {
72
breadcrumbs = append(breadcrumbs, []string{elem, fmt.Sprintf("%s/%s", breadcrumbs[idx][1], url.PathEscape(elem))})
+3
-2
appview/repo/tree.go
+3
-2
appview/repo/tree.go
···
79
result.ReadmeFileName = xrpcResp.Readme.Filename
80
result.Readme = xrpcResp.Readme.Contents
81
}
82
// redirects tree paths trying to access a blob; in this case the result.Files is unpopulated,
83
// so we can safely redirect to the "parent" (which is the same file).
84
if len(result.Files) == 0 && result.Parent == treePath {
85
-
redirectTo := fmt.Sprintf("/%s/blob/%s/%s", f.OwnerSlashRepo(), url.PathEscape(ref), result.Parent)
86
http.Redirect(w, r, redirectTo, http.StatusFound)
87
return
88
}
89
user := rp.oauth.GetUser(r)
90
var breadcrumbs [][]string
91
-
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), url.PathEscape(ref))})
92
if treePath != "" {
93
for idx, elem := range strings.Split(treePath, "/") {
94
breadcrumbs = append(breadcrumbs, []string{elem, fmt.Sprintf("%s/%s", breadcrumbs[idx][1], url.PathEscape(elem))})
···
79
result.ReadmeFileName = xrpcResp.Readme.Filename
80
result.Readme = xrpcResp.Readme.Contents
81
}
82
+
ownerSlashRepo := rp.repoResolver.GetBaseRepoPath(r, &f.Repo)
83
// redirects tree paths trying to access a blob; in this case the result.Files is unpopulated,
84
// so we can safely redirect to the "parent" (which is the same file).
85
if len(result.Files) == 0 && result.Parent == treePath {
86
+
redirectTo := fmt.Sprintf("/%s/blob/%s/%s", ownerSlashRepo, url.PathEscape(ref), result.Parent)
87
http.Redirect(w, r, redirectTo, http.StatusFound)
88
return
89
}
90
user := rp.oauth.GetUser(r)
91
var breadcrumbs [][]string
92
+
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", ownerSlashRepo, url.PathEscape(ref))})
93
if treePath != "" {
94
for idx, elem := range strings.Split(treePath, "/") {
95
breadcrumbs = append(breadcrumbs, []string{elem, fmt.Sprintf("%s/%s", breadcrumbs[idx][1], url.PathEscape(elem))})
+12
-14
appview/reporesolver/resolver.go
+12
-14
appview/reporesolver/resolver.go
···
44
return &RepoResolver{config: config, enforcer: enforcer, idResolver: resolver, execer: execer}
45
}
46
47
func (rr *RepoResolver) Resolve(r *http.Request) (*ResolvedRepo, error) {
48
repo, ok := r.Context().Value("repo").(*models.Repo)
49
if !ok {
···
113
114
c := pages.Collaborator{
115
Did: did,
116
-
Handle: "",
117
Role: role,
118
}
119
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
}
134
135
return collaborators, nil
···
44
return &RepoResolver{config: config, enforcer: enforcer, idResolver: resolver, execer: execer}
45
}
46
47
+
// NOTE: this... should not even be here. the entire package will be removed in future refactor
48
+
func (rr *RepoResolver) GetBaseRepoPath(r *http.Request, repo *models.Repo) string {
49
+
var (
50
+
user = chi.URLParam(r, "user")
51
+
name = chi.URLParam(r, "repo")
52
+
)
53
+
if user == "" || name == "" {
54
+
return repo.DidSlashRepo()
55
+
}
56
+
return path.Join(user, name)
57
+
}
58
+
59
func (rr *RepoResolver) Resolve(r *http.Request) (*ResolvedRepo, error) {
60
repo, ok := r.Context().Value("repo").(*models.Repo)
61
if !ok {
···
125
126
c := pages.Collaborator{
127
Did: did,
128
Role: role,
129
}
130
collaborators = append(collaborators, c)
131
}
132
133
return collaborators, nil
+5
-6
appview/state/profile.go
+5
-6
appview/state/profile.go
···
96
97
return &pages.ProfileCard{
98
UserDid: did,
99
-
UserHandle: ident.Handle.String(),
100
Profile: profile,
101
FollowStatus: followStatus,
102
Stats: pages.ProfileStats{
···
119
s.pages.Error500(w)
120
return
121
}
122
-
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
123
124
repos, err := db.GetRepos(
125
s.db,
···
180
s.pages.Error500(w)
181
return
182
}
183
-
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
184
185
repos, err := db.GetRepos(
186
s.db,
···
209
s.pages.Error500(w)
210
return
211
}
212
-
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
213
214
stars, err := db.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid))
215
if err != nil {
···
240
s.pages.Error500(w)
241
return
242
}
243
-
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
244
245
strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid))
246
if err != nil {
···
272
if err != nil {
273
return nil, err
274
}
275
-
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
276
277
loggedInUser := s.oauth.GetUser(r)
278
params := FollowsPageParams{
···
96
97
return &pages.ProfileCard{
98
UserDid: did,
99
Profile: profile,
100
FollowStatus: followStatus,
101
Stats: pages.ProfileStats{
···
118
s.pages.Error500(w)
119
return
120
}
121
+
l = l.With("profileDid", profile.UserDid)
122
123
repos, err := db.GetRepos(
124
s.db,
···
179
s.pages.Error500(w)
180
return
181
}
182
+
l = l.With("profileDid", profile.UserDid)
183
184
repos, err := db.GetRepos(
185
s.db,
···
208
s.pages.Error500(w)
209
return
210
}
211
+
l = l.With("profileDid", profile.UserDid)
212
213
stars, err := db.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid))
214
if err != nil {
···
239
s.pages.Error500(w)
240
return
241
}
242
+
l = l.With("profileDid", profile.UserDid)
243
244
strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid))
245
if err != nil {
···
271
if err != nil {
272
return nil, err
273
}
274
+
l = l.With("profileDid", profile.UserDid)
275
276
loggedInUser := s.oauth.GetUser(r)
277
params := FollowsPageParams{
+1
-1
types/repo.go
+1
-1
types/repo.go