forked from boos/BoosAPI
feat: complete user login admin keys and deployment docs
This commit is contained in:
+81
-22
@@ -161,33 +161,66 @@ async fn delete_api_key(
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct UserLogsQuery {
|
||||
q: Option<String>,
|
||||
status: Option<String>,
|
||||
date_from: Option<String>,
|
||||
date_to: Option<String>,
|
||||
page: Option<i64>,
|
||||
page_size: Option<i64>,
|
||||
// legacy compat
|
||||
limit: Option<i64>,
|
||||
offset: Option<i64>,
|
||||
}
|
||||
|
||||
async fn get_user_logs(
|
||||
State(state): State<AppState>,
|
||||
headers: HeaderMap,
|
||||
Query(params): Query<std::collections::HashMap<String, String>>,
|
||||
Query(params): Query<UserLogsQuery>,
|
||||
) -> AppResult<Json<Value>> {
|
||||
let user_id = current_user_id(&headers, &state)?;
|
||||
|
||||
let limit = params
|
||||
.get("limit")
|
||||
.and_then(|v| v.parse::<i64>().ok())
|
||||
let page_size = params
|
||||
.page_size
|
||||
.or(params.limit)
|
||||
.unwrap_or(20)
|
||||
.clamp(1, 100);
|
||||
let offset = params
|
||||
.get("offset")
|
||||
.and_then(|v| v.parse::<i64>().ok())
|
||||
.unwrap_or(0)
|
||||
.max(0);
|
||||
.clamp(1, 200);
|
||||
let page = params.page.unwrap_or(1).max(1);
|
||||
let offset = params.offset.unwrap_or((page - 1) * page_size).max(0);
|
||||
|
||||
let q = params.q.as_deref().map(str::trim).filter(|s| !s.is_empty());
|
||||
let q_like = q.map(|s| format!("%{s}%"));
|
||||
let status = params
|
||||
.status
|
||||
.as_deref()
|
||||
.filter(|s| !s.is_empty() && *s != "all");
|
||||
let date_from = params.date_from.as_deref().filter(|s| !s.is_empty());
|
||||
let date_to = params.date_to.as_deref().filter(|s| !s.is_empty());
|
||||
|
||||
let items: Vec<Value> = sqlx::query_as::<_, crate::routes::stats::ProxyLogRow>(
|
||||
"SELECT l.* FROM proxy_logs l
|
||||
JOIN downstream_api_keys k ON l.downstream_api_key_id = k.id
|
||||
WHERE k.user_id = ?
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT ? OFFSET ?",
|
||||
r#"
|
||||
SELECT l.* FROM proxy_logs l
|
||||
JOIN downstream_api_keys k ON l.downstream_api_key_id = k.id
|
||||
WHERE k.user_id = ?
|
||||
AND (? IS NULL OR l.model_requested LIKE ?)
|
||||
AND (? IS NULL OR l.status = ?)
|
||||
AND (? IS NULL OR l.created_at >= ?)
|
||||
AND (? IS NULL OR l.created_at <= ?)
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
"#,
|
||||
)
|
||||
.bind(user_id)
|
||||
.bind(limit)
|
||||
.bind(q_like.as_deref())
|
||||
.bind(q_like.as_deref())
|
||||
.bind(status)
|
||||
.bind(status)
|
||||
.bind(date_from)
|
||||
.bind(date_from)
|
||||
.bind(date_to)
|
||||
.bind(date_to)
|
||||
.bind(page_size)
|
||||
.bind(offset)
|
||||
.fetch_all(&*state.db)
|
||||
.await?
|
||||
@@ -195,20 +228,46 @@ async fn get_user_logs(
|
||||
.map(|row| serde_json::to_value(row).unwrap_or(json!({})))
|
||||
.collect();
|
||||
|
||||
let total: i64 = sqlx::query_scalar(
|
||||
"SELECT COUNT(*) FROM proxy_logs l
|
||||
JOIN downstream_api_keys k ON l.downstream_api_key_id = k.id
|
||||
WHERE k.user_id = ?",
|
||||
let (total, success_count, total_cost, total_tokens): (i64, i64, f64, i64) = sqlx::query_as(
|
||||
r#"
|
||||
SELECT
|
||||
COUNT(*),
|
||||
SUM(CASE WHEN l.status = 'success' THEN 1 ELSE 0 END),
|
||||
COALESCE(SUM(l.estimated_cost), 0.0),
|
||||
COALESCE(SUM(l.total_tokens), 0)
|
||||
FROM proxy_logs l
|
||||
JOIN downstream_api_keys k ON l.downstream_api_key_id = k.id
|
||||
WHERE k.user_id = ?
|
||||
AND (? IS NULL OR l.model_requested LIKE ?)
|
||||
AND (? IS NULL OR l.status = ?)
|
||||
AND (? IS NULL OR l.created_at >= ?)
|
||||
AND (? IS NULL OR l.created_at <= ?)
|
||||
"#,
|
||||
)
|
||||
.bind(user_id)
|
||||
.bind(q_like.as_deref())
|
||||
.bind(q_like.as_deref())
|
||||
.bind(status)
|
||||
.bind(status)
|
||||
.bind(date_from)
|
||||
.bind(date_from)
|
||||
.bind(date_to)
|
||||
.bind(date_to)
|
||||
.fetch_one(&*state.db)
|
||||
.await?;
|
||||
|
||||
Ok(Json(json!({
|
||||
"items": items,
|
||||
"total": total,
|
||||
"limit": limit,
|
||||
"offset": offset
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"summary": {
|
||||
"total": total,
|
||||
"success": success_count,
|
||||
"failed": total - success_count,
|
||||
"total_cost": total_cost,
|
||||
"total_tokens": total_tokens,
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user