fix: correct API key expiry and dashboard savings (#361)

This commit is contained in:
Entropy.Xu
2026-04-30 00:35:32 +08:00
committed by GitHub
parent 9e2faa7e5b
commit 4d59d518d1
11 changed files with 228 additions and 25 deletions

View File

@@ -45,8 +45,8 @@ pub(super) fn build_admin_user_api_key_detail_payload(
"rate_limit": record.rate_limit,
"concurrent_limit": record.concurrent_limit,
"expires_at": format_optional_unix_secs_iso8601(record.expires_at_unix_secs),
"last_used_at": serde_json::Value::Null,
"created_at": serde_json::Value::Null,
"last_used_at": format_optional_unix_secs_iso8601(record.last_used_at_unix_secs),
"created_at": format_optional_unix_secs_iso8601(record.created_at_unix_secs),
})
}

View File

@@ -171,7 +171,8 @@ pub(crate) async fn build_admin_create_user_api_key_response(
"rate_limit": created.rate_limit,
"concurrent_limit": created.concurrent_limit,
"expires_at": format_optional_unix_secs_iso8601(created.expires_at_unix_secs),
"created_at": chrono::Utc::now().to_rfc3339(),
"last_used_at": format_optional_unix_secs_iso8601(created.last_used_at_unix_secs),
"created_at": format_optional_unix_secs_iso8601(created.created_at_unix_secs),
"message": "API Key创建成功请妥善保存完整密钥",
}))
.into_response(),

View File

@@ -64,8 +64,8 @@ pub(crate) async fn build_admin_list_user_api_keys_response(
"rate_limit": record.rate_limit,
"concurrent_limit": record.concurrent_limit,
"expires_at": format_optional_unix_secs_iso8601(record.expires_at_unix_secs),
"last_used_at": serde_json::Value::Null,
"created_at": serde_json::Value::Null,
"last_used_at": format_optional_unix_secs_iso8601(record.last_used_at_unix_secs),
"created_at": format_optional_unix_secs_iso8601(record.created_at_unix_secs),
})
})
.collect::<Vec<_>>();

View File

@@ -3,8 +3,9 @@ use super::{
GatewayError, GatewayPublicRequestContext,
};
use aether_data_contracts::repository::usage::{
StoredUsageDashboardDailyBreakdownRow, StoredUsageDashboardSummary,
UsageAuditAggregationGroupBy, UsageAuditAggregationQuery, UsageDashboardDailyBreakdownQuery,
StoredUsageCostSavingsSummary, StoredUsageDashboardDailyBreakdownRow,
StoredUsageDashboardSummary, UsageAuditAggregationGroupBy, UsageAuditAggregationQuery,
UsageCostSavingsSummaryQuery, UsageDashboardDailyBreakdownQuery,
UsageDashboardProviderCountsQuery, UsageDashboardSummaryQuery,
};
use axum::{
@@ -428,7 +429,10 @@ fn dashboard_parse_daily_range(query: Option<&str>) -> Result<DashboardDateRange
fn dashboard_range_bounds_unix(range: DashboardDateRange) -> Option<(u64, u64)> {
let offset = chrono::Duration::minutes(i64::from(range.tz_offset_minutes));
let start_local = range.start_date.and_hms_opt(0, 0, 0)?;
let end_local = range.end_date.and_hms_opt(23, 59, 59)?;
let end_local = range
.end_date
.checked_add_signed(chrono::Duration::days(1))?
.and_hms_opt(0, 0, 0)?;
let start_utc = (start_local - offset).and_utc().timestamp();
let end_utc = (end_local - offset).and_utc().timestamp();
Some((start_utc.max(0) as u64, end_utc.max(0) as u64))
@@ -1501,6 +1505,41 @@ async fn dashboard_load_user_counts(
Ok((count, count))
}
fn dashboard_cache_savings_usd(summary: &StoredUsageCostSavingsSummary) -> f64 {
let estimated_full_cost =
if summary.estimated_full_cost_usd <= 0.0 && summary.cache_read_cost_usd > 0.0 {
summary.cache_read_cost_usd * 10.0
} else {
summary.estimated_full_cost_usd
};
dashboard_round_f64(
(estimated_full_cost - summary.cache_read_cost_usd).max(0.0),
4,
)
}
async fn dashboard_load_cache_savings(
state: &AppState,
range: DashboardDateRange,
user_id: Option<&str>,
) -> Result<f64, GatewayError> {
let Some((created_from_unix_secs, created_until_unix_secs)) =
dashboard_range_bounds_unix(range)
else {
return Ok(0.0);
};
let summary = state
.summarize_usage_cost_savings(&UsageCostSavingsSummaryQuery {
created_from_unix_secs,
created_until_unix_secs,
user_id: user_id.map(ToOwned::to_owned),
provider_name: None,
model: None,
})
.await?;
Ok(dashboard_cache_savings_usd(&summary))
}
pub(super) async fn handle_dashboard_stats_get(
state: &AppState,
request_context: &GatewayPublicRequestContext,
@@ -1630,10 +1669,17 @@ pub(super) async fn handle_dashboard_stats_get(
/ today_totals.requests as f64
* 100.0
};
let cost_savings = dashboard_round_f64(
period_totals.total_cost_usd - period_totals.actual_total_cost_usd,
4,
);
let cost_savings =
match dashboard_load_cache_savings(state, summary_range, user_filter).await {
Ok(value) => value,
Err(err) => {
return build_auth_error_response(
http::StatusCode::INTERNAL_SERVER_ERROR,
format!("dashboard cache savings lookup failed: {err:?}"),
false,
);
}
};
let stats = json!([
{
"name": "今日请求",

View File

@@ -148,8 +148,8 @@ fn build_users_me_api_key_list_payload(
"key_display": users_me_masked_api_key_display(state, record.key_encrypted.as_deref()),
"is_active": record.is_active,
"is_locked": is_locked,
"last_used_at": serde_json::Value::Null,
"created_at": serde_json::Value::Null,
"last_used_at": format_users_me_optional_unix_secs_iso8601(record.last_used_at_unix_secs),
"created_at": format_users_me_optional_unix_secs_iso8601(record.created_at_unix_secs),
"total_requests": record.total_requests,
"total_cost_usd": record.total_cost_usd,
"rate_limit": record.rate_limit,
@@ -174,9 +174,9 @@ fn build_users_me_api_key_detail_payload(
"force_capabilities": record.force_capabilities,
"rate_limit": record.rate_limit,
"concurrent_limit": record.concurrent_limit,
"last_used_at": serde_json::Value::Null,
"last_used_at": format_users_me_optional_unix_secs_iso8601(record.last_used_at_unix_secs),
"expires_at": format_users_me_optional_unix_secs_iso8601(record.expires_at_unix_secs),
"created_at": serde_json::Value::Null,
"created_at": format_users_me_optional_unix_secs_iso8601(record.created_at_unix_secs),
})
}
@@ -575,8 +575,14 @@ pub(super) async fn handle_users_me_api_key_create(
"name": created.name,
"key": plaintext_key,
"key_display": users_me_masked_api_key_display(state, created.key_encrypted.as_deref()),
"is_active": created.is_active,
"is_locked": false,
"rate_limit": created.rate_limit,
"concurrent_limit": created.concurrent_limit,
"last_used_at": format_users_me_optional_unix_secs_iso8601(created.last_used_at_unix_secs),
"created_at": format_users_me_optional_unix_secs_iso8601(created.created_at_unix_secs),
"total_requests": created.total_requests,
"total_cost_usd": created.total_cost_usd,
"message": "API密钥创建成功",
}))
.into_response()