+1
api/tangled/actorprofile.go
+1
api/tangled/actorprofile.go
···
28
// pinnedRepositories: Any ATURI, it is up to appviews to validate these fields.
29
PinnedRepositories []string `json:"pinnedRepositories,omitempty" cborgen:"pinnedRepositories,omitempty"`
30
Stats []string `json:"stats,omitempty" cborgen:"stats,omitempty"`
31
+
Pronouns *string `json:"pronouns,omitempty" cborgen:"pronouns,omitempty"`
32
}
+7
appview/db/db.go
+7
appview/db/db.go
+8
-5
appview/db/issues.go
+8
-5
appview/db/issues.go
···
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) {
···
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) {
+7
-4
appview/db/notifications.go
+7
-4
appview/db/notifications.go
···
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 {
···
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 {
+26
-6
appview/db/profile.go
+26
-6
appview/db/profile.go
···
129
did,
130
description,
131
include_bluesky,
132
-
location
133
)
134
-
values (?, ?, ?, ?)`,
135
profile.Did,
136
profile.Description,
137
includeBskyValue,
138
profile.Location,
139
)
140
141
if err != nil {
···
216
did,
217
description,
218
include_bluesky,
219
-
location
220
from
221
profile
222
%s`,
···
231
for rows.Next() {
232
var profile models.Profile
233
var includeBluesky int
234
235
-
err = rows.Scan(&profile.ID, &profile.Did, &profile.Description, &includeBluesky, &profile.Location)
236
if err != nil {
237
return nil, err
238
}
239
240
if includeBluesky != 0 {
241
profile.IncludeBluesky = true
242
}
243
244
profileMap[profile.Did] = &profile
···
302
303
func GetProfile(e Execer, did string) (*models.Profile, error) {
304
var profile models.Profile
305
profile.Did = did
306
307
includeBluesky := 0
308
err := e.QueryRow(
309
-
`select description, include_bluesky, location from profile where did = ?`,
310
did,
311
-
).Scan(&profile.Description, &includeBluesky, &profile.Location)
312
if err == sql.ErrNoRows {
313
profile := models.Profile{}
314
profile.Did = did
···
321
322
if includeBluesky != 0 {
323
profile.IncludeBluesky = true
324
}
325
326
rows, err := e.Query(`select link from profile_links where did = ?`, did)
···
412
// ensure description is not too long
413
if len(profile.Location) > 40 {
414
return fmt.Errorf("Entered location is too long.")
415
}
416
417
// ensure links are in order
···
129
did,
130
description,
131
include_bluesky,
132
+
location,
133
+
pronouns
134
)
135
+
values (?, ?, ?, ?, ?)`,
136
profile.Did,
137
profile.Description,
138
includeBskyValue,
139
profile.Location,
140
+
profile.Pronouns,
141
)
142
143
if err != nil {
···
218
did,
219
description,
220
include_bluesky,
221
+
location,
222
+
pronouns
223
from
224
profile
225
%s`,
···
234
for rows.Next() {
235
var profile models.Profile
236
var includeBluesky int
237
+
var pronouns sql.Null[string]
238
239
+
err = rows.Scan(&profile.ID, &profile.Did, &profile.Description, &includeBluesky, &profile.Location, &pronouns)
240
if err != nil {
241
return nil, err
242
}
243
244
if includeBluesky != 0 {
245
profile.IncludeBluesky = true
246
+
}
247
+
248
+
if pronouns.Valid {
249
+
profile.Pronouns = pronouns.V
250
}
251
252
profileMap[profile.Did] = &profile
···
310
311
func GetProfile(e Execer, did string) (*models.Profile, error) {
312
var profile models.Profile
313
+
var pronouns sql.Null[string]
314
+
315
profile.Did = did
316
317
includeBluesky := 0
318
+
319
err := e.QueryRow(
320
+
`select description, include_bluesky, location, pronouns from profile where did = ?`,
321
did,
322
+
).Scan(&profile.Description, &includeBluesky, &profile.Location, &pronouns)
323
if err == sql.ErrNoRows {
324
profile := models.Profile{}
325
profile.Did = did
···
332
333
if includeBluesky != 0 {
334
profile.IncludeBluesky = true
335
+
}
336
+
337
+
if pronouns.Valid {
338
+
profile.Pronouns = pronouns.V
339
}
340
341
rows, err := e.Query(`select link from profile_links where did = ?`, did)
···
427
// ensure description is not too long
428
if len(profile.Location) > 40 {
429
return fmt.Errorf("Entered location is too long.")
430
+
}
431
+
432
+
// ensure pronouns are not too long
433
+
if len(profile.Pronouns) > 40 {
434
+
return fmt.Errorf("Entered pronouns are too long.")
435
}
436
437
// ensure links are in order
+6
appview/ingester.go
+6
appview/ingester.go
···
291
292
includeBluesky := record.Bluesky
293
294
+
pronouns := ""
295
+
if record.Pronouns != nil {
296
+
pronouns = *record.Pronouns
297
+
}
298
+
299
location := ""
300
if record.Location != nil {
301
location = *record.Location
···
330
Links: links,
331
Stats: stats,
332
PinnedRepos: pinned,
333
+
Pronouns: pronouns,
334
}
335
336
ddb, ok := i.Db.Execer.(*db.DB)
+13
-41
appview/issues/issues.go
+13
-41
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, 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
···
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
+7
-21
appview/middleware/middleware.go
+7
-21
appview/middleware/middleware.go
···
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
···
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
+1
appview/models/profile.go
+1
appview/models/profile.go
+3
-11
appview/notifications/notifications.go
+3
-11
appview/notifications/notifications.go
···
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
···
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
+13
-2
appview/oauth/handler.go
+13
-2
appview/oauth/handler.go
···
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
···
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
-1
appview/oauth/oauth.go
+4
-1
appview/oauth/oauth.go
+3
-2
appview/pages/funcmap.go
+3
-2
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)
+9
-12
appview/pages/pages.go
+9
-12
appview/pages/pages.go
···
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
}
···
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
}
+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 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>
···
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>
+11
appview/pages/templates/user/fragments/editBio.html
+11
appview/pages/templates/user/fragments/editBio.html
···
20
</div>
21
22
<div class="flex flex-col gap-1">
23
+
<label class="m-0 p-0" for="pronouns">pronouns</label>
24
+
<div class="flex items-center gap-2 w-full">
25
+
{{ $pronouns := "" }}
26
+
{{ if and .Profile .Profile.Pronouns }}
27
+
{{ $pronouns = .Profile.Pronouns }}
28
+
{{ end }}
29
+
<input type="text" class="py-1 px-1 w-full" name="pronouns" value="{{ $pronouns }}">
30
+
</div>
31
+
</div>
32
+
33
+
<div class="flex flex-col gap-1">
34
<label class="m-0 p-0" for="location">location</label>
35
<div class="flex items-center gap-2 w-full">
36
{{ $location := "" }}
+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 }}" />
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 }}" alt="{{ $userIdent }}" />
7
</div>
8
9
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 w-full">
+5
appview/pages/templates/user/fragments/profileCard.html
+5
appview/pages/templates/user/fragments/profileCard.html
···
12
class="text-lg font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
13
{{ $userIdent }}
14
</p>
15
+
{{ with .Profile }}
16
+
{{ if .Pronouns }}
17
+
<p class="text-gray-500 dark:text-gray-400">{{ .Pronouns }}</p>
18
+
{{ end }}
19
+
{{ end }}
20
<a href="/{{ $userIdent }}/feed.atom">{{ i "rss" "size-4" }}</a>
21
</div>
22
+20
-2
appview/pages/templates/user/login.html
+20
-2
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-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>
···
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>
+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 {
+10
-30
appview/pulls/pulls.go
+10
-30
appview/pulls/pulls.go
···
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
···
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
+2
-8
appview/repo/feed.go
+2
-8
appview/repo/feed.go
···
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
···
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
+1
-3
appview/repo/index.go
+1
-3
appview/repo/index.go
+34
-83
appview/repo/repo.go
+34
-83
appview/repo/repo.go
···
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
···
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
+1
appview/state/follow.go
+1
appview/state/follow.go
+3
-10
appview/state/gfi.go
+3
-10
appview/state/gfi.go
···
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
···
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
+2
appview/state/login.go
+2
appview/state/login.go
+12
-36
appview/state/profile.go
+12
-36
appview/state/profile.go
···
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
···
564
profile.Description = r.FormValue("description")
565
profile.IncludeBluesky = r.FormValue("includeBluesky") == "on"
566
profile.Location = r.FormValue("location")
567
568
var links [5]string
569
for i := range 5 {
···
678
Location: &profile.Location,
679
PinnedRepositories: pinnedRepoStrings,
680
Stats: vanityStats[:],
681
}},
682
SwapRecord: cid,
683
})
···
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
···
538
profile.Description = r.FormValue("description")
539
profile.IncludeBluesky = r.FormValue("includeBluesky") == "on"
540
profile.Location = r.FormValue("location")
541
+
profile.Pronouns = r.FormValue("pronouns")
542
543
var links [5]string
544
for i := range 5 {
···
653
Location: &profile.Location,
654
PinnedRepositories: pinnedRepoStrings,
655
Stats: vanityStats[:],
656
+
Pronouns: &profile.Pronouns,
657
}},
658
SwapRecord: cid,
659
})
+2
-3
appview/state/router.go
+2
-3
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/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
}
···
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
}
+1
-4
appview/strings/strings.go
+1
-4
appview/strings/strings.go
···
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 {
···
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 {
+5
lexicons/actor/profile.json
+5
lexicons/actor/profile.json
+1
-1
spindle/engines/nixery/engine.go
+1
-1
spindle/engines/nixery/engine.go