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

Compare changes

Choose any two refs to compare.

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