forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

Compare changes

Choose any two refs to compare.

Changed files
+243 -287
api
tangled
appview
lexicons
actor
spindle
engines
nixery
+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 }
··· 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
··· 1106 return err 1107 }) 1108 1109 return &DB{ 1110 db, 1111 logger,
··· 1106 return err 1107 }) 1108 1109 + runMigration(conn, logger, "add-pronouns-profile", func(tx *sql.Tx) error { 1110 + _, err := tx.Exec(` 1111 + alter table profile add column pronouns text; 1112 + `) 1113 + return err 1114 + }) 1115 + 1116 return &DB{ 1117 db, 1118 logger,
+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
··· 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
··· 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
··· 291 292 includeBluesky := record.Bluesky 293 294 location := "" 295 if record.Location != nil { 296 location = *record.Location ··· 325 Links: links, 326 Stats: stats, 327 PinnedRepos: pinned, 328 } 329 330 ddb, ok := i.Db.Execer.(*db.DB)
··· 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
··· 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
··· 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
··· 19 Links [5]string 20 Stats [2]VanityStat 21 PinnedRepos [6]syntax.ATURI 22 } 23 24 func (p Profile) IsLinksEmpty() bool {
··· 19 Links [5]string 20 Stats [2]VanityStat 21 PinnedRepos [6]syntax.ATURI 22 + Pronouns string 23 } 24 25 func (p Profile) IsLinksEmpty() bool {
+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
··· 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
··· 58 59 sessStore := sessions.NewCookieStore([]byte(config.Core.CookieSecret)) 60 61 return &OAuth{ 62 - ClientApp: oauth.NewClientApp(&oauthConfig, authStore), 63 Config: config, 64 SessStore: sessStore, 65 JwksUri: jwksUri,
··· 58 59 sessStore := sessions.NewCookieStore([]byte(config.Core.CookieSecret)) 60 61 + clientApp := oauth.NewClientApp(&oauthConfig, authStore) 62 + clientApp.Dir = res.Directory() 63 + 64 return &OAuth{ 65 + ClientApp: clientApp, 66 Config: config, 67 SessStore: sessStore, 68 JwksUri: jwksUri,
+3 -2
appview/pages/funcmap.go
··· 297 }, 298 299 "normalizeForHtmlId": func(s string) string { 300 - // TODO: extend this to handle other cases? 301 - return strings.ReplaceAll(s, ":", "_") 302 }, 303 "sshFingerprint": func(pubKey string) string { 304 fp, err := crypto.SSHFingerprint(pubKey)
··· 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
··· 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
··· 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
··· 20 </div> 21 22 <div class="flex flex-col gap-1"> 23 <label class="m-0 p-0" for="location">location</label> 24 <div class="flex items-center gap-2 w-full"> 25 {{ $location := "" }}
··· 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
··· 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
··· 12 class="text-lg font-bold dark:text-white overflow-hidden text-ellipsis whitespace-nowrap"> 13 {{ $userIdent }} 14 </p> 15 <a href="/{{ $userIdent }}/feed.atom">{{ i "rss" "size-4" }}</a> 16 </div> 17
··· 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
··· 13 <title>login &middot; 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 &middot; 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
··· 1 package pagination 2 3 type Page struct { 4 Offset int // where to start from 5 Limit int // number of items in a page ··· 10 Offset: 0, 11 Limit: 30, 12 } 13 } 14 15 func (p Page) Previous() Page {
··· 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
··· 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
··· 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
··· 67 return 68 } 69 70 - rp.pages.Error503(w, pages.ErrorPageParams{ 71 - LoggedInUser: user, 72 - }) 73 l.Error("failed to build index response", "err", err) 74 return 75 }
··· 67 return 68 } 69 70 + rp.pages.Error503(w) 71 l.Error("failed to build index response", "err", err) 72 return 73 }
+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
··· 26 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 27 if err != nil { 28 log.Println("failed to follow, invalid did") 29 } 30 31 if currentUser.Did == subjectIdent.DID.String() {
··· 26 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 27 if err != nil { 28 log.Println("failed to follow, invalid did") 29 + return 30 } 31 32 if currentUser.Did == subjectIdent.DID.String() {
+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
··· 14 switch r.Method { 15 case http.MethodGet: 16 returnURL := r.URL.Query().Get("return_url") 17 s.pages.Login(w, pages.LoginParams{ 18 ReturnUrl: returnURL, 19 }) 20 case http.MethodPost: 21 handle := r.FormValue("handle")
··· 14 switch r.Method { 15 case http.MethodGet: 16 returnURL := r.URL.Query().Get("return_url") 17 + errorCode := r.URL.Query().Get("error") 18 s.pages.Login(w, pages.LoginParams{ 19 ReturnUrl: returnURL, 20 + ErrorCode: errorCode, 21 }) 22 case http.MethodPost: 23 handle := r.FormValue("handle")
+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
··· 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
··· 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
··· 64 "type": "string", 65 "format": "at-uri" 66 } 67 } 68 } 69 }
··· 64 "type": "string", 65 "format": "at-uri" 66 } 67 + }, 68 + "pronouns": { 69 + "type": "string", 70 + "description": "Preferred gender pronouns.", 71 + "maxLength": 40 72 } 73 } 74 }
+1 -1
spindle/engines/nixery/engine.go
··· 222 }, 223 ReadonlyRootfs: false, 224 CapDrop: []string{"ALL"}, 225 - CapAdd: []string{"CAP_DAC_OVERRIDE"}, 226 SecurityOpt: []string{"no-new-privileges"}, 227 ExtraHosts: []string{"host.docker.internal:host-gateway"}, 228 }, nil, nil, "")
··· 222 }, 223 ReadonlyRootfs: false, 224 CapDrop: []string{"ALL"}, 225 + CapAdd: []string{"CAP_DAC_OVERRIDE", "CAP_CHOWN", "CAP_FOWNER", "CAP_SETUID", "CAP_SETGID"}, 226 SecurityOpt: []string{"no-new-privileges"}, 227 ExtraHosts: []string{"host.docker.internal:host-gateway"}, 228 }, nil, nil, "")