mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Merge pull request #404 from RWDai/fix/python-v063-user-import-compat
Preserve Python user import compatibility
This commit is contained in:
@@ -516,6 +516,13 @@ fn imported_optional_f64(value: Option<&Value>, field_name: &str) -> Result<Opti
|
||||
.filter(|value| value.is_finite())
|
||||
.ok_or_else(|| format!("{field_name} 必须是有限数值"))
|
||||
.map(Some),
|
||||
Some(Value::String(value)) => value
|
||||
.trim()
|
||||
.parse::<f64>()
|
||||
.ok()
|
||||
.filter(|value| value.is_finite())
|
||||
.ok_or_else(|| format!("{field_name} 必须是有限数值"))
|
||||
.map(Some),
|
||||
_ => Err(format!("{field_name} 必须是有限数值")),
|
||||
}
|
||||
}
|
||||
@@ -542,9 +549,14 @@ fn imported_rfc3339_to_unix_secs(
|
||||
let Some(value) = imported_optional_string(value)? else {
|
||||
return Ok(None);
|
||||
};
|
||||
let parsed = chrono::DateTime::parse_from_rfc3339(&value)
|
||||
let parsed_timestamp = chrono::DateTime::parse_from_rfc3339(&value)
|
||||
.map(|parsed| parsed.timestamp())
|
||||
.or_else(|_| {
|
||||
chrono::NaiveDateTime::parse_from_str(&value, "%Y-%m-%dT%H:%M:%S%.f")
|
||||
.map(|parsed| parsed.and_utc().timestamp())
|
||||
})
|
||||
.map_err(|_| format!("{field_name} 必须是 RFC3339 时间"))?;
|
||||
Ok(Some(parsed.timestamp().max(0) as u64))
|
||||
Ok(Some(parsed_timestamp.max(0) as u64))
|
||||
}
|
||||
|
||||
fn imported_string_list_from_value(
|
||||
@@ -609,12 +621,11 @@ fn normalize_imported_wallet_target(
|
||||
} else {
|
||||
let total_balance =
|
||||
imported_optional_f64(map.get("balance"), "wallet.balance")?.unwrap_or(0.0);
|
||||
(total_balance - gift_balance).max(0.0)
|
||||
total_balance - gift_balance
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
.max(0.0);
|
||||
};
|
||||
let limit_mode = if let Some(map) = wallet {
|
||||
if let Some(mode) = imported_optional_string(map.get("limit_mode"))? {
|
||||
match mode.to_ascii_lowercase().as_str() {
|
||||
@@ -2436,8 +2447,8 @@ mod tests {
|
||||
|
||||
use super::{
|
||||
imported_optional_bool, imported_optional_f64, imported_optional_i32,
|
||||
imported_optional_u64, imported_string_list_from_value,
|
||||
validate_imported_system_users_export_version,
|
||||
imported_optional_u64, imported_rfc3339_to_unix_secs, imported_string_list_from_value,
|
||||
normalize_imported_wallet_target, validate_imported_system_users_export_version,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -2454,7 +2465,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_rejects_legacy_string_scalars() {
|
||||
fn import_handles_legacy_string_scalars() {
|
||||
assert_eq!(
|
||||
imported_optional_bool(Some(&json!("true"))).unwrap_err(),
|
||||
"字段必须是布尔值"
|
||||
@@ -2468,11 +2479,63 @@ mod tests {
|
||||
"total_requests 必须是非负整数"
|
||||
);
|
||||
assert_eq!(
|
||||
imported_optional_f64(Some(&json!("1.25")), "total_cost_usd").unwrap_err(),
|
||||
imported_optional_f64(Some(&json!("1.25000000")), "total_cost_usd").unwrap(),
|
||||
Some(1.25)
|
||||
);
|
||||
assert_eq!(
|
||||
imported_optional_f64(Some(&json!("not-a-number")), "total_cost_usd").unwrap_err(),
|
||||
"total_cost_usd 必须是有限数值"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_handles_python_isoformat_timestamps() {
|
||||
assert_eq!(
|
||||
imported_rfc3339_to_unix_secs(Some(&json!("2099-01-01T00:00:00+00:00")), "expires_at")
|
||||
.unwrap(),
|
||||
Some(4_070_908_800)
|
||||
);
|
||||
assert_eq!(
|
||||
imported_rfc3339_to_unix_secs(Some(&json!("2099-01-01T00:00:00")), "expires_at")
|
||||
.unwrap(),
|
||||
Some(4_070_908_800)
|
||||
);
|
||||
assert_eq!(
|
||||
imported_rfc3339_to_unix_secs(Some(&json!("invalid")), "expires_at").unwrap_err(),
|
||||
"expires_at 必须是 RFC3339 时间"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_preserves_python_wallet_negative_recharge_balance() {
|
||||
let wallet = json!({
|
||||
"balance": -4.5,
|
||||
"recharge_balance": -5.25,
|
||||
"gift_balance": 0.75,
|
||||
"limit_mode": "finite"
|
||||
});
|
||||
let wallet = wallet.as_object().expect("wallet should be object");
|
||||
|
||||
let target = normalize_imported_wallet_target(Some(wallet), false).unwrap();
|
||||
assert_eq!(target.recharge_balance, -5.25);
|
||||
assert_eq!(target.gift_balance, 0.75);
|
||||
assert_eq!(target.total_recharged, -5.25);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_preserves_python_wallet_negative_balance_fallback() {
|
||||
let wallet = json!({
|
||||
"balance": -4.5,
|
||||
"gift_balance": 0.75,
|
||||
"limit_mode": "finite"
|
||||
});
|
||||
let wallet = wallet.as_object().expect("wallet should be object");
|
||||
|
||||
let target = normalize_imported_wallet_target(Some(wallet), false).unwrap();
|
||||
assert_eq!(target.recharge_balance, -5.25);
|
||||
assert_eq!(target.gift_balance, 0.75);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_rejects_legacy_string_lists() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -614,7 +614,7 @@ async fn gateway_imports_admin_system_users_locally_and_persists_data() {
|
||||
"auto_delete_on_expiry": false,
|
||||
"total_requests": 12,
|
||||
"total_tokens": 3456,
|
||||
"total_cost_usd": 1.25
|
||||
"total_cost_usd": "1.25000000"
|
||||
}]
|
||||
}],
|
||||
"standalone_keys": [{
|
||||
@@ -630,7 +630,7 @@ async fn gateway_imports_admin_system_users_locally_and_persists_data() {
|
||||
"auto_delete_on_expiry": false,
|
||||
"total_requests": 3,
|
||||
"total_tokens": 789,
|
||||
"total_cost_usd": 0.75,
|
||||
"total_cost_usd": "0.75000000",
|
||||
"wallet": {
|
||||
"balance": 30.0,
|
||||
"recharge_balance": 20.0,
|
||||
@@ -713,6 +713,7 @@ async fn gateway_imports_admin_system_users_locally_and_persists_data() {
|
||||
assert_eq!(user_api_keys.len(), 1);
|
||||
assert_eq!(user_api_keys[0].name.as_deref(), Some("Alice CLI"));
|
||||
assert_eq!(user_api_keys[0].total_tokens, 3456);
|
||||
assert_eq!(user_api_keys[0].total_cost_usd, 1.25);
|
||||
assert_eq!(
|
||||
user_api_keys[0].allowed_api_formats,
|
||||
Some(vec!["openai:chat".to_string()])
|
||||
@@ -739,6 +740,7 @@ async fn gateway_imports_admin_system_users_locally_and_persists_data() {
|
||||
Some("Imported Standalone")
|
||||
);
|
||||
assert_eq!(standalone_keys[0].total_tokens, 789);
|
||||
assert_eq!(standalone_keys[0].total_cost_usd, 0.75);
|
||||
assert_eq!(
|
||||
decrypt_python_fernet_ciphertext(
|
||||
DEVELOPMENT_ENCRYPTION_KEY,
|
||||
|
||||
Reference in New Issue
Block a user