fix: 修复多处代码质量问题-移除unwrap/println/dead-code/重复代码/错误吞咽
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
// handlers/payment.rs — 支付相关处理器(接入支付宝)
|
||||
use actix_web::{get, post, web, HttpRequest, HttpResponse};
|
||||
use chrono::Utc;
|
||||
use rsa::pkcs1v15::{Pkcs1v15Sign, SigningKey, VerifyingKey};
|
||||
use rsa::pkcs1v15::SigningKey;
|
||||
use rsa::pkcs8::DecodePrivateKey;
|
||||
use rsa::signature::{SignatureEncoding, Signer, Verifier};
|
||||
use rsa::signature::{SignatureEncoding, Signer};
|
||||
use rsa::RsaPrivateKey;
|
||||
use serde::Deserialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use sha2::Sha256;
|
||||
use sqlx::postgres::PgPool;
|
||||
use std::collections::BTreeMap;
|
||||
use tracing::info;
|
||||
@@ -110,6 +110,54 @@ fn rsa2_sign(content: &str, private_key_pem: &str) -> Result<String, String> {
|
||||
))
|
||||
}
|
||||
|
||||
/// 合并 mock 支付 HTML(在 payment_page 和 alipay_pay_page 中复用)
|
||||
fn build_mock_pay_html(order_no: &str, display_name: &str, jwt: &str) -> String {
|
||||
format!(r#"<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head><meta charset="utf-8"><title>模拟支付</title></head>
|
||||
<body style="font-family:-apple-system;padding:40px;text-align:center">
|
||||
<h2 style="color:#52c41a">模拟支付环境</h2>
|
||||
<p style="color:#666">当前为沙箱模拟环境,无需真实支付</p>
|
||||
<p style="color:#999;font-size:14px">订单号: {}</p>
|
||||
<p style="color:#999;font-size:14px">套餐: {}</p>
|
||||
<button id="confirmBtn" onclick="confirmMockPay()" style="padding:12px 32px;font-size:16px;background:#1677ff;color:#fff;border:none;border-radius:4px;cursor:pointer">确认模拟支付</button>
|
||||
<p id="result"></p>
|
||||
<p><a href="/payment" style="color:#1677ff">返回重试</a></p>
|
||||
<script>
|
||||
function confirmMockPay() {{
|
||||
var btn = document.getElementById('confirmBtn');
|
||||
btn.disabled = true;
|
||||
btn.textContent = '处理中...';
|
||||
fetch('/api/payment/mock-confirm', {{
|
||||
method: 'POST',
|
||||
headers: {{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer {}'
|
||||
}},
|
||||
body: JSON.stringify({{order_id: '{}'}})
|
||||
}})
|
||||
.then(r => r.json())
|
||||
.then(data => {{
|
||||
if (data.success) {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#52c41a">支付成功!</span>';
|
||||
setTimeout(() => window.location.href = '/payment?mock=1', 1500);
|
||||
}} else {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#f5222d">失败: ' + (data.error || '未知错误') + '</span>';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '重试';
|
||||
}}
|
||||
}})
|
||||
.catch(e => {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#f5222d">网络错误</span>';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '重试';
|
||||
}});
|
||||
}}
|
||||
</script>
|
||||
</body>
|
||||
</html>"#, order_no, display_name, jwt, order_no)
|
||||
}
|
||||
|
||||
/// 验证 RSA2 签名
|
||||
#[allow(dead_code)]
|
||||
fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
|
||||
@@ -577,51 +625,7 @@ pub async fn payment_page(
|
||||
|
||||
let Some(config) = AlipayConfig::from_env() else {
|
||||
let jwt_for_mock = token.clone();
|
||||
let mock_html = format!(r#"<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head><meta charset="utf-8"><title>模拟支付</title></head>
|
||||
<body style="font-family:-apple-system;padding:40px;text-align:center">
|
||||
<h2 style="color:#52c41a">模拟支付环境</h2>
|
||||
<p style="color:#666">当前为沙箱模拟环境,无需真实支付</p>
|
||||
<p style="color:#999;font-size:14px">订单号: {}</p>
|
||||
<p style="color:#999;font-size:14px">套餐: {}</p>
|
||||
<button id="confirmBtn" onclick="confirmMockPay()" style="padding:12px 32px;font-size:16px;background:#1677ff;color:#fff;border:none;border-radius:4px;cursor:pointer">确认模拟支付</button>
|
||||
<p id="result"></p>
|
||||
<p><a href="/payment" style="color:#1677ff">返回重试</a></p>
|
||||
<script>
|
||||
function confirmMockPay() {{
|
||||
var btn = document.getElementById('confirmBtn');
|
||||
btn.disabled = true;
|
||||
btn.textContent = '处理中...';
|
||||
fetch('/api/payment/mock-confirm', {{
|
||||
method: 'POST',
|
||||
headers: {{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer {}'
|
||||
}},
|
||||
body: JSON.stringify({{order_id: '{}'}})
|
||||
}})
|
||||
.then(r => r.json())
|
||||
.then(data => {{
|
||||
if (data.success) {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#52c41a">支付成功!</span>';
|
||||
setTimeout(() => window.location.href = '/payment?mock=1', 1500);
|
||||
}} else {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#f5222d">失败: ' + (data.error || '未知错误') + '</span>';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '重试';
|
||||
}}
|
||||
}})
|
||||
.catch(e => {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#f5222d">网络错误</span>';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '重试';
|
||||
}});
|
||||
}}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"#, order_no, pkg.display_name, jwt_for_mock, order_no);
|
||||
let mock_html = build_mock_pay_html(&order_no, pkg.display_name, &jwt_for_mock);
|
||||
return Ok(HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(mock_html));
|
||||
@@ -676,51 +680,7 @@ pub async fn alipay_pay_page(
|
||||
|
||||
let Some(config) = AlipayConfig::from_env() else {
|
||||
let jwt_for_mock = token.clone();
|
||||
let mock_html = format!(r#"<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head><meta charset="utf-8"><title>模拟支付</title></head>
|
||||
<body style="font-family:-apple-system;padding:40px;text-align:center">
|
||||
<h2 style="color:#52c41a">模拟支付环境</h2>
|
||||
<p style="color:#666">当前为沙箱模拟环境,无需真实支付</p>
|
||||
<p style="color:#999;font-size:14px">订单号: {}</p>
|
||||
<p style="color:#999;font-size:14px">套餐: {}</p>
|
||||
<button id="confirmBtn" onclick="confirmMockPay()" style="padding:12px 32px;font-size:16px;background:#1677ff;color:#fff;border:none;border-radius:4px;cursor:pointer">确认模拟支付</button>
|
||||
<p id="result"></p>
|
||||
<p><a href="/payment" style="color:#1677ff">返回重试</a></p>
|
||||
<script>
|
||||
function confirmMockPay() {{
|
||||
var btn = document.getElementById('confirmBtn');
|
||||
btn.disabled = true;
|
||||
btn.textContent = '处理中...';
|
||||
fetch('/api/payment/mock-confirm', {{
|
||||
method: 'POST',
|
||||
headers: {{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer {}'
|
||||
}},
|
||||
body: JSON.stringify({{order_id: '{}'}})
|
||||
}})
|
||||
.then(r => r.json())
|
||||
.then(data => {{
|
||||
if (data.success) {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#52c41a">支付成功!</span>';
|
||||
setTimeout(() => window.location.href = '/payment?mock=1', 1500);
|
||||
}} else {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#f5222d">失败: ' + (data.error || '未知错误') + '</span>';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '重试';
|
||||
}}
|
||||
}})
|
||||
.catch(e => {{
|
||||
document.getElementById('result').innerHTML = '<span style="color:#f5222d">网络错误</span>';
|
||||
btn.disabled = false;
|
||||
btn.textContent = '重试';
|
||||
}});
|
||||
}}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"#, query.order_no, pkg.display_name, jwt_for_mock, query.order_no);
|
||||
let mock_html = build_mock_pay_html(&query.order_no, pkg.display_name, &jwt_for_mock);
|
||||
return Ok(HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(mock_html));
|
||||
@@ -860,11 +820,10 @@ pub async fn payment_success(
|
||||
let order_no = query.order_no.as_deref().unwrap_or("");
|
||||
|
||||
// 同步确认订单(幂等:已确认的订单会跳过)
|
||||
if !order_no.is_empty() {
|
||||
if let Err(e) = db::confirm_payment_order_by_orderno(pool.get_ref(), order_no).await {
|
||||
if !order_no.is_empty()
|
||||
&& let Err(e) = db::confirm_payment_order_by_orderno(pool.get_ref(), order_no).await {
|
||||
tracing::warn!("支付成功页同步确认失败(可能是异步回调已处理): {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
let html = build_success_html(order_no);
|
||||
HttpResponse::Ok()
|
||||
@@ -948,8 +907,10 @@ pub async fn sync_order(
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
let user_id = claims.user_id;
|
||||
|
||||
// 尝试确认订单(幂等)
|
||||
let _ = db::confirm_payment_order(pool.get_ref(), &body.order_id, user_id).await;
|
||||
// 尝试确认订单(幂等),失败时记录日志
|
||||
if let Err(e) = db::confirm_payment_order(pool.get_ref(), &body.order_id, user_id).await {
|
||||
tracing::warn!("确认订单失败(可能已被异步回调处理): {}", e);
|
||||
}
|
||||
|
||||
// 查询最新状态
|
||||
let user = sqlx::query_as::<_, (bool, Option<chrono::DateTime<chrono::Utc>>)>(
|
||||
@@ -962,7 +923,7 @@ pub async fn sync_order(
|
||||
.ok_or_else(|| AppError::NotFound("用户不存在".to_string()))?;
|
||||
|
||||
let (is_paid, paid_expires_at) = user;
|
||||
let is_paid_active = is_paid && (paid_expires_at.is_none() || paid_expires_at.unwrap() > Utc::now());
|
||||
let is_paid_active = is_paid && paid_expires_at.map_or(true, |expires| expires > Utc::now());
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
@@ -1082,7 +1043,7 @@ pub async fn generate_code(
|
||||
pub async fn payment_login_status(
|
||||
pool: web::Data<PgPool>,
|
||||
query: web::Query<LoginStatusQuery>,
|
||||
app_state: web::Data<crate::models::AppState>,
|
||||
_app_state: web::Data<crate::models::AppState>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
let code = query.code.trim();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user