- 登录:LoginDialog(Modal)替代 /login 页面;/login 重定向回首页 - 设置接口:GET /api/settings 公开读、PATCH 需登录 + version 乐观锁(409/400) - setting 表存 site JSON:页头(启用/速度/条目+标签+色调)、侧栏(hidden/order) - /admin:Tabs 页头/侧栏,条目增删与上下移,保存后首页生效 - 首页应用设置:ticker 文本占位符与速度、侧栏顺序与显隐 - 测试 42 passed(settings 5 例)
56 lines
1.5 KiB
Rust
56 lines
1.5 KiB
Rust
use axum::{
|
|
Json,
|
|
http::StatusCode,
|
|
response::{IntoResponse, Response},
|
|
};
|
|
use serde_json::json;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum StashError {
|
|
#[error("IO 错误: {0}")]
|
|
Io(#[from] std::io::Error),
|
|
|
|
#[error("文件监听失败: {0}")]
|
|
Watch(#[from] notify::Error),
|
|
|
|
#[error("目录不存在或非法: {0}")]
|
|
InvalidDirectory(String),
|
|
|
|
#[error("网络地址解析失败: {0}")]
|
|
AddrParse(#[from] std::net::AddrParseError),
|
|
|
|
#[error("端口绑定失败: {0}")]
|
|
ServerBind(String),
|
|
|
|
#[error("未找到资源: {0}")]
|
|
NotFound(String),
|
|
|
|
/// 数据库相关失败:打开、建表、种子导入、查询。
|
|
/// 统一收敛成一个变体,避免把 rusqlite 的类型泄漏到库的公开 API。
|
|
#[error("数据库错误: {0}")]
|
|
Database(String),
|
|
|
|
/// 乐观锁冲突:资源在本次编辑期间被别人改过。
|
|
#[error("冲突: {0}")]
|
|
Conflict(String),
|
|
}
|
|
|
|
impl IntoResponse for StashError {
|
|
fn into_response(self) -> Response {
|
|
let (status, err_msg) = match self {
|
|
StashError::NotFound(msg) => (StatusCode::NOT_FOUND, msg),
|
|
StashError::InvalidDirectory(msg) => (StatusCode::BAD_REQUEST, msg),
|
|
StashError::Conflict(msg) => (StatusCode::CONFLICT, msg),
|
|
_ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
|
|
};
|
|
|
|
let body = Json(json!({
|
|
"error": err_msg,
|
|
"status": status.as_u16(),
|
|
}));
|
|
|
|
(status, body).into_response()
|
|
}
|
|
}
|