chore: code cleanup - formatting, EOF newlines, model helper, and UI tweaks

This commit is contained in:
xfy 2026-06-02 17:25:58 +08:00
parent 1950646bef
commit 9c5b09a278
10 changed files with 85 additions and 70 deletions

View File

@ -42,6 +42,8 @@ RUST_LOG=info
Run migrations before first dev server start: Run migrations before first dev server start:
```bash ```bash
./migrate.sh # preferred: auto-creates DB, runs all migrations in order
# or manually:
psql $DATABASE_URL -f migrations/001_init.sql psql $DATABASE_URL -f migrations/001_init.sql
``` ```

View File

@ -38,10 +38,7 @@ fn validate_password(password: &str) -> Result<(), String> {
#[cfg(feature = "server")] #[cfg(feature = "server")]
fn parse_session_token(cookie_header: &str) -> Option<&str> { fn parse_session_token(cookie_header: &str) -> Option<&str> {
cookie_header cookie_header.split(';').map(|s| s.trim()).find_map(|pair| {
.split(';')
.map(|s| s.trim())
.find_map(|pair| {
let mut parts = pair.splitn(2, '='); let mut parts = pair.splitn(2, '=');
let name = parts.next()?.trim(); let name = parts.next()?.trim();
let value = parts.next()?.trim(); let value = parts.next()?.trim();
@ -88,10 +85,7 @@ pub async fn register(
}); });
} }
let client = DB_POOL let client = DB_POOL.get().await.map_err(|e| {
.get()
.await
.map_err(|e| {
tracing::error!("Register DB connection failed: {:?}", e); tracing::error!("Register DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e)) ServerFnError::new(format!("数据库连接失败: {}", e))
})?; })?;
@ -113,8 +107,7 @@ pub async fn register(
}); });
} }
let password_hash = password::hash_password(&password) let password_hash = password::hash_password(&password).map_err(|e| {
.map_err(|e| {
tracing::error!("Register password hash failed: {:?}", e); tracing::error!("Register password hash failed: {:?}", e);
ServerFnError::new(format!("密码哈希失败: {}", e)) ServerFnError::new(format!("密码哈希失败: {}", e))
})?; })?;
@ -148,14 +141,8 @@ pub async fn register(
} }
#[server(Login, "/api")] #[server(Login, "/api")]
pub async fn login( pub async fn login(username: String, password: String) -> Result<AuthResponse, ServerFnError> {
username: String, let client = DB_POOL.get().await.map_err(|e| {
password: String,
) -> Result<AuthResponse, ServerFnError> {
let client = DB_POOL
.get()
.await
.map_err(|e| {
tracing::error!("Login DB connection failed: {:?}", e); tracing::error!("Login DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e)) ServerFnError::new(format!("数据库连接失败: {}", e))
})?; })?;
@ -182,8 +169,7 @@ pub async fn login(
}; };
let password_hash: String = row.get("password_hash"); let password_hash: String = row.get("password_hash");
let valid = password::verify_password(&password, &password_hash) let valid = password::verify_password(&password, &password_hash).map_err(|e| {
.map_err(|e| {
tracing::error!("Login password verify failed: {:?}", e); tracing::error!("Login password verify failed: {:?}", e);
ServerFnError::new(format!("密码验证失败: {}", e)) ServerFnError::new(format!("密码验证失败: {}", e))
})?; })?;
@ -242,10 +228,7 @@ pub async fn logout() -> Result<AuthResponse, ServerFnError> {
None None
}; };
let client = DB_POOL let client = DB_POOL.get().await.map_err(|e| {
.get()
.await
.map_err(|e| {
tracing::error!("Logout DB connection failed: {:?}", e); tracing::error!("Logout DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e)) ServerFnError::new(format!("数据库连接失败: {}", e))
})?; })?;
@ -254,9 +237,7 @@ pub async fn logout() -> Result<AuthResponse, ServerFnError> {
if let Some(ctx) = dioxus::fullstack::FullstackContext::current() { if let Some(ctx) = dioxus::fullstack::FullstackContext::current() {
ctx.add_response_header( ctx.add_response_header(
SET_COOKIE, SET_COOKIE,
HeaderValue::from_static( HeaderValue::from_static("session=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax"),
"session=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax",
),
); );
} }
@ -301,10 +282,7 @@ pub async fn get_current_user() -> Result<CurrentUserResponse, ServerFnError> {
return Ok(CurrentUserResponse { user: None }); return Ok(CurrentUserResponse { user: None });
}; };
let client = DB_POOL let client = DB_POOL.get().await.map_err(|e| {
.get()
.await
.map_err(|e| {
tracing::error!("GetCurrentUser DB connection failed: {:?}", e); tracing::error!("GetCurrentUser DB connection failed: {:?}", e);
ServerFnError::new(format!("数据库连接失败: {}", e)) ServerFnError::new(format!("数据库连接失败: {}", e))
})?; })?;

View File

@ -40,9 +40,13 @@ fn main() {
.serve_dioxus_application(config, router::AppRouter) .serve_dioxus_application(config, router::AppRouter)
.layer( .layer(
TraceLayer::new_for_http() TraceLayer::new_for_http()
.make_span_with(tower_http::trace::DefaultMakeSpan::new().level(Level::INFO)) .make_span_with(
tower_http::trace::DefaultMakeSpan::new().level(Level::INFO),
)
.on_request(tower_http::trace::DefaultOnRequest::new().level(Level::INFO)) .on_request(tower_http::trace::DefaultOnRequest::new().level(Level::INFO))
.on_response(tower_http::trace::DefaultOnResponse::new().level(Level::INFO)), .on_response(
tower_http::trace::DefaultOnResponse::new().level(Level::INFO),
),
); );
Ok(router) Ok(router)

View File

@ -42,6 +42,14 @@ pub struct Post {
pub tags: Vec<String>, pub tags: Vec<String>,
} }
impl Post {
pub fn formatted_date(&self) -> String {
self.published_at
.map(|d| d.format("%Y-%m-%d").to_string())
.unwrap_or_else(|| self.created_at.format("%Y-%m-%d").to_string())
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Tag { pub struct Tag {
pub id: i32, pub id: i32,

View File

@ -38,7 +38,7 @@ pub fn Posts() -> Element {
thead { thead {
tr { class: "border-b border-gray-200 dark:border-[#333] text-left text-gray-500 dark:text-[#9b9c9d]", tr { class: "border-b border-gray-200 dark:border-[#333] text-left text-gray-500 dark:text-[#9b9c9d]",
th { class: "px-4 py-3 font-medium", "标题" } th { class: "px-4 py-3 font-medium", "标题" }
th { class: "px-4 py-3 font-medium w-24", "状态" } th { class: "px-4 py-3 font-medium w-24 text-center", "状态" }
th { class: "px-4 py-3 font-medium w-32", "日期" } th { class: "px-4 py-3 font-medium w-32", "日期" }
th { class: "px-4 py-3 font-medium w-24 text-right", "操作" } th { class: "px-4 py-3 font-medium w-24 text-right", "操作" }
} }
@ -107,9 +107,15 @@ fn PostRow(post: Post, deleting: bool, on_delete: EventHandler<i32>) -> Element
.unwrap_or_else(|| post.created_at.format("%Y-%m-%d").to_string()); .unwrap_or_else(|| post.created_at.format("%Y-%m-%d").to_string());
let (status_label, status_class) = if post.status == PostStatus::Published { let (status_label, status_class) = if post.status == PostStatus::Published {
("已发布", "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300") (
"已发布",
"bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300",
)
} else { } else {
("草稿", "bg-gray-100 dark:bg-[#333] text-gray-600 dark:text-[#9b9c9d]") (
"草稿",
"bg-gray-100 dark:bg-[#333] text-gray-600 dark:text-[#9b9c9d]",
)
}; };
rsx! { rsx! {
@ -125,7 +131,7 @@ fn PostRow(post: Post, deleting: bool, on_delete: EventHandler<i32>) -> Element
"{post.title}" "{post.title}"
} }
} }
td { class: "px-4 py-3", td { class: "px-4 py-3 text-center",
span { class: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {status_class}", span { class: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium {status_class}",
"{status_label}" "{status_label}"
} }

View File

@ -120,7 +120,16 @@ pub fn Write() -> Element {
error.set(None); error.set(None);
spawn(async move { spawn(async move {
match create_post(title().trim().to_string(), slug_opt, summary_opt, md, status(), tags_list).await { match create_post(
title().trim().to_string(),
slug_opt,
summary_opt,
md,
status(),
tags_list,
)
.await
{
Ok(CreatePostResponse { success: true, .. }) => { Ok(CreatePostResponse { success: true, .. }) => {
saving.set(false); saving.set(false);
success.set(true); success.set(true);
@ -131,7 +140,11 @@ pub fn Write() -> Element {
} }
let _ = dioxus::router::navigator().push("/admin"); let _ = dioxus::router::navigator().push("/admin");
} }
Ok(CreatePostResponse { success: false, message, .. }) => { Ok(CreatePostResponse {
success: false,
message,
..
}) => {
saving.set(false); saving.set(false);
error.set(Some(message)); error.set(Some(message));
} }

View File

@ -33,7 +33,11 @@ pub fn Register() -> Element {
Ok(AuthResponse { success: true, .. }) => { Ok(AuthResponse { success: true, .. }) => {
success.set(true); success.set(true);
} }
Ok(AuthResponse { success: false, message, .. }) => { Ok(AuthResponse {
success: false,
message,
..
}) => {
error.set(Some(message)); error.set(Some(message));
} }
Err(e) => { Err(e) => {