From 9577fe99ba9c165a23b700f5b6e526bf66c5f0ab Mon Sep 17 00:00:00 2001 From: dal Date: Tue, 11 Mar 2025 22:33:42 -0600 Subject: [PATCH] added in the list metrics --- .../src/metrics/list_metrics_handler.rs | 104 ++++++++++++++++++ api/libs/handlers/src/metrics/mod.rs | 4 +- .../rest/routes/metrics/list_metrics.rs | 37 +++++++ api/src/routes/rest/routes/metrics/mod.rs | 12 +- 4 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 api/libs/handlers/src/metrics/list_metrics_handler.rs create mode 100644 api/src/routes/rest/routes/metrics/list_metrics.rs diff --git a/api/libs/handlers/src/metrics/list_metrics_handler.rs b/api/libs/handlers/src/metrics/list_metrics_handler.rs new file mode 100644 index 000000000..4342ec78c --- /dev/null +++ b/api/libs/handlers/src/metrics/list_metrics_handler.rs @@ -0,0 +1,104 @@ +use anyhow::{anyhow, Result}; +use chrono::{DateTime, Utc}; +use database::{enums::Verification, pool::get_pg_pool, schema::metric_files}; +use diesel::{ExpressionMethods, QueryDsl}; +use diesel_async::RunQueryDsl; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize)] +pub struct MetricsListRequest { + pub page_token: i64, + pub page_size: i64, + pub shared_with_me: Option, + pub only_my_metrics: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct BusterMetricListItem { + pub id: Uuid, + pub title: String, + pub last_edited: DateTime, + pub created_by_id: Uuid, + pub created_by_name: String, + pub created_by_email: String, + pub created_by_avatar: String, + pub status: Verification, + pub is_shared: bool, +} + +pub async fn list_metrics_handler( + user_id: &Uuid, + request: MetricsListRequest, +) -> Result> { + let mut conn = match get_pg_pool().get().await { + Ok(conn) => conn, + Err(e) => return Err(anyhow!("Failed to get database connection: {}", e)), + }; + + // Calculate offset from page_token + let offset = request.page_token * request.page_size; + + // Build the base query + let mut metric_statement = metric_files::table + .select(( + metric_files::id, + metric_files::name, + metric_files::created_by, + metric_files::created_at, + metric_files::updated_at, + metric_files::verification, + metric_files::content, + )) + .filter(metric_files::deleted_at.is_null()) + .distinct() + .order((metric_files::updated_at.desc(), metric_files::id.asc())) + .offset(offset) + .limit(request.page_size) + .into_boxed(); + + // Add filters for shared_with_me and only_my_metrics if provided + if let Some(true) = request.only_my_metrics { + metric_statement = + diesel::QueryDsl::filter(metric_statement, metric_files::created_by.eq(user_id)); + } + + // Execute the query + let metric_results = match metric_statement + .load::<( + Uuid, + String, + Uuid, + DateTime, + DateTime, + Verification, + serde_json::Value, + )>(&mut conn) + .await + { + Ok(results) => results, + Err(e) => return Err(anyhow!("Error getting metric results: {}", e)), + }; + + // Transform query results into BusterMetricListItem + let metrics = metric_results + .into_iter() + .map( + |(id, name, created_by, _created_at, updated_at, status, content)| { + BusterMetricListItem { + id, + title: name, + last_edited: updated_at, + created_by_id: created_by, + created_by_name: "todo".to_string(), // Would fetch from users table + created_by_email: "todo".to_string(), // Would fetch from users table + created_by_avatar: "todo".to_string(), // Would fetch from users table + status, + is_shared: false, // Would determine based on permissions + } + }, + ) + .collect(); + + Ok(metrics) +} diff --git a/api/libs/handlers/src/metrics/mod.rs b/api/libs/handlers/src/metrics/mod.rs index b6fc70bef..c0585a4f0 100644 --- a/api/libs/handlers/src/metrics/mod.rs +++ b/api/libs/handlers/src/metrics/mod.rs @@ -1,7 +1,9 @@ pub mod get_metric_data_handler; pub mod get_metric_handler; +pub mod list_metrics_handler; pub mod types; pub use get_metric_data_handler::*; pub use get_metric_handler::*; -pub use types::*; \ No newline at end of file +pub use list_metrics_handler::*; +pub use types::*; \ No newline at end of file diff --git a/api/src/routes/rest/routes/metrics/list_metrics.rs b/api/src/routes/rest/routes/metrics/list_metrics.rs new file mode 100644 index 000000000..bd9ca03f2 --- /dev/null +++ b/api/src/routes/rest/routes/metrics/list_metrics.rs @@ -0,0 +1,37 @@ +use crate::routes::rest::ApiResponse; +use axum::extract::Query; +use axum::http::StatusCode; +use axum::Extension; +use handlers::metrics::{list_metrics_handler, MetricsListRequest, BusterMetricListItem}; +use middleware::AuthenticatedUser; +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct ListMetricsQuery { + page_token: Option, + page_size: Option, + shared_with_me: Option, + only_my_metrics: Option, +} + +pub async fn list_metrics_rest_handler( + Extension(user): Extension, + Query(query): Query, +) -> Result>, (StatusCode, &'static str)> { + let request = MetricsListRequest { + page_token: query.page_token.unwrap_or(0), + page_size: query.page_size.unwrap_or(25), + shared_with_me: query.shared_with_me, + only_my_metrics: query.only_my_metrics, + }; + + let metrics = match list_metrics_handler(&user.id, request).await { + Ok(metrics) => metrics, + Err(e) => { + tracing::error!("Error listing metrics: {}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Failed to list metrics")); + } + }; + + Ok(ApiResponse::JsonData(metrics)) +} diff --git a/api/src/routes/rest/routes/metrics/mod.rs b/api/src/routes/rest/routes/metrics/mod.rs index 6082babc5..f0c71d8ab 100644 --- a/api/src/routes/rest/routes/metrics/mod.rs +++ b/api/src/routes/rest/routes/metrics/mod.rs @@ -1,14 +1,16 @@ -use axum::{ - routing::get, - Router, -}; +use axum::{routing::get, Router}; // Import modules mod get_metric; mod get_metric_data; +mod list_metrics; pub fn router() -> Router { Router::new() .route("/:id", get(get_metric::get_metric_rest_handler)) - .route("/:id/data", get(get_metric_data::get_metric_data_rest_handler)) + .route("/", get(list_metrics::list_metrics_rest_handler)) + .route( + "/:id/data", + get(get_metric_data::get_metric_data_rest_handler), + ) }