diff --git a/src/handlers/http/users/dashboards.rs b/src/handlers/http/users/dashboards.rs index 16a885969..beae53e9f 100644 --- a/src/handlers/http/users/dashboards.rs +++ b/src/handlers/http/users/dashboards.rs @@ -16,25 +16,23 @@ * */ -use crate::{ - handlers::http::rbac::RBACError, - parseable::PARSEABLE, - storage::{object_storage::dashboard_path, ObjectStorageError}, - users::dashboards::{Dashboard, CURRENT_DASHBOARD_VERSION, DASHBOARDS}, - utils::{actix::extract_session_key_from_req, get_hash, get_user_from_request}, -}; use actix_web::{ http::header::ContentType, web::{self, Json, Path}, HttpRequest, HttpResponse, Responder, }; use bytes::Bytes; -use rand::distributions::DistString; - -use chrono::Utc; use http::StatusCode; use serde_json::Error as SerdeError; +use crate::{ + handlers::http::rbac::RBACError, + parseable::PARSEABLE, + storage::{object_storage::dashboard_path, ObjectStorageError}, + users::dashboards::{Dashboard, DASHBOARDS}, + utils::{actix::extract_session_key_from_req, get_hash, get_user_from_request}, +}; + pub async fn list(req: HttpRequest) -> Result { let key = extract_session_key_from_req(&req).map_err(|e| DashboardError::Custom(e.to_string()))?; @@ -50,14 +48,11 @@ pub async fn get( let user_id = get_user_from_request(&req)?; let dashboard_id = dashboard_id.into_inner(); - if let Some(dashboard) = DASHBOARDS - .get_dashboard(&dashboard_id, &get_hash(&user_id)) - .await - { + if let Some(dashboard) = DASHBOARDS.get(&dashboard_id, &get_hash(&user_id)).await { return Ok((web::Json(dashboard), StatusCode::OK)); } - Err(DashboardError::Metadata("Dashboard does not exist")) + Err(DashboardError::DashboardDoesNotExist) } pub async fn post( @@ -66,24 +61,10 @@ pub async fn post( ) -> Result { let mut user_id = get_user_from_request(&req)?; user_id = get_hash(&user_id); - let dashboard_id = get_hash(Utc::now().timestamp_micros().to_string().as_str()); - dashboard.dashboard_id = Some(dashboard_id.clone()); - dashboard.version = Some(CURRENT_DASHBOARD_VERSION.to_string()); - dashboard.user_id = Some(user_id.clone()); - for tile in dashboard.tiles.iter_mut() { - tile.tile_id = Some(get_hash( - format!( - "{}{}", - rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 8), - Utc::now().timestamp_micros() - ) - .as_str(), - )); - } DASHBOARDS.update(&dashboard).await; - let path = dashboard_path(&user_id, &format!("{}.json", dashboard_id)); + let path = dashboard_path(&user_id, &format!("{}.json", dashboard.dashboard_id)); let store = PARSEABLE.storage.get_object_store(); let dashboard_bytes = serde_json::to_vec(&dashboard)?; @@ -103,21 +84,11 @@ pub async fn update( user_id = get_hash(&user_id); let dashboard_id = dashboard_id.into_inner(); - if DASHBOARDS - .get_dashboard(&dashboard_id, &user_id) - .await - .is_none() - { - return Err(DashboardError::Metadata("Dashboard does not exist")); + if DASHBOARDS.get(&dashboard_id, &user_id).await.is_none() { + return Err(DashboardError::DashboardDoesNotExist); } - dashboard.dashboard_id = Some(dashboard_id.to_string()); + dashboard.dashboard_id = dashboard_id.to_string(); dashboard.user_id = Some(user_id.clone()); - dashboard.version = Some(CURRENT_DASHBOARD_VERSION.to_string()); - for tile in dashboard.tiles.iter_mut() { - if tile.tile_id.is_none() { - tile.tile_id = Some(get_hash(Utc::now().timestamp_micros().to_string().as_str())); - } - } DASHBOARDS.update(&dashboard).await; let path = dashboard_path(&user_id, &format!("{}.json", dashboard_id)); @@ -138,18 +109,14 @@ pub async fn delete( let mut user_id = get_user_from_request(&req)?; user_id = get_hash(&user_id); let dashboard_id = dashboard_id.into_inner(); - if DASHBOARDS - .get_dashboard(&dashboard_id, &user_id) - .await - .is_none() - { - return Err(DashboardError::Metadata("Dashboard does not exist")); + if DASHBOARDS.get(&dashboard_id, &user_id).await.is_none() { + return Err(DashboardError::DashboardDoesNotExist); } let path = dashboard_path(&user_id, &format!("{}.json", dashboard_id)); let store = PARSEABLE.storage.get_object_store(); store.delete_object(&path).await?; - DASHBOARDS.delete_dashboard(&dashboard_id).await; + DASHBOARDS.delete(&dashboard_id).await; Ok(HttpResponse::Ok().finish()) } @@ -162,6 +129,8 @@ pub enum DashboardError { Serde(#[from] SerdeError), #[error("Cannot perform this operation: {0}")] Metadata(&'static str), + #[error("Dashboard does not exist")] + DashboardDoesNotExist, #[error("User does not exist")] UserDoesNotExist(#[from] RBACError), #[error("Error: {0}")] @@ -174,6 +143,7 @@ impl actix_web::ResponseError for DashboardError { Self::ObjectStorage(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::Serde(_) => StatusCode::BAD_REQUEST, Self::Metadata(_) => StatusCode::BAD_REQUEST, + Self::DashboardDoesNotExist => StatusCode::NOT_FOUND, Self::UserDoesNotExist(_) => StatusCode::NOT_FOUND, Self::Custom(_) => StatusCode::INTERNAL_SERVER_ERROR, } diff --git a/src/prism/home/mod.rs b/src/prism/home/mod.rs index 95e03b8ce..96da615f5 100644 --- a/src/prism/home/mod.rs +++ b/src/prism/home/mod.rs @@ -117,15 +117,10 @@ pub async fn generate_home_response(key: &SessionKey) -> Result = Lazy::new(Dashboards::default); pub const CURRENT_DASHBOARD_VERSION: &str = "v3"; +fn gen_tile_id() -> String { + get_hash( + format!( + "{}{}", + rand::distributions::Alphanumeric.sample_string(&mut rand::thread_rng(), 8), + Utc::now().timestamp_micros() + ) + .as_str(), + ) +} + #[derive(Debug, Serialize, Deserialize, Default, Clone)] pub struct Tiles { name: String, - pub tile_id: Option, + #[serde(default = "gen_tile_id")] + pub tile_id: String, description: String, query: String, order: Option, @@ -94,12 +108,22 @@ pub struct TickConfig { unit: String, } +fn default_version() -> String { + CURRENT_DASHBOARD_VERSION.to_owned() +} + +fn gen_dashboard_id() -> String { + get_hash(Utc::now().timestamp_micros().to_string().as_str()) +} + #[derive(Debug, Serialize, Deserialize, Default, Clone)] pub struct Dashboard { - pub version: Option, + #[serde(default = "default_version")] + pub version: String, pub name: String, description: String, - pub dashboard_id: Option, + #[serde(default = "gen_dashboard_id")] + pub dashboard_id: String, pub user_id: Option, pub time_filter: Option, refresh_interval: u64, @@ -183,19 +207,18 @@ impl Dashboards { s.push(dashboard.clone()); } - pub async fn delete_dashboard(&self, dashboard_id: &str) { + pub async fn delete(&self, dashboard_id: &str) { let mut s = self.0.write().await; - s.retain(|d| d.dashboard_id != Some(dashboard_id.to_string())); + s.retain(|d| d.dashboard_id != dashboard_id); } - pub async fn get_dashboard(&self, dashboard_id: &str, user_id: &str) -> Option { + pub async fn get(&self, dashboard_id: &str, user_id: &str) -> Option { self.0 .read() .await .iter() .find(|d| { - d.dashboard_id == Some(dashboard_id.to_string()) - && d.user_id == Some(user_id.to_string()) + d.dashboard_id == dashboard_id && d.user_id.as_ref().is_some_and(|id| id == user_id) }) .cloned() } @@ -209,12 +232,9 @@ impl Dashboards { let mut skip_dashboard = false; for tile in d.tiles.iter() { let query = &tile.query; - match user_auth_for_query(key, query).await { - Ok(_) => {} - Err(_) => { - skip_dashboard = true; - break; - } + if user_auth_for_query(key, query).await.is_err() { + skip_dashboard = true; + break; } } if !skip_dashboard {