diff --git a/flake.nix b/flake.nix index c5c3f1b..ee7749e 100644 --- a/flake.nix +++ b/flake.nix @@ -35,6 +35,7 @@ pkg-config sqlite gemini-cli + claude-code biome sqlx-cli typos diff --git a/src/admin/handlers.rs b/src/admin/handlers.rs index b95a759..12172ef 100644 --- a/src/admin/handlers.rs +++ b/src/admin/handlers.rs @@ -325,21 +325,19 @@ pub async fn list_logs( State(state): State>, Query(params): Query, ) -> Result, (StatusCode, Json)> { - match ( - db::repositories::logs::list( - &state.db, - params.method.as_deref(), - params.search.as_deref(), - params.limit, - params - .limit - .map(|limit| limit * (params.page.unwrap_or(1) - 1)), - ) - .await, - db::repositories::logs::total(&state.db).await, - ) { - (Ok(logs), Ok(total)) => Ok(Json(PaginatedRequestLogs { total, data: logs })), - (Err(e), _) | (_, Err(e)) => { + match db::repositories::logs::list( + &state.db, + params.method.as_deref(), + params.search.as_deref(), + params.limit, + params + .limit + .map(|limit| limit * (params.page.unwrap_or(1) - 1)), + ) + .await + { + Ok((logs, total)) => Ok(Json(PaginatedRequestLogs { total, data: logs })), + Err(e) => { error!("Failed to list logs: {}", e); Err(( StatusCode::INTERNAL_SERVER_ERROR, diff --git a/src/db/repositories/logs.rs b/src/db/repositories/logs.rs index 86ecdd6..a8649e2 100644 --- a/src/db/repositories/logs.rs +++ b/src/db/repositories/logs.rs @@ -1,26 +1,23 @@ use crate::db::models::{InterceptionAction, RequestLog}; use sqlx::{QueryBuilder, SqlitePool}; -pub async fn total(pool: &SqlitePool) -> anyhow::Result { - Ok( - sqlx::query_scalar::<_, i64>("SELECT COUNT(*) FROM request_logs;") - .fetch_one(pool) - .await? as usize, - ) -} - pub async fn list( pool: &SqlitePool, method: Option<&str>, search: Option<&str>, limit: Option, offset: Option, -) -> anyhow::Result> { +) -> anyhow::Result<(Vec, usize)> { + let mut tx = pool.begin().await?; let mut builder: QueryBuilder = QueryBuilder::new("SELECT * FROM request_logs"); + let mut total_builder: QueryBuilder = + QueryBuilder::new("SELECT COUNT(*) FROM request_logs"); if let Some(method_val) = method { builder.push(" WHERE method = "); builder.push_bind(method_val); + total_builder.push(" WHERE method = "); + total_builder.push_bind(method_val); } if let Some(search_val) = search { @@ -32,8 +29,18 @@ pub async fn list( } builder.push_bind(pattern.clone()); builder.push(" OR response_body LIKE "); - builder.push_bind(pattern); + builder.push_bind(pattern.clone()); builder.push(")"); + + if method.is_some() { + total_builder.push(" AND (request_body LIKE "); + } else { + total_builder.push(" WHERE (request_body LIKE "); + } + total_builder.push_bind(pattern.clone()); + total_builder.push(" OR response_body LIKE "); + total_builder.push_bind(pattern); + total_builder.push(")"); } if let Some(limit) = limit { @@ -49,14 +56,22 @@ pub async fn list( builder.push(" ORDER BY created_at DESC"); let query = builder.build_query_as(); - Ok(query.fetch_all(pool).await?) + let logs = query.fetch_all(&mut *tx).await?; + let total = builder + .build_query_scalar::() + .fetch_one(&mut *tx) + .await? as usize; + tx.commit().await?; + Ok((logs, total)) } pub async fn list_methods(pool: &SqlitePool) -> anyhow::Result> { Ok( - sqlx::query_scalar::<_, String>("SELECT DISTINCT method FROM request_logs ORDER BY method;") - .fetch_all(pool) - .await? + sqlx::query_scalar::<_, String>( + "SELECT DISTINCT method FROM request_logs ORDER BY method;", + ) + .fetch_all(pool) + .await?, ) } diff --git a/src/middleware.rs b/src/middleware.rs index 1882af5..ece35ff 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -198,7 +198,8 @@ async fn process_response(body: String, method: &str, ctx: &Arc) -> } }; - let modified_body_str = serde_json::to_string(&response_value).expect("serialization succeeded"); + let modified_body_str = + serde_json::to_string(&response_value).expect("serialization succeeded"); let encrypted = ctx.cryptor.encrypt(modified_body_str.clone()); let final_ = action.map(|action| (modified_body_str.clone(), action));