fix Preserve navigation on authenticated errors

Resolve the current viewer in the catch-all route and pass the viewer and request to error_page. Authenticated 404 pages now render the same top navigation and profile menu as other authenticated pages. Public errors keep the public shell.

Commit
4ff2ec1ca584bfaa7b28803d7e9713e11a5dda79
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/web/handlers.ml
index ad4dcf7e..b7d15f2c 100644..100644
@@ -1614,14 +1614,25 @@
1614 1614 body Dream's router would return. Kept last so it never shadows a real
1615 1615 route. The production [error_handler] covers the rest: [5xx] responses and
1616 1616 uncaught exceptions. *)
1617 Removed: let catch_all =
1618 Removed: Dream.any "/**" (fun _ ->
1619 Removed: html ~status:`Not_Found (Pages.error_page ~status:404))
1617 Added: let catch_all t =
1618 Added: Dream.any "/**" (fun request ->
1619 Added: current_trainee t request >>= function
1620 Added: | Some trainee ->
1621 Added: let viewer =
1622 Added: {
1623 Added: View_model.Viewer.username =
1624 Added: Trainee.username_to_string trainee.Trainee.username;
1625 Added: }
1626 Added: in
1627 Added: html ~status:`Not_Found
1628 Added: (Pages.error_page ~viewer ~request ~status:404 ())
1629 Added: | None -> html ~status:`Not_Found (Pages.error_page ~status:404 ()))
1620 1630
1621 1631 let routes t =
1622 1632 Auth.routes t @ Overview.routes t @ Current_workout.routes t
1623 1633 @ Logbook.routes t @ App_feedback.routes t @ Profile.routes t
1624 Removed: @ Settings.routes t @ Import.routes t @ Assets.routes @ [ catch_all ]
1634 Added: @ Settings.routes t @ Import.routes t @ Assets.routes
1635 Added: @ [ catch_all t ]
1625 1636
1626 1637 (* A branded error page for every failure Dream routes here: unmatched paths,
1627 1638 [4xx] and [5xx] responses, and uncaught exceptions. The page names only the
@@ -1630,6 +1641,6 @@
1630 1641 let error_handler =
1631 1642 Dream.error_template (fun _error _message suggested ->
1632 1643 let status = Dream.status suggested |> Dream.status_to_int in
1633 Removed: Dream_html.set_body suggested (Pages.error_page ~status);
1644 Added: Dream_html.set_body suggested (Pages.error_page ~status ());
1634 1645 Lwt.return suggested)
1635 1646 end
lib/web/pages.ml
index b54e2d0c..674dbe5c 100644..100644
@@ -262,7 +262,7 @@
262 262 of failure, never a server-supplied string, so nothing internal leaks. The
263 263 navigation stays present — top on desktop, bottom on mobile — so a lost
264 264 visitor is one tap from a known destination. *)
265 Removed: let error_page ~status =
265 Added: let error_page ?viewer ?request ~status () =
266 266 let title, detail =
267 267 match status with
268 268 | 404 ->
@@ -273,7 +273,7 @@
273 273 ("Something went wrong", "The server hit a problem. Try again shortly.")
274 274 | _ -> ("Something went wrong", "That request could not be completed.")
275 275 in
276 Removed: html_page ~show_nav:true title
276 Added: html_page ?viewer ?request ~show_nav:true title
277 277 [
278 278 tag "p" [ class_ "eyebrow" ] [ txt "%d" status ];
279 279 tag "h1" [] [ txt "%s" title ];
lib/web/pages.mli
index 4368c0cf..7cb67e5c 100644..100644
@@ -102,7 +102,12 @@
102 102
103 103 val problem : title:string -> detail:string -> page
104 104
105 Removed: val error_page : status:int -> page
105 Added: val error_page :
106 Added: ?viewer:View_model.Viewer.t ->
107 Added: ?request:Dream.request ->
108 Added: status:int ->
109 Added: unit ->
110 Added: page
106 111 (** A branded page for an HTTP failure. It names only the class of failure, so
107 112 no server-supplied string leaks, and keeps the navigation affordances: top
108 113 on desktop, bottom on mobile. *)