use leptos::*; use crate::prelude::*; pub trait AuthToken { fn present(&self) -> bool; fn token(&self) -> String; fn user_id(&self) -> String; fn username(&self) -> String; fn outbox(&self) -> String; } #[derive(Debug, Clone, Copy)] pub struct Auth { pub token: Signal>, pub userid: Signal>, } #[component] pub fn LoginBox( token_tx: WriteSignal>, userid_tx: WriteSignal>, home_tl: Timeline, server_tl: Timeline, ) -> impl IntoView { let auth = use_context::().expect("missing auth context"); let username_ref: NodeRef = create_node_ref(); let password_ref: NodeRef = create_node_ref(); view! { "hi "{move || auth.username() } () .await else { if let Some(rf) = password_ref.get() { rf.set_value("") }; return }; logging::log!("logged in until {}", auth_response.expires); // update our username and token cookies let username = auth_response.user.split('/').last().unwrap_or_default().to_string(); userid_tx.set(Some(auth_response.user)); token_tx.set(Some(auth_response.token)); // reset home feed and point it to our user's inbox home_tl.reset(format!("{URL_BASE}/users/{}/inbox/page", username)); spawn_local(async move { if let Err(e) = home_tl.more(auth).await { tracing::error!("failed refreshing home timeline: {e}"); } }); // reset server feed: there may be more content now that we're authed server_tl.reset(format!("{URL_BASE}/inbox/page")); spawn_local(async move { if let Err(e) = server_tl.more(auth).await { tracing::error!("failed refreshing server timeline: {e}"); } }); }); } > } } #[derive(Debug, serde::Serialize)] struct LoginForm { email: String, password: String, } #[derive(Debug, Clone, serde::Deserialize)] struct AuthResponse { token: String, user: String, expires: chrono::DateTime, } impl AuthToken for Auth { fn token(&self) -> String { self.token.get().unwrap_or_default() } fn user_id(&self) -> String { self.userid.get().unwrap_or_default() } fn username(&self) -> String { // TODO maybe cache this?? how often do i need it? self.userid.get() .unwrap_or_default() .split('/') .last() .unwrap_or_default() .to_string() } fn present(&self) -> bool { self.token.get().map_or(false, |x| !x.is_empty()) } fn outbox(&self) -> String { format!("{URL_BASE}/users/{}/outbox", self.username()) } }