mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
Merge remote-tracking branch 'origin/pr/395' into aether-rust-pioneer
This commit is contained in:
@@ -60,6 +60,25 @@ impl<'a> AdminAppState<'a> {
|
||||
self.app.read_admin_system_stats().await
|
||||
}
|
||||
|
||||
pub(crate) async fn purge_admin_system_data(
|
||||
&self,
|
||||
target: aether_data::repository::system::AdminSystemPurgeTarget,
|
||||
) -> Result<aether_data::repository::system::AdminSystemPurgeSummary, GatewayError> {
|
||||
self.app.purge_admin_system_data(target).await
|
||||
}
|
||||
|
||||
pub(crate) async fn run_admin_system_cleanup_once(
|
||||
&self,
|
||||
) -> Result<crate::maintenance::AdminSystemCleanupSummary, GatewayError> {
|
||||
self.app.run_admin_system_cleanup_once().await
|
||||
}
|
||||
|
||||
pub(crate) async fn rebuild_admin_stats_once(
|
||||
&self,
|
||||
) -> Result<crate::maintenance::AdminStatsRebuildSummary, GatewayError> {
|
||||
self.app.rebuild_admin_stats_once().await
|
||||
}
|
||||
|
||||
pub(crate) async fn find_proxy_node(
|
||||
&self,
|
||||
node_id: &str,
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::handlers::admin::system::shared::settings::{
|
||||
};
|
||||
use crate::handlers::admin::system::shared::smtp::build_admin_smtp_test_payload;
|
||||
use crate::GatewayError;
|
||||
use aether_data::repository::system::AdminSystemPurgeTarget;
|
||||
use axum::{
|
||||
body::{Body, Bytes},
|
||||
http,
|
||||
@@ -183,26 +184,29 @@ pub(super) async fn maybe_build_local_admin_core_system_response(
|
||||
));
|
||||
}
|
||||
|
||||
if matches!(
|
||||
decision.route_kind.as_deref(),
|
||||
Some(
|
||||
"cleanup"
|
||||
| "purge_config"
|
||||
| "purge_users"
|
||||
| "purge_usage"
|
||||
| "purge_audit_logs"
|
||||
| "purge_request_bodies"
|
||||
| "purge_stats"
|
||||
)
|
||||
) && request_method == http::Method::POST
|
||||
if decision.route_kind.as_deref() == Some("cleanup") && request_method == http::Method::POST {
|
||||
return Ok(Some(attach_admin_audit_response(
|
||||
Json(build_admin_system_cleanup_payload(state).await?).into_response(),
|
||||
"admin_system_cleanup_completed",
|
||||
"cleanup_system_data",
|
||||
"system_cleanup",
|
||||
"global",
|
||||
)));
|
||||
}
|
||||
|
||||
if let Some((target, action, object_type, object_id)) =
|
||||
admin_system_purge_target_for_route_kind(decision.route_kind.as_deref())
|
||||
{
|
||||
return Ok(Some(
|
||||
(
|
||||
http::StatusCode::SERVICE_UNAVAILABLE,
|
||||
Json(json!({ "detail": "Admin system data unavailable" })),
|
||||
)
|
||||
.into_response(),
|
||||
));
|
||||
if request_method != http::Method::POST {
|
||||
return Ok(None);
|
||||
}
|
||||
return Ok(Some(attach_admin_audit_response(
|
||||
Json(build_admin_system_purge_payload(state, target).await?).into_response(),
|
||||
"admin_system_data_purged",
|
||||
action,
|
||||
object_type,
|
||||
object_id,
|
||||
)));
|
||||
}
|
||||
|
||||
if decision.route_kind.as_deref() == Some("settings_set")
|
||||
@@ -430,3 +434,128 @@ pub(super) async fn maybe_build_local_admin_core_system_response(
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn admin_system_purge_target_for_route_kind(
|
||||
route_kind: Option<&str>,
|
||||
) -> Option<(
|
||||
AdminSystemPurgeTarget,
|
||||
&'static str,
|
||||
&'static str,
|
||||
&'static str,
|
||||
)> {
|
||||
match route_kind {
|
||||
Some("purge_config") => Some((
|
||||
AdminSystemPurgeTarget::Config,
|
||||
"purge_system_config",
|
||||
"system_config",
|
||||
"global",
|
||||
)),
|
||||
Some("purge_users") => Some((
|
||||
AdminSystemPurgeTarget::Users,
|
||||
"purge_non_admin_users",
|
||||
"users",
|
||||
"non_admin",
|
||||
)),
|
||||
Some("purge_usage") => Some((
|
||||
AdminSystemPurgeTarget::Usage,
|
||||
"purge_usage_records",
|
||||
"usage",
|
||||
"all",
|
||||
)),
|
||||
Some("purge_audit_logs") => Some((
|
||||
AdminSystemPurgeTarget::AuditLogs,
|
||||
"purge_audit_logs",
|
||||
"audit_logs",
|
||||
"all",
|
||||
)),
|
||||
Some("purge_request_bodies") => Some((
|
||||
AdminSystemPurgeTarget::RequestBodies,
|
||||
"purge_request_bodies",
|
||||
"request_bodies",
|
||||
"all",
|
||||
)),
|
||||
Some("purge_stats") => Some((AdminSystemPurgeTarget::Stats, "purge_stats", "stats", "all")),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_admin_system_purge_payload(
|
||||
state: &AdminAppState<'_>,
|
||||
target: AdminSystemPurgeTarget,
|
||||
) -> Result<serde_json::Value, GatewayError> {
|
||||
let summary = state.purge_admin_system_data(target).await?;
|
||||
let total = summary.total();
|
||||
let affected = summary.affected.clone();
|
||||
|
||||
if target == AdminSystemPurgeTarget::Stats {
|
||||
let rebuild = state.rebuild_admin_stats_once().await?;
|
||||
let message = if rebuild.capped {
|
||||
format!(
|
||||
"统计聚合已清空,已重建 {} 个小时桶和 {} 个日桶,仍有历史统计待后台任务继续重建",
|
||||
rebuild.hourly_buckets, rebuild.daily_buckets
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"统计聚合已清空并重建,删除 {} 行,重建 {} 个小时桶和 {} 个日桶",
|
||||
total, rebuild.hourly_buckets, rebuild.daily_buckets
|
||||
)
|
||||
};
|
||||
return Ok(json!({
|
||||
"message": message,
|
||||
"deleted": affected,
|
||||
"rebuilt": {
|
||||
"hourly_buckets": rebuild.hourly_buckets,
|
||||
"daily_buckets": rebuild.daily_buckets,
|
||||
"capped": rebuild.capped,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
let (message, count_key) = match target {
|
||||
AdminSystemPurgeTarget::Config => ("系统配置已清空", "deleted"),
|
||||
AdminSystemPurgeTarget::Users => ("非管理员用户已清空", "deleted"),
|
||||
AdminSystemPurgeTarget::Usage => ("使用记录已清空", "deleted"),
|
||||
AdminSystemPurgeTarget::AuditLogs => ("审计日志已清空", "deleted"),
|
||||
AdminSystemPurgeTarget::RequestBodies => ("请求/响应体已清空", "cleaned"),
|
||||
AdminSystemPurgeTarget::Stats => unreachable!("stats handled above"),
|
||||
};
|
||||
|
||||
Ok(json!({
|
||||
"message": format!("{message},影响 {} 行", total),
|
||||
count_key: affected,
|
||||
}))
|
||||
}
|
||||
|
||||
async fn build_admin_system_cleanup_payload(
|
||||
state: &AdminAppState<'_>,
|
||||
) -> Result<serde_json::Value, GatewayError> {
|
||||
let summary = state.run_admin_system_cleanup_once().await?;
|
||||
let cleaned = json!({
|
||||
"audit_logs": summary.audit_logs_deleted,
|
||||
"request_candidates": summary.request_candidates_deleted,
|
||||
"pending_failed": summary.pending_failed,
|
||||
"pending_recovered": summary.pending_recovered,
|
||||
"usage_body_externalized": summary.usage.body_externalized,
|
||||
"usage_legacy_body_refs_migrated": summary.usage.legacy_body_refs_migrated,
|
||||
"usage_body_cleaned": summary.usage.body_cleaned,
|
||||
"usage_header_cleaned": summary.usage.header_cleaned,
|
||||
"usage_keys_cleaned": summary.usage.keys_cleaned,
|
||||
"usage_records_deleted": summary.usage.records_deleted,
|
||||
});
|
||||
let total = summary
|
||||
.audit_logs_deleted
|
||||
.saturating_add(summary.request_candidates_deleted)
|
||||
.saturating_add(summary.pending_failed)
|
||||
.saturating_add(summary.pending_recovered)
|
||||
.saturating_add(summary.usage.body_externalized)
|
||||
.saturating_add(summary.usage.legacy_body_refs_migrated)
|
||||
.saturating_add(summary.usage.body_cleaned)
|
||||
.saturating_add(summary.usage.header_cleaned)
|
||||
.saturating_add(summary.usage.keys_cleaned)
|
||||
.saturating_add(summary.usage.records_deleted);
|
||||
|
||||
Ok(json!({
|
||||
"message": format!("系统清理已执行,影响 {} 项", total),
|
||||
"cleaned": cleaned,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ pub(in super::super) async fn build_admin_list_users_response(
|
||||
.map(|value| value.trim().to_ascii_lowercase())
|
||||
.filter(|value| !value.is_empty());
|
||||
let is_active = query_param_optional_bool(request_context.query_string(), "is_active");
|
||||
let search = query_param_value(request_context.query_string(), "search")
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty());
|
||||
|
||||
let paged_rows = state
|
||||
.list_export_users_page(&aether_data::repository::users::UserExportListQuery {
|
||||
@@ -36,6 +39,7 @@ pub(in super::super) async fn build_admin_list_users_response(
|
||||
limit,
|
||||
role: role.clone(),
|
||||
is_active,
|
||||
search,
|
||||
})
|
||||
.await?;
|
||||
let user_ids = paged_rows
|
||||
|
||||
Reference in New Issue
Block a user