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

Compare changes

Choose any two refs to compare.

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