From 9c9295d050229ea9eea4fcadaf66601f57a23962 Mon Sep 17 00:00:00 2001 From: Michael Vlach Date: Tue, 18 Jun 2024 20:40:22 +0200 Subject: [PATCH] fix audit concat --- agdb_server/src/db_pool.rs | 20 ++++++++--- agdb_server/tests/routes/db_audit_test.rs | 44 +++++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/agdb_server/src/db_pool.rs b/agdb_server/src/db_pool.rs index 9e55a5bf..66da2596 100644 --- a/agdb_server/src/db_pool.rs +++ b/agdb_server/src/db_pool.rs @@ -34,6 +34,9 @@ use axum::http::StatusCode; use server_db::ServerDb; use server_db::ServerDbImpl; use std::collections::HashMap; +use std::io::Seek; +use std::io::SeekFrom; +use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; @@ -498,12 +501,21 @@ impl DbPool { Ok(results) }); - if r.is_ok() { - let log = std::fs::OpenOptions::new() + if r.is_ok() && !audit.is_empty() { + let mut log = std::fs::OpenOptions::new() .create(true) - .append(true) + .truncate(false) + .write(true) .open(db_audit_file(owner, db, config))?; - serde_json::to_writer(log, &audit)?; + let len = log.seek(SeekFrom::End(0))?; + if len == 0 { + serde_json::to_writer(&log, &audit)?; + } else { + let mut data = serde_json::to_vec(&audit)?; + data[0] = b','; + log.seek(SeekFrom::End(-1))?; + log.write_all(&data)?; + } } r } diff --git a/agdb_server/tests/routes/db_audit_test.rs b/agdb_server/tests/routes/db_audit_test.rs index 07bbf812..2502ef79 100644 --- a/agdb_server/tests/routes/db_audit_test.rs +++ b/agdb_server/tests/routes/db_audit_test.rs @@ -79,3 +79,47 @@ async fn audit_no_token() -> anyhow::Result<()> { assert_eq!(status, 401); Ok(()) } + +#[tokio::test] +async fn repeated_query_with_db_audit() -> anyhow::Result<()> { + let mut server = TestServer::new().await?; + let owner = &server.next_user_name(); + let db = &server.next_db_name(); + server.api.user_login(ADMIN, ADMIN).await?; + server.api.admin_user_add(owner, owner).await?; + server.api.user_login(owner, owner).await?; + server.api.db_add(owner, db, DbType::Mapped).await?; + server + .api + .db_exec( + owner, + db, + &vec![QueryBuilder::insert() + .nodes() + .aliases("root") + .query() + .into()], + ) + .await?; + let (status, audit) = server.api.db_audit(owner, db).await?; + assert_eq!(status, 200); + assert!(!audit.0.is_empty()); + server + .api + .db_exec( + owner, + db, + &vec![QueryBuilder::insert() + .nodes() + .aliases("root") + .query() + .into()], + ) + .await?; + let (status, audit2) = server.api.db_audit(owner, db).await?; + assert_eq!(status, 200); + assert_eq!(audit2.0.len(), 2); + assert_eq!(audit2.0[0], audit.0[0]); + assert_eq!(audit2.0[1], audit.0[0]); + Ok(()) +}