+5
-8
appview/db/issues.go
+5
-8
appview/db/issues.go
···
101
pLower := FilterGte("row_num", page.Offset+1)
102
pUpper := FilterLte("row_num", page.Offset+page.Limit)
103
104
-
pageClause := ""
105
-
if page.Limit > 0 {
106
-
args = append(args, pLower.Arg()...)
107
-
args = append(args, pUpper.Arg()...)
108
-
pageClause = " where " + pLower.Condition() + " and " + pUpper.Condition()
109
-
}
110
111
query := fmt.Sprintf(
112
`
···
131
%s
132
`,
133
whereClause,
134
-
pageClause,
135
)
136
137
rows, err := e.Query(query, args...)
···
247
}
248
249
func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) {
250
-
return GetIssuesPaginated(e, pagination.Page{}, filters...)
251
}
252
253
func AddIssueComment(e Execer, c models.IssueComment) (int64, error) {
···
101
pLower := FilterGte("row_num", page.Offset+1)
102
pUpper := FilterLte("row_num", page.Offset+page.Limit)
103
104
+
args = append(args, pLower.Arg()...)
105
+
args = append(args, pUpper.Arg()...)
106
+
pagination := " where " + pLower.Condition() + " and " + pUpper.Condition()
107
108
query := fmt.Sprintf(
109
`
···
128
%s
129
`,
130
whereClause,
131
+
pagination,
132
)
133
134
rows, err := e.Query(query, args...)
···
244
}
245
246
func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) {
247
+
return GetIssuesPaginated(e, pagination.FirstPage(), filters...)
248
}
249
250
func AddIssueComment(e Execer, c models.IssueComment) (int64, error) {
+4
-7
appview/db/notifications.go
+4
-7
appview/db/notifications.go
···
60
whereClause += " AND " + condition
61
}
62
}
63
-
pageClause := ""
64
-
if page.Limit > 0 {
65
-
pageClause = " limit ? offset ? "
66
-
args = append(args, page.Limit, page.Offset)
67
-
}
68
69
query := fmt.Sprintf(`
70
select id, recipient_did, actor_did, type, entity_type, entity_id, read, created, repo_id, issue_id, pull_id
71
from notifications
72
%s
73
order by created desc
74
-
%s
75
-
`, whereClause, pageClause)
76
77
rows, err := e.QueryContext(context.Background(), query, args...)
78
if err != nil {
···
60
whereClause += " AND " + condition
61
}
62
}
63
64
query := fmt.Sprintf(`
65
select id, recipient_did, actor_did, type, entity_type, entity_id, read, created, repo_id, issue_id, pull_id
66
from notifications
67
%s
68
order by created desc
69
+
limit ? offset ?
70
+
`, whereClause)
71
+
72
+
args = append(args, page.Limit, page.Offset)
73
74
rows, err := e.QueryContext(context.Background(), query, args...)
75
if err != nil {
+41
-13
appview/issues/issues.go
+41
-13
appview/issues/issues.go
···
78
issue, ok := r.Context().Value("issue").(*models.Issue)
79
if !ok {
80
l.Error("failed to get issue")
81
-
rp.pages.Error404(w)
82
return
83
}
84
···
99
)
100
if err != nil {
101
l.Error("failed to fetch labels", "err", err)
102
-
rp.pages.Error503(w)
103
return
104
}
105
···
132
issue, ok := r.Context().Value("issue").(*models.Issue)
133
if !ok {
134
l.Error("failed to get issue")
135
-
rp.pages.Error404(w)
136
return
137
}
138
···
275
issue, ok := r.Context().Value("issue").(*models.Issue)
276
if !ok {
277
l.Error("failed to get issue")
278
-
rp.pages.Error404(w)
279
return
280
}
281
···
324
issue, ok := r.Context().Value("issue").(*models.Issue)
325
if !ok {
326
l.Error("failed to get issue")
327
-
rp.pages.Error404(w)
328
return
329
}
330
···
368
issue, ok := r.Context().Value("issue").(*models.Issue)
369
if !ok {
370
l.Error("failed to get issue")
371
-
rp.pages.Error404(w)
372
return
373
}
374
···
456
issue, ok := r.Context().Value("issue").(*models.Issue)
457
if !ok {
458
l.Error("failed to get issue")
459
-
rp.pages.Error404(w)
460
return
461
}
462
···
497
issue, ok := r.Context().Value("issue").(*models.Issue)
498
if !ok {
499
l.Error("failed to get issue")
500
-
rp.pages.Error404(w)
501
return
502
}
503
···
601
issue, ok := r.Context().Value("issue").(*models.Issue)
602
if !ok {
603
l.Error("failed to get issue")
604
-
rp.pages.Error404(w)
605
return
606
}
607
···
642
issue, ok := r.Context().Value("issue").(*models.Issue)
643
if !ok {
644
l.Error("failed to get issue")
645
-
rp.pages.Error404(w)
646
return
647
}
648
···
683
issue, ok := r.Context().Value("issue").(*models.Issue)
684
if !ok {
685
l.Error("failed to get issue")
686
-
rp.pages.Error404(w)
687
return
688
}
689
···
770
isOpen = true
771
}
772
773
-
page := pagination.FromContext(r.Context())
774
775
user := rp.oauth.GetUser(r)
776
f, err := rp.repoResolver.Resolve(r)
···
802
)
803
if err != nil {
804
l.Error("failed to fetch labels", "err", err)
805
-
rp.pages.Error503(w)
806
return
807
}
808
···
78
issue, ok := r.Context().Value("issue").(*models.Issue)
79
if !ok {
80
l.Error("failed to get issue")
81
+
rp.pages.Error404(w, pages.ErrorPageParams{
82
+
LoggedInUser: user,
83
+
})
84
return
85
}
86
···
101
)
102
if err != nil {
103
l.Error("failed to fetch labels", "err", err)
104
+
rp.pages.Error503(w, pages.ErrorPageParams{
105
+
LoggedInUser: user,
106
+
})
107
return
108
}
109
···
136
issue, ok := r.Context().Value("issue").(*models.Issue)
137
if !ok {
138
l.Error("failed to get issue")
139
+
rp.pages.Error404(w, pages.ErrorPageParams{
140
+
LoggedInUser: user,
141
+
})
142
return
143
}
144
···
281
issue, ok := r.Context().Value("issue").(*models.Issue)
282
if !ok {
283
l.Error("failed to get issue")
284
+
rp.pages.Error404(w, pages.ErrorPageParams{
285
+
LoggedInUser: user,
286
+
})
287
return
288
}
289
···
332
issue, ok := r.Context().Value("issue").(*models.Issue)
333
if !ok {
334
l.Error("failed to get issue")
335
+
rp.pages.Error404(w, pages.ErrorPageParams{
336
+
LoggedInUser: user,
337
+
})
338
return
339
}
340
···
378
issue, ok := r.Context().Value("issue").(*models.Issue)
379
if !ok {
380
l.Error("failed to get issue")
381
+
rp.pages.Error404(w, pages.ErrorPageParams{
382
+
LoggedInUser: user,
383
+
})
384
return
385
}
386
···
468
issue, ok := r.Context().Value("issue").(*models.Issue)
469
if !ok {
470
l.Error("failed to get issue")
471
+
rp.pages.Error404(w, pages.ErrorPageParams{
472
+
LoggedInUser: user,
473
+
})
474
return
475
}
476
···
511
issue, ok := r.Context().Value("issue").(*models.Issue)
512
if !ok {
513
l.Error("failed to get issue")
514
+
rp.pages.Error404(w, pages.ErrorPageParams{
515
+
LoggedInUser: user,
516
+
})
517
return
518
}
519
···
617
issue, ok := r.Context().Value("issue").(*models.Issue)
618
if !ok {
619
l.Error("failed to get issue")
620
+
rp.pages.Error404(w, pages.ErrorPageParams{
621
+
LoggedInUser: user,
622
+
})
623
return
624
}
625
···
660
issue, ok := r.Context().Value("issue").(*models.Issue)
661
if !ok {
662
l.Error("failed to get issue")
663
+
rp.pages.Error404(w, pages.ErrorPageParams{
664
+
LoggedInUser: user,
665
+
})
666
return
667
}
668
···
703
issue, ok := r.Context().Value("issue").(*models.Issue)
704
if !ok {
705
l.Error("failed to get issue")
706
+
rp.pages.Error404(w, pages.ErrorPageParams{
707
+
LoggedInUser: user,
708
+
})
709
return
710
}
711
···
792
isOpen = true
793
}
794
795
+
page, ok := r.Context().Value("page").(pagination.Page)
796
+
if !ok {
797
+
l.Error("failed to get page")
798
+
page = pagination.FirstPage()
799
+
}
800
801
user := rp.oauth.GetUser(r)
802
f, err := rp.repoResolver.Resolve(r)
···
828
)
829
if err != nil {
830
l.Error("failed to fetch labels", "err", err)
831
+
rp.pages.Error503(w, pages.ErrorPageParams{
832
+
LoggedInUser: user,
833
+
})
834
return
835
}
836
+21
-7
appview/middleware/middleware.go
+21
-7
appview/middleware/middleware.go
···
105
}
106
}
107
108
-
ctx := pagination.IntoContext(r.Context(), page)
109
next.ServeHTTP(w, r.WithContext(ctx))
110
})
111
}
···
191
if err != nil {
192
// invalid did or handle
193
log.Printf("failed to resolve did/handle '%s': %s\n", didOrHandle, err)
194
-
mw.pages.Error404(w)
195
return
196
}
197
···
206
return func(next http.Handler) http.Handler {
207
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
208
repoName := chi.URLParam(req, "repo")
209
id, ok := req.Context().Value("resolvedId").(identity.Identity)
210
if !ok {
211
log.Println("malformed middleware")
···
220
)
221
if err != nil {
222
log.Println("failed to resolve repo", "err", err)
223
-
mw.pages.ErrorKnot404(w)
224
return
225
}
226
···
235
return func(next http.Handler) http.Handler {
236
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
237
f, err := mw.repoResolver.Resolve(r)
238
if err != nil {
239
log.Println("failed to fully resolve repo", err)
240
-
mw.pages.ErrorKnot404(w)
241
return
242
}
243
···
282
func (mw Middleware) ResolveIssue(next http.Handler) http.Handler {
283
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
284
f, err := mw.repoResolver.Resolve(r)
285
if err != nil {
286
log.Println("failed to fully resolve repo", err)
287
-
mw.pages.ErrorKnot404(w)
288
return
289
}
290
···
292
issueId, err := strconv.Atoi(issueIdStr)
293
if err != nil {
294
log.Println("failed to fully resolve issue ID", err)
295
-
mw.pages.ErrorKnot404(w)
296
return
297
}
298
···
326
return func(next http.Handler) http.Handler {
327
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
328
f, err := mw.repoResolver.Resolve(r)
329
if err != nil {
330
log.Println("failed to fully resolve repo", err)
331
-
mw.pages.ErrorKnot404(w)
332
return
333
}
334
···
105
}
106
}
107
108
+
ctx := context.WithValue(r.Context(), "page", page)
109
next.ServeHTTP(w, r.WithContext(ctx))
110
})
111
}
···
191
if err != nil {
192
// invalid did or handle
193
log.Printf("failed to resolve did/handle '%s': %s\n", didOrHandle, err)
194
+
mw.pages.Error404(w, pages.ErrorPageParams{})
195
return
196
}
197
···
206
return func(next http.Handler) http.Handler {
207
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
208
repoName := chi.URLParam(req, "repo")
209
+
user := mw.oauth.GetUser(req)
210
id, ok := req.Context().Value("resolvedId").(identity.Identity)
211
if !ok {
212
log.Println("malformed middleware")
···
221
)
222
if err != nil {
223
log.Println("failed to resolve repo", "err", err)
224
+
mw.pages.ErrorKnot404(w, pages.ErrorPageParams{
225
+
LoggedInUser: user,
226
+
})
227
return
228
}
229
···
238
return func(next http.Handler) http.Handler {
239
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
240
f, err := mw.repoResolver.Resolve(r)
241
+
user := mw.oauth.GetUser(r)
242
if err != nil {
243
log.Println("failed to fully resolve repo", err)
244
+
mw.pages.ErrorKnot404(w, pages.ErrorPageParams{
245
+
LoggedInUser: user,
246
+
})
247
return
248
}
249
···
288
func (mw Middleware) ResolveIssue(next http.Handler) http.Handler {
289
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
290
f, err := mw.repoResolver.Resolve(r)
291
+
user := mw.oauth.GetUser(r)
292
if err != nil {
293
log.Println("failed to fully resolve repo", err)
294
+
mw.pages.ErrorKnot404(w, pages.ErrorPageParams{
295
+
LoggedInUser: user,
296
+
})
297
return
298
}
299
···
301
issueId, err := strconv.Atoi(issueIdStr)
302
if err != nil {
303
log.Println("failed to fully resolve issue ID", err)
304
+
mw.pages.ErrorKnot404(w, pages.ErrorPageParams{
305
+
LoggedInUser: user,
306
+
})
307
return
308
}
309
···
337
return func(next http.Handler) http.Handler {
338
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
339
f, err := mw.repoResolver.Resolve(r)
340
+
user := mw.oauth.GetUser(r)
341
if err != nil {
342
log.Println("failed to fully resolve repo", err)
343
+
mw.pages.ErrorKnot404(w, pages.ErrorPageParams{
344
+
LoggedInUser: user,
345
+
})
346
return
347
}
348
+11
-3
appview/notifications/notifications.go
+11
-3
appview/notifications/notifications.go
···
49
l := n.logger.With("handler", "notificationsPage")
50
user := n.oauth.GetUser(r)
51
52
-
page := pagination.FromContext(r.Context())
53
54
total, err := db.CountNotifications(
55
n.db,
···
57
)
58
if err != nil {
59
l.Error("failed to get total notifications", "err", err)
60
-
n.pages.Error500(w)
61
return
62
}
63
···
68
)
69
if err != nil {
70
l.Error("failed to get notifications", "err", err)
71
-
n.pages.Error500(w)
72
return
73
}
74
···
49
l := n.logger.With("handler", "notificationsPage")
50
user := n.oauth.GetUser(r)
51
52
+
page, ok := r.Context().Value("page").(pagination.Page)
53
+
if !ok {
54
+
l.Error("failed to get page")
55
+
page = pagination.FirstPage()
56
+
}
57
58
total, err := db.CountNotifications(
59
n.db,
···
61
)
62
if err != nil {
63
l.Error("failed to get total notifications", "err", err)
64
+
n.pages.Error500(w, pages.ErrorPageParams{
65
+
LoggedInUser: user,
66
+
})
67
return
68
}
69
···
74
)
75
if err != nil {
76
l.Error("failed to get notifications", "err", err)
77
+
n.pages.Error500(w, pages.ErrorPageParams{
78
+
LoggedInUser: user,
79
+
})
80
return
81
}
82
+2
-13
appview/oauth/handler.go
+2
-13
appview/oauth/handler.go
···
4
"bytes"
5
"context"
6
"encoding/json"
7
-
"errors"
8
"fmt"
9
"net/http"
10
"slices"
11
"time"
12
13
-
"github.com/bluesky-social/indigo/atproto/auth/oauth"
14
"github.com/go-chi/chi/v5"
15
"github.com/lestrrat-go/jwx/v2/jwk"
16
"github.com/posthog/posthog-go"
···
60
61
func (o *OAuth) callback(w http.ResponseWriter, r *http.Request) {
62
ctx := r.Context()
63
-
l := o.Logger.With("query", r.URL.Query())
64
65
sessData, err := o.ClientApp.ProcessCallback(ctx, r.URL.Query())
66
if err != nil {
67
-
var callbackErr *oauth.AuthRequestCallbackError
68
-
if errors.As(err, &callbackErr) {
69
-
l.Debug("callback error", "err", callbackErr)
70
-
http.Redirect(w, r, fmt.Sprintf("/login?error=%s", callbackErr.ErrorCode), http.StatusFound)
71
-
return
72
-
}
73
-
l.Error("failed to process callback", "err", err)
74
-
http.Redirect(w, r, "/login?error=oauth", http.StatusFound)
75
return
76
}
77
78
if err := o.SaveSession(w, r, sessData); err != nil {
79
-
l.Error("failed to save session", "data", sessData, "err", err)
80
-
http.Redirect(w, r, "/login?error=session", http.StatusFound)
81
return
82
}
83
···
4
"bytes"
5
"context"
6
"encoding/json"
7
"fmt"
8
"net/http"
9
"slices"
10
"time"
11
12
"github.com/go-chi/chi/v5"
13
"github.com/lestrrat-go/jwx/v2/jwk"
14
"github.com/posthog/posthog-go"
···
58
59
func (o *OAuth) callback(w http.ResponseWriter, r *http.Request) {
60
ctx := r.Context()
61
62
sessData, err := o.ClientApp.ProcessCallback(ctx, r.URL.Query())
63
if err != nil {
64
+
http.Error(w, err.Error(), http.StatusInternalServerError)
65
return
66
}
67
68
if err := o.SaveSession(w, r, sessData); err != nil {
69
+
http.Error(w, err.Error(), http.StatusInternalServerError)
70
return
71
}
72
+1
-4
appview/oauth/oauth.go
+1
-4
appview/oauth/oauth.go
+2
-3
appview/pages/funcmap.go
+2
-3
appview/pages/funcmap.go
···
297
},
298
299
"normalizeForHtmlId": func(s string) string {
300
-
normalized := strings.ReplaceAll(s, ":", "_")
301
-
normalized = strings.ReplaceAll(normalized, ".", "_")
302
-
return normalized
303
},
304
"sshFingerprint": func(pubKey string) string {
305
fp, err := crypto.SSHFingerprint(pubKey)
+12
-9
appview/pages/pages.go
+12
-9
appview/pages/pages.go
···
221
222
type LoginParams struct {
223
ReturnUrl string
224
-
ErrorCode string
225
}
226
227
func (p *Pages) Login(w io.Writer, params LoginParams) error {
···
1382
Active string
1383
}
1384
1385
func (p *Pages) Workflow(w io.Writer, params WorkflowParams) error {
1386
params.Active = "pipelines"
1387
return p.executeRepo("repo/pipelines/workflow", w, params)
···
1519
return hex.EncodeToString(hasher.Sum(nil))[:8] // Use first 8 chars of hash
1520
}
1521
1522
-
func (p *Pages) Error500(w io.Writer) error {
1523
-
return p.execute("errors/500", w, nil)
1524
}
1525
1526
-
func (p *Pages) Error404(w io.Writer) error {
1527
-
return p.execute("errors/404", w, nil)
1528
}
1529
1530
-
func (p *Pages) ErrorKnot404(w io.Writer) error {
1531
-
return p.execute("errors/knot404", w, nil)
1532
}
1533
1534
-
func (p *Pages) Error503(w io.Writer) error {
1535
-
return p.execute("errors/503", w, nil)
1536
}
···
221
222
type LoginParams struct {
223
ReturnUrl string
224
}
225
226
func (p *Pages) Login(w io.Writer, params LoginParams) error {
···
1381
Active string
1382
}
1383
1384
+
type ErrorPageParams struct {
1385
+
LoggedInUser *oauth.User
1386
+
}
1387
+
1388
func (p *Pages) Workflow(w io.Writer, params WorkflowParams) error {
1389
params.Active = "pipelines"
1390
return p.executeRepo("repo/pipelines/workflow", w, params)
···
1522
return hex.EncodeToString(hasher.Sum(nil))[:8] // Use first 8 chars of hash
1523
}
1524
1525
+
func (p *Pages) Error500(w io.Writer, params ErrorPageParams) error {
1526
+
return p.execute("errors/500", w, params)
1527
}
1528
1529
+
func (p *Pages) Error404(w io.Writer, params ErrorPageParams) error {
1530
+
return p.execute("errors/404", w, params)
1531
}
1532
1533
+
func (p *Pages) ErrorKnot404(w io.Writer, params ErrorPageParams) error {
1534
+
return p.execute("errors/knot404", w, params)
1535
}
1536
1537
+
func (p *Pages) Error503(w io.Writer, params ErrorPageParams) error {
1538
+
return p.execute("errors/503", w, params)
1539
}
+1
-1
appview/pages/templates/strings/string.html
+1
-1
appview/pages/templates/strings/string.html
···
47
</span>
48
</section>
49
<section class="bg-white dark:bg-gray-800 px-6 py-4 rounded relative w-full dark:text-white">
50
-
<div class="flex flex-col md:flex-row md:justify-between md:items-center text-gray-500 dark:text-gray-400 text-sm md:text-base pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
51
<span>
52
{{ .String.Filename }}
53
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
···
47
</span>
48
</section>
49
<section class="bg-white dark:bg-gray-800 px-6 py-4 rounded relative w-full dark:text-white">
50
+
<div class="flex justify-between items-center text-gray-500 dark:text-gray-400 text-sm md:text-base pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
51
<span>
52
{{ .String.Filename }}
53
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
+1
-1
appview/pages/templates/user/fragments/followCard.html
+1
-1
appview/pages/templates/user/fragments/followCard.html
···
3
<div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 rounded-sm">
4
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4">
5
<div class="flex-shrink-0 max-h-full w-24 h-24">
6
-
<img class="object-cover rounded-full p-2" src="{{ fullAvatar $userIdent }}" alt="{{ $userIdent }}" />
7
</div>
8
9
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 w-full">
···
3
<div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 rounded-sm">
4
<div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4">
5
<div class="flex-shrink-0 max-h-full w-24 h-24">
6
+
<img class="object-cover rounded-full p-2" src="{{ fullAvatar $userIdent }}" />
7
</div>
8
9
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 w-full">
+2
-20
appview/pages/templates/user/login.html
+2
-20
appview/pages/templates/user/login.html
···
13
<title>login · tangled</title>
14
</head>
15
<body class="flex items-center justify-center min-h-screen">
16
-
<main class="max-w-md px-7 mt-4">
17
<h1 class="flex place-content-center text-3xl font-semibold italic dark:text-white" >
18
{{ template "fragments/logotype" }}
19
</h1>
···
21
tightly-knit social coding.
22
</h2>
23
<form
24
-
class="mt-4"
25
hx-post="/login"
26
hx-swap="none"
27
hx-disabled-elt="#login-button"
···
56
<span>login</span>
57
</button>
58
</form>
59
-
{{ if .ErrorCode }}
60
-
<div class="flex gap-2 my-2 bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-3 py-2 text-red-500 dark:text-red-300">
61
-
<span class="py-1">{{ i "circle-alert" "w-4 h-4" }}</span>
62
-
<div>
63
-
<h5 class="font-medium">Login error</h5>
64
-
<p class="text-sm">
65
-
{{ if eq .ErrorCode "access_denied" }}
66
-
You have not authorized the app.
67
-
{{ else if eq .ErrorCode "session" }}
68
-
Server failed to create user session.
69
-
{{ else }}
70
-
Internal Server error.
71
-
{{ end }}
72
-
Please try again.
73
-
</p>
74
-
</div>
75
-
</div>
76
-
{{ end }}
77
<p class="text-sm text-gray-500">
78
Don't have an account? <a href="/signup" class="underline">Create an account</a> on Tangled now!
79
</p>
···
13
<title>login · tangled</title>
14
</head>
15
<body class="flex items-center justify-center min-h-screen">
16
+
<main class="max-w-md px-6 -mt-4">
17
<h1 class="flex place-content-center text-3xl font-semibold italic dark:text-white" >
18
{{ template "fragments/logotype" }}
19
</h1>
···
21
tightly-knit social coding.
22
</h2>
23
<form
24
+
class="mt-4 max-w-sm mx-auto"
25
hx-post="/login"
26
hx-swap="none"
27
hx-disabled-elt="#login-button"
···
56
<span>login</span>
57
</button>
58
</form>
59
<p class="text-sm text-gray-500">
60
Don't have an account? <a href="/signup" class="underline">Create an account</a> on Tangled now!
61
</p>
-23
appview/pagination/page.go
-23
appview/pagination/page.go
···
1
package pagination
2
3
-
import "context"
4
-
5
type Page struct {
6
Offset int // where to start from
7
Limit int // number of items in a page
···
12
Offset: 0,
13
Limit: 30,
14
}
15
-
}
16
-
17
-
type ctxKey struct{}
18
-
19
-
func IntoContext(ctx context.Context, page Page) context.Context {
20
-
return context.WithValue(ctx, ctxKey{}, page)
21
-
}
22
-
23
-
func FromContext(ctx context.Context) Page {
24
-
if ctx == nil {
25
-
return FirstPage()
26
-
}
27
-
v := ctx.Value(ctxKey{})
28
-
if v == nil {
29
-
return FirstPage()
30
-
}
31
-
page, ok := v.(Page)
32
-
if !ok {
33
-
return FirstPage()
34
-
}
35
-
return page
36
}
37
38
func (p Page) Previous() Page {
+30
-10
appview/pulls/pulls.go
+30
-10
appview/pulls/pulls.go
···
205
)
206
if err != nil {
207
log.Println("failed to fetch labels", err)
208
-
s.pages.Error503(w)
209
return
210
}
211
···
636
)
637
if err != nil {
638
log.Println("failed to fetch labels", err)
639
-
s.pages.Error503(w)
640
return
641
}
642
···
785
if err != nil {
786
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
787
log.Println("failed to call XRPC repo.branches", xrpcerr)
788
-
s.pages.Error503(w)
789
return
790
}
791
log.Println("failed to fetch branches", err)
···
795
var result types.RepoBranchesResponse
796
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
797
log.Println("failed to decode XRPC response", err)
798
-
s.pages.Error503(w)
799
return
800
}
801
···
1392
if err != nil {
1393
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1394
log.Println("failed to call XRPC repo.branches", xrpcerr)
1395
-
s.pages.Error503(w)
1396
return
1397
}
1398
log.Println("failed to fetch branches", err)
···
1402
var result types.RepoBranchesResponse
1403
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1404
log.Println("failed to decode XRPC response", err)
1405
-
s.pages.Error503(w)
1406
return
1407
}
1408
···
1484
if err != nil {
1485
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1486
log.Println("failed to call XRPC repo.branches for source", xrpcerr)
1487
-
s.pages.Error503(w)
1488
return
1489
}
1490
log.Println("failed to fetch source branches", err)
···
1495
var sourceBranches types.RepoBranchesResponse
1496
if err := json.Unmarshal(sourceXrpcBytes, &sourceBranches); err != nil {
1497
log.Println("failed to decode source branches XRPC response", err)
1498
-
s.pages.Error503(w)
1499
return
1500
}
1501
···
1513
if err != nil {
1514
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1515
log.Println("failed to call XRPC repo.branches for target", xrpcerr)
1516
-
s.pages.Error503(w)
1517
return
1518
}
1519
log.Println("failed to fetch target branches", err)
···
1524
var targetBranches types.RepoBranchesResponse
1525
if err := json.Unmarshal(targetXrpcBytes, &targetBranches); err != nil {
1526
log.Println("failed to decode target branches XRPC response", err)
1527
-
s.pages.Error503(w)
1528
return
1529
}
1530
···
205
)
206
if err != nil {
207
log.Println("failed to fetch labels", err)
208
+
s.pages.Error503(w, pages.ErrorPageParams{
209
+
LoggedInUser: user,
210
+
})
211
return
212
}
213
···
638
)
639
if err != nil {
640
log.Println("failed to fetch labels", err)
641
+
s.pages.Error503(w, pages.ErrorPageParams{
642
+
LoggedInUser: user,
643
+
})
644
return
645
}
646
···
789
if err != nil {
790
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
791
log.Println("failed to call XRPC repo.branches", xrpcerr)
792
+
s.pages.Error503(w, pages.ErrorPageParams{
793
+
LoggedInUser: user,
794
+
})
795
return
796
}
797
log.Println("failed to fetch branches", err)
···
801
var result types.RepoBranchesResponse
802
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
803
log.Println("failed to decode XRPC response", err)
804
+
s.pages.Error503(w, pages.ErrorPageParams{
805
+
LoggedInUser: user,
806
+
})
807
return
808
}
809
···
1400
if err != nil {
1401
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1402
log.Println("failed to call XRPC repo.branches", xrpcerr)
1403
+
s.pages.Error503(w, pages.ErrorPageParams{
1404
+
LoggedInUser: user,
1405
+
})
1406
return
1407
}
1408
log.Println("failed to fetch branches", err)
···
1412
var result types.RepoBranchesResponse
1413
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1414
log.Println("failed to decode XRPC response", err)
1415
+
s.pages.Error503(w, pages.ErrorPageParams{
1416
+
LoggedInUser: user,
1417
+
})
1418
return
1419
}
1420
···
1496
if err != nil {
1497
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1498
log.Println("failed to call XRPC repo.branches for source", xrpcerr)
1499
+
s.pages.Error503(w, pages.ErrorPageParams{
1500
+
LoggedInUser: user,
1501
+
})
1502
return
1503
}
1504
log.Println("failed to fetch source branches", err)
···
1509
var sourceBranches types.RepoBranchesResponse
1510
if err := json.Unmarshal(sourceXrpcBytes, &sourceBranches); err != nil {
1511
log.Println("failed to decode source branches XRPC response", err)
1512
+
s.pages.Error503(w, pages.ErrorPageParams{
1513
+
LoggedInUser: user,
1514
+
})
1515
return
1516
}
1517
···
1529
if err != nil {
1530
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1531
log.Println("failed to call XRPC repo.branches for target", xrpcerr)
1532
+
s.pages.Error503(w, pages.ErrorPageParams{
1533
+
LoggedInUser: user,
1534
+
})
1535
return
1536
}
1537
log.Println("failed to fetch target branches", err)
···
1542
var targetBranches types.RepoBranchesResponse
1543
if err := json.Unmarshal(targetXrpcBytes, &targetBranches); err != nil {
1544
log.Println("failed to decode target branches XRPC response", err)
1545
+
s.pages.Error503(w, pages.ErrorPageParams{
1546
+
LoggedInUser: user,
1547
+
})
1548
return
1549
}
1550
+8
-2
appview/repo/feed.go
+8
-2
appview/repo/feed.go
···
10
11
"tangled.org/core/appview/db"
12
"tangled.org/core/appview/models"
13
"tangled.org/core/appview/pagination"
14
"tangled.org/core/appview/reporesolver"
15
···
152
log.Println("failed to fully resolve repo:", err)
153
return
154
}
155
156
feed, err := rp.getRepoFeed(r.Context(), f)
157
if err != nil {
158
log.Println("failed to get repo feed:", err)
159
-
rp.pages.Error500(w)
160
return
161
}
162
163
atom, err := feed.ToAtom()
164
if err != nil {
165
-
rp.pages.Error500(w)
166
return
167
}
168
···
10
11
"tangled.org/core/appview/db"
12
"tangled.org/core/appview/models"
13
+
"tangled.org/core/appview/pages"
14
"tangled.org/core/appview/pagination"
15
"tangled.org/core/appview/reporesolver"
16
···
153
log.Println("failed to fully resolve repo:", err)
154
return
155
}
156
+
user := rp.oauth.GetUser(r)
157
158
feed, err := rp.getRepoFeed(r.Context(), f)
159
if err != nil {
160
log.Println("failed to get repo feed:", err)
161
+
rp.pages.Error500(w, pages.ErrorPageParams{
162
+
LoggedInUser: user,
163
+
})
164
return
165
}
166
167
atom, err := feed.ToAtom()
168
if err != nil {
169
+
rp.pages.Error500(w, pages.ErrorPageParams{
170
+
LoggedInUser: user,
171
+
})
172
return
173
}
174
+3
-1
appview/repo/index.go
+3
-1
appview/repo/index.go
+83
-34
appview/repo/repo.go
+83
-34
appview/repo/repo.go
···
90
91
func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) {
92
l := rp.logger.With("handler", "DownloadArchive")
93
94
ref := chi.URLParam(r, "ref")
95
ref, _ = url.PathUnescape(ref)
···
113
archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo)
114
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
115
l.Error("failed to call XRPC repo.archive", "err", xrpcerr)
116
-
rp.pages.Error503(w)
117
return
118
}
119
···
130
131
func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) {
132
l := rp.logger.With("handler", "RepoLog")
133
134
f, err := rp.repoResolver.Resolve(r)
135
if err != nil {
···
169
xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo)
170
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
171
l.Error("failed to call XRPC repo.log", "err", xrpcerr)
172
-
rp.pages.Error503(w)
173
return
174
}
175
176
var xrpcResp types.RepoLogResponse
177
if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil {
178
l.Error("failed to decode XRPC response", "err", err)
179
-
rp.pages.Error503(w)
180
return
181
}
182
183
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
184
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
185
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
186
-
rp.pages.Error503(w)
187
return
188
}
189
···
204
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
205
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
206
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
207
-
rp.pages.Error503(w)
208
return
209
}
210
···
216
}
217
}
218
}
219
-
220
-
user := rp.oauth.GetUser(r)
221
222
emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true)
223
if err != nil {
···
353
354
func (rp *Repo) RepoCommit(w http.ResponseWriter, r *http.Request) {
355
l := rp.logger.With("handler", "RepoCommit")
356
357
f, err := rp.repoResolver.Resolve(r)
358
if err != nil {
···
368
}
369
370
if !plumbing.IsHash(ref) {
371
-
rp.pages.Error404(w)
372
return
373
}
374
···
385
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo)
386
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
387
l.Error("failed to call XRPC repo.diff", "err", xrpcerr)
388
-
rp.pages.Error503(w)
389
return
390
}
391
392
var result types.RepoCommitResponse
393
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
394
l.Error("failed to decode XRPC response", "err", err)
395
-
rp.pages.Error503(w)
396
return
397
}
398
···
406
l.Error("failed to GetVerifiedCommits", "err", err)
407
}
408
409
-
user := rp.oauth.GetUser(r)
410
repoInfo := f.RepoInfo(user)
411
pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This})
412
if err != nil {
···
431
432
func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) {
433
l := rp.logger.With("handler", "RepoTree")
434
435
f, err := rp.repoResolver.Resolve(r)
436
if err != nil {
···
460
xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo)
461
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
462
l.Error("failed to call XRPC repo.tree", "err", xrpcerr)
463
-
rp.pages.Error503(w)
464
return
465
}
466
···
511
http.Redirect(w, r, redirectTo, http.StatusFound)
512
return
513
}
514
-
515
-
user := rp.oauth.GetUser(r)
516
517
var breadcrumbs [][]string
518
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), url.PathEscape(ref))})
···
535
536
func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) {
537
l := rp.logger.With("handler", "RepoTags")
538
539
f, err := rp.repoResolver.Resolve(r)
540
if err != nil {
···
555
xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
556
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
557
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
558
-
rp.pages.Error503(w)
559
return
560
}
561
562
var result types.RepoTagsResponse
563
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
564
l.Error("failed to decode XRPC response", "err", err)
565
-
rp.pages.Error503(w)
566
return
567
}
568
···
594
}
595
}
596
597
-
user := rp.oauth.GetUser(r)
598
rp.pages.RepoTags(w, pages.RepoTagsParams{
599
LoggedInUser: user,
600
RepoInfo: f.RepoInfo(user),
···
606
607
func (rp *Repo) RepoBranches(w http.ResponseWriter, r *http.Request) {
608
l := rp.logger.With("handler", "RepoBranches")
609
610
f, err := rp.repoResolver.Resolve(r)
611
if err != nil {
···
626
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
627
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
628
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
629
-
rp.pages.Error503(w)
630
return
631
}
632
633
var result types.RepoBranchesResponse
634
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
635
l.Error("failed to decode XRPC response", "err", err)
636
-
rp.pages.Error503(w)
637
return
638
}
639
640
sortBranches(result.Branches)
641
642
-
user := rp.oauth.GetUser(r)
643
rp.pages.RepoBranches(w, pages.RepoBranchesParams{
644
LoggedInUser: user,
645
RepoInfo: f.RepoInfo(user),
···
698
699
func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) {
700
l := rp.logger.With("handler", "RepoBlob")
701
702
f, err := rp.repoResolver.Resolve(r)
703
if err != nil {
···
724
resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo)
725
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
726
l.Error("failed to call XRPC repo.blob", "err", xrpcerr)
727
-
rp.pages.Error503(w)
728
return
729
}
730
···
796
sizeHint = uint64(len(resp.Content))
797
}
798
799
-
user := rp.oauth.GetUser(r)
800
-
801
// Determine if content is binary (dereference pointer)
802
isBinary := false
803
if resp.IsBinary != nil {
···
824
825
func (rp *Repo) RepoBlobRaw(w http.ResponseWriter, r *http.Request) {
826
l := rp.logger.With("handler", "RepoBlobRaw")
827
828
f, err := rp.repoResolver.Resolve(r)
829
if err != nil {
···
872
resp, err := client.Do(req)
873
if err != nil {
874
l.Error("failed to reach knotserver", "err", err)
875
-
rp.pages.Error503(w)
876
return
877
}
878
defer resp.Body.Close()
···
1963
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1964
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1965
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
1966
-
rp.pages.Error503(w)
1967
return
1968
}
1969
1970
var result types.RepoBranchesResponse
1971
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
1972
l.Error("failed to decode XRPC response", "err", err)
1973
-
rp.pages.Error503(w)
1974
return
1975
}
1976
1977
defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", models.DefaultLabelDefs()))
1978
if err != nil {
1979
l.Error("failed to fetch labels", "err", err)
1980
-
rp.pages.Error503(w)
1981
return
1982
}
1983
1984
labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Repo.Labels))
1985
if err != nil {
1986
l.Error("failed to fetch labels", "err", err)
1987
-
rp.pages.Error503(w)
1988
return
1989
}
1990
// remove default labels from the labels list, if present
···
2418
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2419
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2420
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
2421
-
rp.pages.Error503(w)
2422
return
2423
}
2424
···
2455
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2456
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2457
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
2458
-
rp.pages.Error503(w)
2459
return
2460
}
2461
···
2512
2513
if base == "" || head == "" {
2514
l.Error("invalid comparison")
2515
-
rp.pages.Error404(w)
2516
return
2517
}
2518
···
2530
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2531
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2532
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
2533
-
rp.pages.Error503(w)
2534
return
2535
}
2536
···
2544
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2545
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2546
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
2547
-
rp.pages.Error503(w)
2548
return
2549
}
2550
···
2558
compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head)
2559
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2560
l.Error("failed to call XRPC repo.compare", "err", xrpcerr)
2561
-
rp.pages.Error503(w)
2562
return
2563
}
2564
···
90
91
func (rp *Repo) DownloadArchive(w http.ResponseWriter, r *http.Request) {
92
l := rp.logger.With("handler", "DownloadArchive")
93
+
user := rp.oauth.GetUser(r)
94
95
ref := chi.URLParam(r, "ref")
96
ref, _ = url.PathUnescape(ref)
···
114
archiveBytes, err := tangled.RepoArchive(r.Context(), xrpcc, "tar.gz", "", ref, repo)
115
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
116
l.Error("failed to call XRPC repo.archive", "err", xrpcerr)
117
+
rp.pages.Error503(w, pages.ErrorPageParams{
118
+
LoggedInUser: user,
119
+
})
120
return
121
}
122
···
133
134
func (rp *Repo) RepoLog(w http.ResponseWriter, r *http.Request) {
135
l := rp.logger.With("handler", "RepoLog")
136
+
user := rp.oauth.GetUser(r)
137
138
f, err := rp.repoResolver.Resolve(r)
139
if err != nil {
···
173
xrpcBytes, err := tangled.RepoLog(r.Context(), xrpcc, cursor, limit, "", ref, repo)
174
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
175
l.Error("failed to call XRPC repo.log", "err", xrpcerr)
176
+
rp.pages.Error503(w, pages.ErrorPageParams{
177
+
LoggedInUser: user,
178
+
})
179
return
180
}
181
182
var xrpcResp types.RepoLogResponse
183
if err := json.Unmarshal(xrpcBytes, &xrpcResp); err != nil {
184
l.Error("failed to decode XRPC response", "err", err)
185
+
rp.pages.Error503(w, pages.ErrorPageParams{
186
+
LoggedInUser: user,
187
+
})
188
return
189
}
190
191
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
192
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
193
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
194
+
rp.pages.Error503(w, pages.ErrorPageParams{
195
+
LoggedInUser: user,
196
+
})
197
return
198
}
199
···
214
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
215
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
216
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
217
+
rp.pages.Error503(w, pages.ErrorPageParams{
218
+
LoggedInUser: user,
219
+
})
220
return
221
}
222
···
228
}
229
}
230
}
231
232
emailToDidMap, err := db.GetEmailToDid(rp.db, uniqueEmails(xrpcResp.Commits), true)
233
if err != nil {
···
363
364
func (rp *Repo) RepoCommit(w http.ResponseWriter, r *http.Request) {
365
l := rp.logger.With("handler", "RepoCommit")
366
+
user := rp.oauth.GetUser(r)
367
368
f, err := rp.repoResolver.Resolve(r)
369
if err != nil {
···
379
}
380
381
if !plumbing.IsHash(ref) {
382
+
rp.pages.Error404(w, pages.ErrorPageParams{
383
+
LoggedInUser: user,
384
+
})
385
return
386
}
387
···
398
xrpcBytes, err := tangled.RepoDiff(r.Context(), xrpcc, ref, repo)
399
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
400
l.Error("failed to call XRPC repo.diff", "err", xrpcerr)
401
+
rp.pages.Error503(w, pages.ErrorPageParams{
402
+
LoggedInUser: user,
403
+
})
404
return
405
}
406
407
var result types.RepoCommitResponse
408
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
409
l.Error("failed to decode XRPC response", "err", err)
410
+
rp.pages.Error503(w, pages.ErrorPageParams{
411
+
LoggedInUser: user,
412
+
})
413
return
414
}
415
···
423
l.Error("failed to GetVerifiedCommits", "err", err)
424
}
425
426
repoInfo := f.RepoInfo(user)
427
pipelines, err := getPipelineStatuses(rp.db, repoInfo, []string{result.Diff.Commit.This})
428
if err != nil {
···
447
448
func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) {
449
l := rp.logger.With("handler", "RepoTree")
450
+
user := rp.oauth.GetUser(r)
451
452
f, err := rp.repoResolver.Resolve(r)
453
if err != nil {
···
477
xrpcResp, err := tangled.RepoTree(r.Context(), xrpcc, treePath, ref, repo)
478
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
479
l.Error("failed to call XRPC repo.tree", "err", xrpcerr)
480
+
rp.pages.Error503(w, pages.ErrorPageParams{
481
+
LoggedInUser: user,
482
+
})
483
return
484
}
485
···
530
http.Redirect(w, r, redirectTo, http.StatusFound)
531
return
532
}
533
534
var breadcrumbs [][]string
535
breadcrumbs = append(breadcrumbs, []string{f.Name, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), url.PathEscape(ref))})
···
552
553
func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) {
554
l := rp.logger.With("handler", "RepoTags")
555
+
user := rp.oauth.GetUser(r)
556
557
f, err := rp.repoResolver.Resolve(r)
558
if err != nil {
···
573
xrpcBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
574
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
575
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
576
+
rp.pages.Error503(w, pages.ErrorPageParams{
577
+
LoggedInUser: user,
578
+
})
579
return
580
}
581
582
var result types.RepoTagsResponse
583
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
584
l.Error("failed to decode XRPC response", "err", err)
585
+
rp.pages.Error503(w, pages.ErrorPageParams{
586
+
LoggedInUser: user,
587
+
})
588
return
589
}
590
···
616
}
617
}
618
619
rp.pages.RepoTags(w, pages.RepoTagsParams{
620
LoggedInUser: user,
621
RepoInfo: f.RepoInfo(user),
···
627
628
func (rp *Repo) RepoBranches(w http.ResponseWriter, r *http.Request) {
629
l := rp.logger.With("handler", "RepoBranches")
630
+
user := rp.oauth.GetUser(r)
631
632
f, err := rp.repoResolver.Resolve(r)
633
if err != nil {
···
648
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
649
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
650
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
651
+
rp.pages.Error503(w, pages.ErrorPageParams{
652
+
LoggedInUser: user,
653
+
})
654
return
655
}
656
657
var result types.RepoBranchesResponse
658
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
659
l.Error("failed to decode XRPC response", "err", err)
660
+
rp.pages.Error503(w, pages.ErrorPageParams{
661
+
LoggedInUser: user,
662
+
})
663
return
664
}
665
666
sortBranches(result.Branches)
667
668
rp.pages.RepoBranches(w, pages.RepoBranchesParams{
669
LoggedInUser: user,
670
RepoInfo: f.RepoInfo(user),
···
723
724
func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) {
725
l := rp.logger.With("handler", "RepoBlob")
726
+
user := rp.oauth.GetUser(r)
727
728
f, err := rp.repoResolver.Resolve(r)
729
if err != nil {
···
750
resp, err := tangled.RepoBlob(r.Context(), xrpcc, filePath, false, ref, repo)
751
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
752
l.Error("failed to call XRPC repo.blob", "err", xrpcerr)
753
+
rp.pages.Error503(w, pages.ErrorPageParams{
754
+
LoggedInUser: user,
755
+
})
756
return
757
}
758
···
824
sizeHint = uint64(len(resp.Content))
825
}
826
827
// Determine if content is binary (dereference pointer)
828
isBinary := false
829
if resp.IsBinary != nil {
···
850
851
func (rp *Repo) RepoBlobRaw(w http.ResponseWriter, r *http.Request) {
852
l := rp.logger.With("handler", "RepoBlobRaw")
853
+
user := rp.oauth.GetUser(r)
854
855
f, err := rp.repoResolver.Resolve(r)
856
if err != nil {
···
899
resp, err := client.Do(req)
900
if err != nil {
901
l.Error("failed to reach knotserver", "err", err)
902
+
rp.pages.Error503(w, pages.ErrorPageParams{
903
+
LoggedInUser: user,
904
+
})
905
return
906
}
907
defer resp.Body.Close()
···
1992
xrpcBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
1993
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
1994
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
1995
+
rp.pages.Error503(w, pages.ErrorPageParams{
1996
+
LoggedInUser: user,
1997
+
})
1998
return
1999
}
2000
2001
var result types.RepoBranchesResponse
2002
if err := json.Unmarshal(xrpcBytes, &result); err != nil {
2003
l.Error("failed to decode XRPC response", "err", err)
2004
+
rp.pages.Error503(w, pages.ErrorPageParams{
2005
+
LoggedInUser: user,
2006
+
})
2007
return
2008
}
2009
2010
defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", models.DefaultLabelDefs()))
2011
if err != nil {
2012
l.Error("failed to fetch labels", "err", err)
2013
+
rp.pages.Error503(w, pages.ErrorPageParams{
2014
+
LoggedInUser: user,
2015
+
})
2016
return
2017
}
2018
2019
labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Repo.Labels))
2020
if err != nil {
2021
l.Error("failed to fetch labels", "err", err)
2022
+
rp.pages.Error503(w, pages.ErrorPageParams{
2023
+
LoggedInUser: user,
2024
+
})
2025
return
2026
}
2027
// remove default labels from the labels list, if present
···
2455
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2456
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2457
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
2458
+
rp.pages.Error503(w, pages.ErrorPageParams{
2459
+
LoggedInUser: user,
2460
+
})
2461
return
2462
}
2463
···
2494
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2495
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2496
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
2497
+
rp.pages.Error503(w, pages.ErrorPageParams{
2498
+
LoggedInUser: user,
2499
+
})
2500
return
2501
}
2502
···
2553
2554
if base == "" || head == "" {
2555
l.Error("invalid comparison")
2556
+
rp.pages.Error404(w, pages.ErrorPageParams{
2557
+
LoggedInUser: user,
2558
+
})
2559
return
2560
}
2561
···
2573
branchBytes, err := tangled.RepoBranches(r.Context(), xrpcc, "", 0, repo)
2574
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2575
l.Error("failed to call XRPC repo.branches", "err", xrpcerr)
2576
+
rp.pages.Error503(w, pages.ErrorPageParams{
2577
+
LoggedInUser: user,
2578
+
})
2579
return
2580
}
2581
···
2589
tagBytes, err := tangled.RepoTags(r.Context(), xrpcc, "", 0, repo)
2590
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2591
l.Error("failed to call XRPC repo.tags", "err", xrpcerr)
2592
+
rp.pages.Error503(w, pages.ErrorPageParams{
2593
+
LoggedInUser: user,
2594
+
})
2595
return
2596
}
2597
···
2605
compareBytes, err := tangled.RepoCompare(r.Context(), xrpcc, repo, base, head)
2606
if xrpcerr := xrpcclient.HandleXrpcErr(err); xrpcerr != nil {
2607
l.Error("failed to call XRPC repo.compare", "err", xrpcerr)
2608
+
rp.pages.Error503(w, pages.ErrorPageParams{
2609
+
LoggedInUser: user,
2610
+
})
2611
return
2612
}
2613
-1
appview/state/follow.go
-1
appview/state/follow.go
+10
-3
appview/state/gfi.go
+10
-3
appview/state/gfi.go
···
18
func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) {
19
user := s.oauth.GetUser(r)
20
21
-
page := pagination.FromContext(r.Context())
22
23
goodFirstIssueLabel := fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "good-first-issue")
24
25
repoLabels, err := db.GetRepoLabels(s.db, db.FilterEq("label_at", goodFirstIssueLabel))
26
if err != nil {
27
log.Println("failed to get repo labels", err)
28
-
s.pages.Error503(w)
29
return
30
}
31
···
54
)
55
if err != nil {
56
log.Println("failed to get issues", err)
57
-
s.pages.Error503(w)
58
return
59
}
60
···
18
func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) {
19
user := s.oauth.GetUser(r)
20
21
+
page, ok := r.Context().Value("page").(pagination.Page)
22
+
if !ok {
23
+
page = pagination.FirstPage()
24
+
}
25
26
goodFirstIssueLabel := fmt.Sprintf("at://%s/%s/%s", consts.TangledDid, tangled.LabelDefinitionNSID, "good-first-issue")
27
28
repoLabels, err := db.GetRepoLabels(s.db, db.FilterEq("label_at", goodFirstIssueLabel))
29
if err != nil {
30
log.Println("failed to get repo labels", err)
31
+
s.pages.Error503(w, pages.ErrorPageParams{
32
+
LoggedInUser: user,
33
+
})
34
return
35
}
36
···
59
)
60
if err != nil {
61
log.Println("failed to get issues", err)
62
+
s.pages.Error503(w, pages.ErrorPageParams{
63
+
LoggedInUser: user,
64
+
})
65
return
66
}
67
-2
appview/state/login.go
-2
appview/state/login.go
+36
-10
appview/state/profile.go
+36
-10
appview/state/profile.go
···
112
113
func (s *State) profileOverview(w http.ResponseWriter, r *http.Request) {
114
l := s.logger.With("handler", "profileHomePage")
115
116
profile, err := s.profile(r)
117
if err != nil {
118
l.Error("failed to build profile card", "err", err)
119
-
s.pages.Error500(w)
120
return
121
}
122
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
173
174
func (s *State) reposPage(w http.ResponseWriter, r *http.Request) {
175
l := s.logger.With("handler", "reposPage")
176
177
profile, err := s.profile(r)
178
if err != nil {
179
l.Error("failed to build profile card", "err", err)
180
-
s.pages.Error500(w)
181
return
182
}
183
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
189
)
190
if err != nil {
191
l.Error("failed to get repos", "err", err)
192
-
s.pages.Error500(w)
193
return
194
}
195
···
202
203
func (s *State) starredPage(w http.ResponseWriter, r *http.Request) {
204
l := s.logger.With("handler", "starredPage")
205
206
profile, err := s.profile(r)
207
if err != nil {
208
l.Error("failed to build profile card", "err", err)
209
-
s.pages.Error500(w)
210
return
211
}
212
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
214
stars, err := db.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid))
215
if err != nil {
216
l.Error("failed to get stars", "err", err)
217
-
s.pages.Error500(w)
218
return
219
}
220
var repos []models.Repo
···
233
234
func (s *State) stringsPage(w http.ResponseWriter, r *http.Request) {
235
l := s.logger.With("handler", "stringsPage")
236
237
profile, err := s.profile(r)
238
if err != nil {
239
l.Error("failed to build profile card", "err", err)
240
-
s.pages.Error500(w)
241
return
242
}
243
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
245
strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid))
246
if err != nil {
247
l.Error("failed to get strings", "err", err)
248
-
s.pages.Error500(w)
249
return
250
}
251
···
380
381
func (s *State) AtomFeedPage(w http.ResponseWriter, r *http.Request) {
382
ident, ok := r.Context().Value("resolvedId").(identity.Identity)
383
if !ok {
384
-
s.pages.Error404(w)
385
return
386
}
387
388
feed, err := s.getProfileFeed(r.Context(), &ident)
389
if err != nil {
390
-
s.pages.Error500(w)
391
return
392
}
393
···
397
398
atom, err := feed.ToAtom()
399
if err != nil {
400
-
s.pages.Error500(w)
401
return
402
}
403
···
112
113
func (s *State) profileOverview(w http.ResponseWriter, r *http.Request) {
114
l := s.logger.With("handler", "profileHomePage")
115
+
user := s.oauth.GetUser(r)
116
117
profile, err := s.profile(r)
118
if err != nil {
119
l.Error("failed to build profile card", "err", err)
120
+
s.pages.Error500(w, pages.ErrorPageParams{
121
+
LoggedInUser: user,
122
+
})
123
return
124
}
125
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
176
177
func (s *State) reposPage(w http.ResponseWriter, r *http.Request) {
178
l := s.logger.With("handler", "reposPage")
179
+
user := s.oauth.GetUser(r)
180
181
profile, err := s.profile(r)
182
if err != nil {
183
l.Error("failed to build profile card", "err", err)
184
+
s.pages.Error500(w, pages.ErrorPageParams{
185
+
LoggedInUser: user,
186
+
})
187
return
188
}
189
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
195
)
196
if err != nil {
197
l.Error("failed to get repos", "err", err)
198
+
s.pages.Error500(w, pages.ErrorPageParams{
199
+
LoggedInUser: user,
200
+
})
201
return
202
}
203
···
210
211
func (s *State) starredPage(w http.ResponseWriter, r *http.Request) {
212
l := s.logger.With("handler", "starredPage")
213
+
user := s.oauth.GetUser(r)
214
215
profile, err := s.profile(r)
216
if err != nil {
217
l.Error("failed to build profile card", "err", err)
218
+
s.pages.Error500(w, pages.ErrorPageParams{
219
+
LoggedInUser: user,
220
+
})
221
return
222
}
223
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
225
stars, err := db.GetStars(s.db, 0, db.FilterEq("starred_by_did", profile.UserDid))
226
if err != nil {
227
l.Error("failed to get stars", "err", err)
228
+
s.pages.Error500(w, pages.ErrorPageParams{
229
+
LoggedInUser: user,
230
+
})
231
return
232
}
233
var repos []models.Repo
···
246
247
func (s *State) stringsPage(w http.ResponseWriter, r *http.Request) {
248
l := s.logger.With("handler", "stringsPage")
249
+
user := s.oauth.GetUser(r)
250
251
profile, err := s.profile(r)
252
if err != nil {
253
l.Error("failed to build profile card", "err", err)
254
+
s.pages.Error500(w, pages.ErrorPageParams{
255
+
LoggedInUser: user,
256
+
})
257
return
258
}
259
l = l.With("profileDid", profile.UserDid, "profileHandle", profile.UserHandle)
···
261
strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid))
262
if err != nil {
263
l.Error("failed to get strings", "err", err)
264
+
s.pages.Error500(w, pages.ErrorPageParams{
265
+
LoggedInUser: user,
266
+
})
267
return
268
}
269
···
398
399
func (s *State) AtomFeedPage(w http.ResponseWriter, r *http.Request) {
400
ident, ok := r.Context().Value("resolvedId").(identity.Identity)
401
+
user := s.oauth.GetUser(r)
402
+
403
if !ok {
404
+
s.pages.Error404(w, pages.ErrorPageParams{
405
+
LoggedInUser: user,
406
+
})
407
return
408
}
409
410
feed, err := s.getProfileFeed(r.Context(), &ident)
411
if err != nil {
412
+
s.pages.Error500(w, pages.ErrorPageParams{
413
+
LoggedInUser: user,
414
+
})
415
return
416
}
417
···
421
422
atom, err := feed.ToAtom()
423
if err != nil {
424
+
s.pages.Error500(w, pages.ErrorPageParams{
425
+
LoggedInUser: user,
426
+
})
427
return
428
}
429
+3
-2
appview/state/router.go
+3
-2
appview/state/router.go
···
10
"tangled.org/core/appview/labels"
11
"tangled.org/core/appview/middleware"
12
"tangled.org/core/appview/notifications"
13
"tangled.org/core/appview/pipelines"
14
"tangled.org/core/appview/pulls"
15
"tangled.org/core/appview/repo"
···
103
})
104
105
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
106
-
s.pages.Error404(w)
107
})
108
109
return r
···
174
r.Get("/brand", s.Brand)
175
176
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
177
-
s.pages.Error404(w)
178
})
179
return r
180
}
···
10
"tangled.org/core/appview/labels"
11
"tangled.org/core/appview/middleware"
12
"tangled.org/core/appview/notifications"
13
+
"tangled.org/core/appview/pages"
14
"tangled.org/core/appview/pipelines"
15
"tangled.org/core/appview/pulls"
16
"tangled.org/core/appview/repo"
···
104
})
105
106
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
107
+
s.pages.Error404(w, pages.ErrorPageParams{})
108
})
109
110
return r
···
175
r.Get("/brand", s.Brand)
176
177
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
178
+
s.pages.Error404(w, pages.ErrorPageParams{})
179
})
180
return r
181
}
+4
-1
appview/strings/strings.go
+4
-1
appview/strings/strings.go
···
88
89
func (s *Strings) contents(w http.ResponseWriter, r *http.Request) {
90
l := s.Logger.With("handler", "contents")
91
92
id, ok := r.Context().Value("resolvedId").(identity.Identity)
93
if !ok {
···
118
}
119
if len(strings) < 1 {
120
l.Error("string not found")
121
-
s.Pages.Error404(w)
122
return
123
}
124
if len(strings) != 1 {
···
88
89
func (s *Strings) contents(w http.ResponseWriter, r *http.Request) {
90
l := s.Logger.With("handler", "contents")
91
+
user := s.OAuth.GetUser(r)
92
93
id, ok := r.Context().Value("resolvedId").(identity.Identity)
94
if !ok {
···
119
}
120
if len(strings) < 1 {
121
l.Error("string not found")
122
+
s.Pages.Error404(w, pages.ErrorPageParams{
123
+
LoggedInUser: user,
124
+
})
125
return
126
}
127
if len(strings) != 1 {
+1
-1
spindle/engines/nixery/engine.go
+1
-1
spindle/engines/nixery/engine.go