diff --git a/src/api/auth.rs b/src/api/auth.rs index cbc1172..f16de87 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -15,9 +15,13 @@ use http::header::{HeaderValue, SET_COOKIE}; use crate::api::error::AppError; #[cfg(feature = "server")] use crate::auth::session::get_session_from_ctx; +#[cfg(feature = "server")] use crate::auth::{password, session}; +#[cfg(feature = "server")] use crate::db::pool::get_conn; -use crate::models::user::{PublicUser, User, UserRole}; +#[cfg(feature = "server")] +use crate::models::user::{User, UserRole}; +use crate::models::user::PublicUser; #[allow(dead_code)] fn validate_username(username: &str) -> Result<(), String> { diff --git a/src/api/comments/helpers.rs b/src/api/comments/helpers.rs index 6c26fae..c12f7f8 100644 --- a/src/api/comments/helpers.rs +++ b/src/api/comments/helpers.rs @@ -68,6 +68,7 @@ pub fn row_to_admin_comment(row: &tokio_postgres::Row) -> AdminComment { } /// 将 UTC 时间格式化为相对时间(刚刚 / N 分钟前 / N 小时前 / N 天前 / 日期)。 +#[cfg(feature = "server")] pub fn format_relative_time(dt: chrono::DateTime) -> String { let now = chrono::Utc::now(); let diff = now.signed_duration_since(dt); @@ -139,6 +140,7 @@ pub fn validate_comment_content(content: &str) -> Result<(), String> { } /// 计算评论内容哈希,用于检测短时间内的重复提交。 +#[cfg(feature = "server")] pub fn compute_content_hash( post_id: i32, parent_id: Option, diff --git a/src/api/comments/types.rs b/src/api/comments/types.rs index cfd4c4e..0de9c23 100644 --- a/src/api/comments/types.rs +++ b/src/api/comments/types.rs @@ -52,6 +52,7 @@ pub struct CommentTreeResponse { /// 评论计数响应。 #[derive(Debug, Clone, Serialize, Deserialize)] +#[allow(dead_code)] pub struct CommentCountResponse { /// 评论数量。 pub count: i64, @@ -59,6 +60,7 @@ pub struct CommentCountResponse { /// 待审核评论列表响应。 #[derive(Debug, Clone, Serialize, Deserialize)] +#[allow(dead_code)] pub struct PendingCommentsResponse { /// 待审核评论列表。 pub comments: Vec, diff --git a/src/api/posts/create.rs b/src/api/posts/create.rs index 4b40383..197de9f 100644 --- a/src/api/posts/create.rs +++ b/src/api/posts/create.rs @@ -14,7 +14,9 @@ use super::helpers::{clean_tags, get_current_admin_user, sync_tags}; use super::types::CreatePostResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; +#[cfg(feature = "server")] use crate::models::post::PostStatus; /// 创建一篇新文章。 diff --git a/src/api/posts/delete.rs b/src/api/posts/delete.rs index c8dfec5..b1f9043 100644 --- a/src/api/posts/delete.rs +++ b/src/api/posts/delete.rs @@ -12,6 +12,7 @@ use super::helpers::get_current_admin_user; use super::types::CreatePostResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; /// 删除指定文章。 diff --git a/src/api/posts/list.rs b/src/api/posts/list.rs index 34f2082..81ca38e 100644 --- a/src/api/posts/list.rs +++ b/src/api/posts/list.rs @@ -12,12 +12,14 @@ use super::helpers::{get_current_admin_user, row_to_post_list}; use super::types::PostListResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; /// 单页允许的最大文章数。 /// /// 公开的 `list_published_posts` 接口无需认证,若不对 `per_page` 设上限, /// 攻击者可传入巨大值迫使数据库扫描并实例化超大 Vec,造成内存放大与拒绝服务。 +#[cfg(feature = "server")] const MAX_PER_PAGE: i32 = 50; /// 允许的最大页码。 @@ -25,11 +27,13 @@ const MAX_PER_PAGE: i32 = 50; /// `page` 无上限时,攻击者可用海量不同 `page` 值撑大缓存键空间(缓存污染), /// 并触发无意义的超大 `OFFSET` 扫描。10_000 对任何实际博客都足够宽裕 /// (配合 `MAX_PER_PAGE` 最多覆盖 50 万篇文章),同时把缓存键空间限制在有限范围。 +#[cfg(feature = "server")] const MAX_PAGE: i32 = 10_000; /// 将分页参数钳制到安全范围:页码 1–`MAX_PAGE`,每页 1–`MAX_PER_PAGE`。 /// /// 注意:返回值必须同时用于缓存键与 SQL 查询,避免同一逻辑页落入不同缓存条目。 +#[cfg(feature = "server")] fn clamp_pagination(page: i32, per_page: i32) -> (i32, i32) { (page.clamp(1, MAX_PAGE), per_page.clamp(1, MAX_PER_PAGE)) } diff --git a/src/api/posts/read.rs b/src/api/posts/read.rs index 5a55a0f..e4f52d3 100644 --- a/src/api/posts/read.rs +++ b/src/api/posts/read.rs @@ -12,6 +12,7 @@ use super::helpers::{get_current_admin_user, row_to_post_full, row_to_post_list} use super::types::SinglePostResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; /// 根据文章 id 获取详情。 diff --git a/src/api/posts/rebuild.rs b/src/api/posts/rebuild.rs index a71803b..bc56a84 100644 --- a/src/api/posts/rebuild.rs +++ b/src/api/posts/rebuild.rs @@ -12,11 +12,14 @@ use super::helpers::get_current_admin_user; #[cfg(feature = "server")] use crate::api::error::AppError; use crate::api::posts::RebuildResult; +#[cfg(feature = "server")] use crate::db::pool::get_conn; /// 单次重建批处理数量上限。 +#[cfg(feature = "server")] const REBUILD_BATCH_LIMIT: i64 = 500; /// 返回给前端展示的最大错误条数。 +#[cfg(feature = "server")] const MAX_DISPLAY_ERRORS: usize = 5; /// 批量重建文章 content_html 与 toc_html。 diff --git a/src/api/posts/search.rs b/src/api/posts/search.rs index 66106c9..0612629 100644 --- a/src/api/posts/search.rs +++ b/src/api/posts/search.rs @@ -12,6 +12,7 @@ use super::helpers::row_to_post_list; use super::types::PostListResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; /// 搜索已发布文章。 diff --git a/src/api/posts/stats.rs b/src/api/posts/stats.rs index db3863e..a0dd4fa 100644 --- a/src/api/posts/stats.rs +++ b/src/api/posts/stats.rs @@ -11,7 +11,9 @@ use super::helpers::get_current_admin_user; use super::types::PostStatsResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; +#[cfg(feature = "server")] use crate::models::post::PostStats; /// 获取文章统计信息。 diff --git a/src/api/posts/tags.rs b/src/api/posts/tags.rs index cfe7035..5f56a45 100644 --- a/src/api/posts/tags.rs +++ b/src/api/posts/tags.rs @@ -9,7 +9,9 @@ use dioxus::prelude::*; use super::types::TagListResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; +#[cfg(feature = "server")] use crate::models::post::Tag; /// 获取全部标签列表。 diff --git a/src/api/posts/update.rs b/src/api/posts/update.rs index a27e6e8..c1772dd 100644 --- a/src/api/posts/update.rs +++ b/src/api/posts/update.rs @@ -14,7 +14,9 @@ use super::helpers::{clean_tags, get_current_admin_user, sync_tags}; use super::types::CreatePostResponse; #[cfg(feature = "server")] use crate::api::error::AppError; +#[cfg(feature = "server")] use crate::db::pool::get_conn; +#[cfg(feature = "server")] use crate::models::post::PostStatus; /// 更新指定文章。 diff --git a/src/api/slug.rs b/src/api/slug.rs index 4c0a3d0..aac06cd 100644 --- a/src/api/slug.rs +++ b/src/api/slug.rs @@ -6,6 +6,7 @@ #![allow(clippy::unused_unit, deprecated)] +#[cfg(feature = "server")] use dioxus::prelude::*; #[cfg(feature = "server")] diff --git a/src/models/comment.rs b/src/models/comment.rs index 4cb1c66..355f6d7 100644 --- a/src/models/comment.rs +++ b/src/models/comment.rs @@ -22,6 +22,7 @@ pub enum CommentStatus { impl CommentStatus { /// 将数据库或 API 中的状态字符串解析为 CommentStatus,未知值默认回退到 Pending。 + #[cfg(feature = "server")] pub fn from_str(s: &str) -> Self { match s { "approved" => Self::Approved,