1use axum::response::{Html, IntoResponse as _, Response};
10use mas_axum_utils::{SessionInfoExt, cookies::CookieJar, csrf::CsrfExt};
11use mas_data_model::BrowserSession;
12use mas_i18n::DataLocale;
13use mas_storage::{BoxRepository, Clock, RepositoryError};
14use mas_templates::{AccountInactiveContext, TemplateContext, Templates};
15use rand::RngCore;
16use thiserror::Error;
17
18#[derive(Debug, Error)]
19#[error(transparent)]
20pub enum SessionLoadError {
21 Template(#[from] mas_templates::TemplateError),
22 Repository(#[from] RepositoryError),
23}
24
25#[allow(clippy::large_enum_variant)]
26pub enum SessionOrFallback {
27 MaybeSession {
28 cookie_jar: CookieJar,
29 maybe_session: Option<BrowserSession>,
30 },
31 Fallback {
32 response: Response,
33 },
34}
35
36pub async fn load_session_or_fallback(
39 cookie_jar: CookieJar,
40 clock: &impl Clock,
41 rng: impl RngCore,
42 templates: &Templates,
43 locale: &DataLocale,
44 repo: &mut BoxRepository,
45) -> Result<SessionOrFallback, SessionLoadError> {
46 let (session_info, cookie_jar) = cookie_jar.session_info();
47 let Some(session_id) = session_info.current_session_id() else {
48 return Ok(SessionOrFallback::MaybeSession {
49 cookie_jar,
50 maybe_session: None,
51 });
52 };
53
54 let Some(session) = repo.browser_session().lookup(session_id).await? else {
55 let session_info = session_info.mark_session_ended();
57 let cookie_jar = cookie_jar.update_session_info(&session_info);
58 return Ok(SessionOrFallback::MaybeSession {
59 cookie_jar,
60 maybe_session: None,
61 });
62 };
63
64 if session.user.deactivated_at.is_some() {
65 let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng);
67 let ctx = AccountInactiveContext::new(session.user)
68 .with_csrf(csrf_token.form_value())
69 .with_language(locale.clone());
70 let fallback = templates.render_account_deactivated(&ctx)?;
71 let response = (cookie_jar, Html(fallback)).into_response();
72 return Ok(SessionOrFallback::Fallback { response });
73 }
74
75 if session.user.locked_at.is_some() {
76 let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng);
78 let ctx = AccountInactiveContext::new(session.user)
79 .with_csrf(csrf_token.form_value())
80 .with_language(locale.clone());
81 let fallback = templates.render_account_locked(&ctx)?;
82 let response = (cookie_jar, Html(fallback)).into_response();
83 return Ok(SessionOrFallback::Fallback { response });
84 }
85
86 if session.finished_at.is_some() {
87 let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng);
92 let ctx = AccountInactiveContext::new(session.user)
93 .with_csrf(csrf_token.form_value())
94 .with_language(locale.clone());
95 let fallback = templates.render_account_logged_out(&ctx)?;
96 let response = (cookie_jar, Html(fallback)).into_response();
97 return Ok(SessionOrFallback::Fallback { response });
98 }
99
100 Ok(SessionOrFallback::MaybeSession {
101 cookie_jar,
102 maybe_session: Some(session),
103 })
104}