diff --git a/src/api/auth.rs b/src/api/auth.rs index 0dec85b..86e8dcd 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -5,6 +5,7 @@ use dioxus::prelude::*; use http::header::{HeaderValue, SET_COOKIE}; use crate::auth::{password, session}; +use crate::auth::session::get_session_from_ctx; use crate::db::pool::get_conn; use crate::models::user::{PublicUser, User, UserRole}; @@ -36,20 +37,6 @@ fn validate_password(password: &str) -> Result<(), String> { Ok(()) } -#[cfg(feature = "server")] -fn parse_session_token(cookie_header: &str) -> Option<&str> { - cookie_header.split(';').map(|s| s.trim()).find_map(|pair| { - let mut parts = pair.splitn(2, '='); - let name = parts.next()?.trim(); - let value = parts.next()?.trim(); - if name == "session" { - Some(value) - } else { - None - } - }) -} - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct AuthResponse { pub success: bool, @@ -216,17 +203,7 @@ pub async fn login(username: String, password: String) -> Result Result { - let token = if let Some(ctx) = dioxus::fullstack::FullstackContext::current() { - let parts = ctx.parts_mut(); - parts - .headers - .get("cookie") - .and_then(|h| h.to_str().ok()) - .and_then(parse_session_token) - .map(|s| s.to_string()) - } else { - None - }; + let token = get_session_from_ctx(); let client = get_conn().await.map_err(|e| { tracing::error!("Logout DB connection failed: {:?}", e); @@ -266,17 +243,7 @@ pub struct CurrentUserResponse { #[server(GetCurrentUser, "/api")] pub async fn get_current_user() -> Result { - let token = if let Some(ctx) = dioxus::fullstack::FullstackContext::current() { - let parts = ctx.parts_mut(); - parts - .headers - .get("cookie") - .and_then(|h| h.to_str().ok()) - .and_then(parse_session_token) - .map(|s| s.to_string()) - } else { - None - }; + let token = get_session_from_ctx(); let Some(token) = token else { return Ok(CurrentUserResponse { user: None }); diff --git a/src/api/mod.rs b/src/api/mod.rs index 949724c..48191ec 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,2 +1,3 @@ pub mod auth; pub mod posts; +pub mod utils; diff --git a/src/api/posts.rs b/src/api/posts.rs index a64cad5..f3ee9c8 100644 --- a/src/api/posts.rs +++ b/src/api/posts.rs @@ -2,6 +2,8 @@ use dioxus::prelude::*; +use crate::auth::session::get_session_from_ctx; +use crate::api::utils::{db_conn_error, query_error}; use crate::db::pool::get_conn; use crate::models::post::{Post, PostStats, PostStatus, Tag}; use crate::models::user::{User, UserRole}; @@ -10,42 +12,15 @@ use crate::models::user::{User, UserRole}; // Server-side helpers (only compiled when server feature is enabled) // ============================================================================ -#[cfg(feature = "server")] -fn parse_session_token(cookie_header: &str) -> Option<&str> { - cookie_header.split(';').map(|s| s.trim()).find_map(|pair| { - let mut parts = pair.splitn(2, '='); - let name = parts.next()?.trim(); - let value = parts.next()?.trim(); - if name == "session" { - Some(value) - } else { - None - } - }) -} - #[cfg(feature = "server")] async fn get_current_admin_user() -> Result { - let token = if let Some(ctx) = dioxus::fullstack::FullstackContext::current() { - let parts = ctx.parts_mut(); - parts - .headers - .get("cookie") - .and_then(|h| h.to_str().ok()) - .and_then(parse_session_token) - .map(|s| s.to_string()) - } else { - None - }; + let token = get_session_from_ctx(); let Some(token) = token else { return Err(ServerFnError::new("未登录")); }; - let client = get_conn().await.map_err(|e| { - tracing::error!("DB connection failed: {:?}", e); - ServerFnError::new(format!("数据库连接失败: {}", e)) - })?; + let client = get_conn().await.map_err(db_conn_error)?; let row = client .query_opt( @@ -56,10 +31,7 @@ async fn get_current_admin_user() -> Result { &[&token], ) .await - .map_err(|e| { - tracing::error!("query failed: {:?}", e); - ServerFnError::new(format!("查询失败: {}", e)) - })?; + .map_err(query_error)?; let user = match row { Some(row) => { diff --git a/src/api/utils.rs b/src/api/utils.rs new file mode 100644 index 0000000..370b8a0 --- /dev/null +++ b/src/api/utils.rs @@ -0,0 +1,15 @@ +#![allow(clippy::unused_unit)] + +use dioxus::prelude::*; + +#[cfg(feature = "server")] +pub fn db_conn_error(e: impl std::fmt::Display) -> ServerFnError { + tracing::error!("DB connection failed: {}", e); + ServerFnError::new(format!("数据库连接失败: {}", e)) +} + +#[cfg(feature = "server")] +pub fn query_error(e: impl std::fmt::Display) -> ServerFnError { + tracing::error!("Query failed: {}", e); + ServerFnError::new(format!("查询失败: {}", e)) +} diff --git a/src/auth/session.rs b/src/auth/session.rs index 8041440..78d9e1c 100644 --- a/src/auth/session.rs +++ b/src/auth/session.rs @@ -10,3 +10,31 @@ pub fn generate_token() -> String { pub fn default_expiry() -> DateTime { Utc::now() + Duration::days(30) } + +pub fn parse_session_token(cookie_header: &str) -> Option<&str> { + cookie_header.split(';').map(|s| s.trim()).find_map(|pair| { + let mut parts = pair.splitn(2, '='); + let name = parts.next()?.trim(); + let value = parts.next()?.trim(); + if name == "session" { + Some(value) + } else { + None + } + }) +} + +#[cfg(feature = "server")] +pub fn get_session_from_ctx() -> Option { + use dioxus::fullstack::FullstackContext; + + FullstackContext::current().and_then(|ctx| { + let parts = ctx.parts_mut(); + parts + .headers + .get("cookie") + .and_then(|h| h.to_str().ok()) + .and_then(parse_session_token) + .map(|s| s.to_string()) + }) +}