feat: 添加PAYMENT_MAINTENANCE_MODE维护模式 + ServiceUnavailable错误
This commit is contained in:
@@ -9,6 +9,9 @@ use crate::error::AppError;
|
||||
|
||||
// 用于插入weather_data的数据
|
||||
pub async fn insert_weather_data(pool: &PgPool, weather_data: &WeatherData, user_id: i32) -> Result<i32, AppError> {
|
||||
// 维护模式:跳过所有配额检查
|
||||
let is_maintenance = std::env::var("PAYMENT_MAINTENANCE_MODE").ok() == Some("true".to_string());
|
||||
if !is_maintenance {
|
||||
// 配额检查:非付费用户数据条数限制
|
||||
let user = get_user_by_id(pool, user_id).await?;
|
||||
let is_paid_active = user.is_paid && user.paid_expires_at.map_or(true, |expires| expires > Utc::now());
|
||||
@@ -24,6 +27,7 @@ pub async fn insert_weather_data(pool: &PgPool, weather_data: &WeatherData, user
|
||||
return Err(AppError::Forbidden("数据条数已达上限,请升级为付费用户".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 准备插入数据的 SQL 语句
|
||||
let insert_query = r#"
|
||||
|
||||
@@ -53,6 +53,7 @@ pub enum AppError {
|
||||
Internal(String),
|
||||
Database(String),
|
||||
TooManyRequests(String),
|
||||
ServiceUnavailable(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for AppError {
|
||||
@@ -65,6 +66,7 @@ impl fmt::Display for AppError {
|
||||
AppError::Internal(msg) => write!(f, "{}", msg),
|
||||
AppError::Database(msg) => write!(f, "{}", msg),
|
||||
AppError::TooManyRequests(msg) => write!(f, "{}", msg),
|
||||
AppError::ServiceUnavailable(msg) => write!(f, "{}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +80,7 @@ impl ResponseError for AppError {
|
||||
AppError::BadRequest(_) => StatusCode::BAD_REQUEST,
|
||||
AppError::Internal(_) | AppError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
AppError::TooManyRequests(_) => StatusCode::TOO_MANY_REQUESTS,
|
||||
AppError::ServiceUnavailable(_) => StatusCode::SERVICE_UNAVAILABLE,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +172,7 @@ impl ResponseError for AppError {
|
||||
AppError::BadRequest(_) => "请求无效",
|
||||
AppError::Internal(_) | AppError::Database(_) => "服务器错误",
|
||||
AppError::TooManyRequests(_) => "请求过于频繁",
|
||||
AppError::ServiceUnavailable(_) => "服务暂不可用",
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -255,6 +255,16 @@ fn build_alipay_form_html(
|
||||
|
||||
// ===== 提取 JWT token =====
|
||||
|
||||
/// 维护模式守卫:PAYMENT_MAINTENANCE_MODE=true 时所有支付接口返回 503
|
||||
fn check_payment_maintenance() -> Result<(), AppError> {
|
||||
if std::env::var("PAYMENT_MAINTENANCE_MODE").ok() == Some("true".to_string()) {
|
||||
return Err(AppError::ServiceUnavailable(
|
||||
"支付系统维护中,请稍后再试".to_string()
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_token(req: &HttpRequest) -> Option<String> {
|
||||
req.headers()
|
||||
.get("Authorization")?
|
||||
@@ -272,6 +282,7 @@ fn get_jwt_secret() -> String {
|
||||
|
||||
#[get("/payment")]
|
||||
pub async fn payment_index() -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
let html = r##"<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
@@ -594,6 +605,7 @@ pub async fn payment_page(
|
||||
pool: web::Data<PgPool>,
|
||||
query: web::Query<PaymentPageQuery>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
let token = extract_token(&req)
|
||||
.or_else(|| query.jwt.clone())
|
||||
.ok_or_else(|| AppError::Unauthorized("未登录".to_string()))?;
|
||||
@@ -665,6 +677,7 @@ pub async fn alipay_pay_page(
|
||||
req: HttpRequest,
|
||||
query: web::Query<AlipayPayQuery>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
let token = extract_token(&req).ok_or_else(|| AppError::Unauthorized("未登录".to_string()))?;
|
||||
crate::auth::verify_token(&token, &get_jwt_secret())
|
||||
.map_err(|_| AppError::Unauthorized("Token 无效".to_string()))?;
|
||||
@@ -908,6 +921,7 @@ pub async fn create_order(
|
||||
claims: web::ReqData<Claims>,
|
||||
body: web::Json<CreateOrderRequest>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
let user_id = claims.user_id;
|
||||
|
||||
let pkg = match get_package_info(&body.package_type) {
|
||||
@@ -950,6 +964,7 @@ pub async fn mock_confirm(
|
||||
claims: web::ReqData<Claims>,
|
||||
body: web::Json<MockConfirmRequest>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
let user_id = claims.user_id;
|
||||
|
||||
let expires_at =
|
||||
@@ -973,6 +988,7 @@ pub async fn sync_order(
|
||||
claims: web::ReqData<Claims>,
|
||||
body: web::Json<MockConfirmRequest>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
let user_id = claims.user_id;
|
||||
|
||||
// 尝试确认订单(幂等),失败时记录日志
|
||||
@@ -1015,6 +1031,7 @@ pub async fn cancel_order(
|
||||
claims: web::ReqData<Claims>,
|
||||
body: web::Json<CancelOrderRequest>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
check_payment_maintenance()?;
|
||||
db::cancel_payment_order(pool.get_ref(), &body.order_id, claims.user_id).await?;
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1052,6 +1069,8 @@ pub async fn get_user_quota(
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
let user_id = claims.user_id;
|
||||
|
||||
let is_maintenance = std::env::var("PAYMENT_MAINTENANCE_MODE").ok() == Some("true".to_string());
|
||||
|
||||
let (used, is_paid_active, paid_expires_at) =
|
||||
db::get_user_quota(pool.get_ref(), user_id).await?;
|
||||
let limit: i64 = std::env::var("FREE_USER_DATA_LIMIT")
|
||||
@@ -1059,14 +1078,21 @@ pub async fn get_user_quota(
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(20);
|
||||
|
||||
let (unlimited, active) = if is_maintenance {
|
||||
(true, true)
|
||||
} else {
|
||||
(is_paid_active, is_paid_active)
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"data": {
|
||||
"used": used,
|
||||
"limit": limit,
|
||||
"unlimited": is_paid_active,
|
||||
"is_paid_active": is_paid_active,
|
||||
"unlimited": unlimited,
|
||||
"is_paid_active": active,
|
||||
"paid_expires_at": paid_expires_at,
|
||||
"maintenance_mode": is_maintenance,
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -16,8 +16,13 @@ pub async fn get_current_user_profile(
|
||||
info!("获取当前用户信息, 用户ID: {}", user_id);
|
||||
|
||||
let user = db::get_user_by_id(pool.get_ref(), user_id).await?;
|
||||
let is_paid_active = user.is_paid &&
|
||||
user.paid_expires_at.map_or(true, |expires| expires > chrono::Utc::now());
|
||||
let is_maintenance = std::env::var("PAYMENT_MAINTENANCE_MODE").ok() == Some("true".to_string());
|
||||
let is_paid_active = if is_maintenance {
|
||||
true
|
||||
} else {
|
||||
user.is_paid &&
|
||||
user.paid_expires_at.map_or(true, |expires| expires > chrono::Utc::now())
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
|
||||
Reference in New Issue
Block a user