P0 - Panic 风险修复: - payment.rs: unwrap() → let-else safe handling - payment.rs: get_jwt_secret() expect → Result/AppError - auth.rs: openid 切片添加 len >= 8 守卫 - main.rs: 启动时 expect → unwrap_or_else 描述性 panic - main.rs: Directive::from_str 添加 fallback P1 - 逻辑/安全修复: - payment.rs: urlencoding() + 解码 bug 修复 (移除 had_escape) - payment.rs: Mock 支付添加 check_mock_payment_allowed 检查 - db.rs: 永久会员 NULL → 2099-12-31 一致化 - user.rs: 维护模式添加安全说明注释 - 自动清理 unused_variables 警告 (_is_mobile) P2 - 错误吞没修复: - main.rs: 3 处定时任务 let _ = → if let Err = tracing::error! - db.rs + admin.rs: 7 处通知/审计日志 let _ = → tracing::warn! - auth.rs: refresh token 保存 add warn 日志 P3 - 死代码清理: - models.rs: 移除 TokenResponse (dead) - models.rs: 移除 AppState 中 5 个未使用字段 (env var 直接读取) - error.rs: 移除 3 个 dead ErrorResponse 方法 - rate_limiter.rs: extract_client_ip_from_header → #[cfg(test)] - models.rs: 注释 typo fix (user_ytpe → user_type) - db.rs: RefreshToken 添加 deserialization 注释 Shell 脚本修复: - deploy.sh: run_migrations 移到 restart_service 之前 - test.sh: 移除 EXIT trap 覆盖; heredoc 引号修复; 维护模式添加 restart - common.sh: mock_key 添加 sed 转义 (防 / & 注入) 验证: cargo check 0 warnings, 8 tests passed
This commit is contained in:
72
src/db.rs
72
src/db.rs
@@ -700,7 +700,7 @@ pub async fn confirm_payment_order_by_orderno(
|
||||
is_member = true,
|
||||
membership_expires_at =
|
||||
CASE
|
||||
WHEN uo.package_type = 'permanent' THEN NULL
|
||||
WHEN uo.package_type = 'permanent' THEN '2099-12-31'::TIMESTAMPTZ
|
||||
ELSE GREATEST(COALESCE(users.membership_expires_at, NOW()), NOW()) +
|
||||
CASE
|
||||
WHEN uo.package_type = 'monthly' THEN INTERVAL '30 days'
|
||||
@@ -727,9 +727,13 @@ pub async fn confirm_payment_order_by_orderno(
|
||||
|
||||
// 审计日志
|
||||
if let Some(uid) = user_id {
|
||||
let _ = insert_payment_audit_log(pool, order_no, uid, "paid", None, None).await;
|
||||
if let Err(e) = insert_payment_audit_log(pool, order_no, uid, "paid", None, None).await {
|
||||
tracing::warn!("插入支付审计日志失败: {}", e);
|
||||
}
|
||||
// 发送支付成功通知
|
||||
let _ = insert_payment_notification(pool, uid, order_no).await;
|
||||
if let Err(e) = insert_payment_notification(pool, uid, order_no).await {
|
||||
tracing::warn!("插入支付通知失败: {}", e);
|
||||
}
|
||||
|
||||
// 验证会员到期时间是否正常
|
||||
if let Err(e) = verify_membership_after_payment(pool, order_no).await {
|
||||
@@ -808,7 +812,9 @@ pub async fn refund_payment_order(
|
||||
|
||||
// 审计日志
|
||||
let detail = if other_active.0 == 0 { "退款,会员已撤销" } else { "退款,有其他有效订单,保留会员" };
|
||||
let _ = insert_payment_audit_log(pool, order_no, user_id, "refunded", None, Some(detail)).await;
|
||||
if let Err(e) = insert_payment_audit_log(pool, order_no, user_id, "refunded", None, Some(detail)).await {
|
||||
tracing::warn!("插入支付审计日志失败: {}", e);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -901,14 +907,14 @@ pub async fn set_weather_favorite(
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
pub struct RefreshToken {
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code)] // sqlx deserialization only; not read directly
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code)] // sqlx deserialization only
|
||||
pub token: String,
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code)] // sqlx deserialization only
|
||||
pub expires_at: chrono::DateTime<chrono::Utc>,
|
||||
#[allow(dead_code)]
|
||||
#[allow(dead_code)] // sqlx deserialization only
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
@@ -1068,17 +1074,17 @@ pub async fn admin_force_confirm_order(
|
||||
UPDATE users SET
|
||||
is_member = true,
|
||||
membership_expires_at =
|
||||
CASE
|
||||
WHEN uo.package_type = 'permanent' THEN NULL
|
||||
ELSE GREATEST(COALESCE(users.membership_expires_at, NOW()), NOW()) +
|
||||
CASE
|
||||
WHEN uo.package_type = 'monthly' THEN INTERVAL '30 days'
|
||||
WHEN uo.package_type = 'quarterly' THEN INTERVAL '90 days'
|
||||
WHEN uo.package_type = 'half_year' THEN INTERVAL '182 days'
|
||||
WHEN uo.package_type = 'yearly' THEN INTERVAL '365 days'
|
||||
ELSE INTERVAL '0 days'
|
||||
END
|
||||
END
|
||||
CASE
|
||||
WHEN uo.package_type = 'permanent' THEN '2099-12-31'::TIMESTAMPTZ
|
||||
ELSE GREATEST(COALESCE(users.membership_expires_at, NOW()), NOW()) +
|
||||
CASE
|
||||
WHEN uo.package_type = 'monthly' THEN INTERVAL '30 days'
|
||||
WHEN uo.package_type = 'quarterly' THEN INTERVAL '90 days'
|
||||
WHEN uo.package_type = 'half_year' THEN INTERVAL '182 days'
|
||||
WHEN uo.package_type = 'yearly' THEN INTERVAL '365 days'
|
||||
ELSE INTERVAL '0 days'
|
||||
END
|
||||
END
|
||||
FROM updated_order uo
|
||||
WHERE users.id = $2
|
||||
RETURNING users.membership_expires_at
|
||||
@@ -1091,7 +1097,7 @@ pub async fn admin_force_confirm_order(
|
||||
.map_err(|e| AppError::Database(format!("管理员确认订单失败: {}", e)))?;
|
||||
|
||||
// 写审计日志
|
||||
let _ = insert_payment_audit_log(
|
||||
if let Err(e) = insert_payment_audit_log(
|
||||
pool,
|
||||
order_no,
|
||||
user_id,
|
||||
@@ -1099,7 +1105,10 @@ pub async fn admin_force_confirm_order(
|
||||
Some(admin_user_id),
|
||||
Some("管理员强制确认支付"),
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
{
|
||||
tracing::warn!("插入支付审计日志失败: {}", e);
|
||||
}
|
||||
|
||||
// 验证会员到期时间是否正常
|
||||
if let Err(e) = verify_membership_after_payment(pool, order_no).await {
|
||||
@@ -1109,7 +1118,7 @@ pub async fn admin_force_confirm_order(
|
||||
result
|
||||
} else {
|
||||
// 订单已处理,只写日志
|
||||
let _ = insert_payment_audit_log(
|
||||
if let Err(e) = insert_payment_audit_log(
|
||||
pool,
|
||||
order_no,
|
||||
user_id,
|
||||
@@ -1117,7 +1126,10 @@ pub async fn admin_force_confirm_order(
|
||||
Some(admin_user_id),
|
||||
Some(&format!("订单状态为 {},跳过确认", status)),
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
{
|
||||
tracing::warn!("插入支付审计日志失败: {}", e);
|
||||
}
|
||||
|
||||
// 返回当前到期时间
|
||||
sqlx::query_scalar::<_, Option<chrono::DateTime<chrono::Utc>>>(
|
||||
@@ -1182,8 +1194,11 @@ pub async fn cancel_payment_order(
|
||||
.await
|
||||
.map_err(|e| AppError::Database(format!("取消订单失败: {}", e)))?;
|
||||
|
||||
let _ = insert_payment_audit_log(pool, order_no, user_id, "cancelled", Some(user_id),
|
||||
Some("用户主动取消待支付订单")).await;
|
||||
if let Err(e) = insert_payment_audit_log(pool, order_no, user_id, "cancelled", Some(user_id),
|
||||
Some("用户主动取消待支付订单")).await
|
||||
{
|
||||
tracing::warn!("插入支付审计日志失败: {}", e);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1256,8 +1271,11 @@ pub async fn admin_refund_order(
|
||||
}
|
||||
|
||||
let detail = if status == "paid" { "管理员手动退款(已支付订单)" } else { "管理员取消订单(待支付订单)" };
|
||||
let _ = insert_payment_audit_log(pool, order_no, user_id, "refunded",
|
||||
Some(admin_user_id), Some(detail)).await;
|
||||
if let Err(e) = insert_payment_audit_log(pool, order_no, user_id, "refunded",
|
||||
Some(admin_user_id), Some(detail)).await
|
||||
{
|
||||
tracing::warn!("插入支付审计日志失败: {}", e);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user