Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/handlers/http/modal/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ impl Server {
.authorize(Action::CreateDashboard),
),
)
.service(
web::resource("/add_tile").route(
web::post()
.to(dashboards::add_tile)
.authorize(Action::CreateDashboard),
),
)
}

// get the filters web scope
Expand Down
166 changes: 79 additions & 87 deletions src/handlers/http/users/dashboards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,52 @@

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},
storage::ObjectStorageError,
users::dashboards::{Dashboard, Tile, DASHBOARDS},
utils::{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;

pub async fn list(req: HttpRequest) -> Result<impl Responder, DashboardError> {
let key =
extract_session_key_from_req(&req).map_err(|e| DashboardError::Custom(e.to_string()))?;
let dashboards = DASHBOARDS.list_dashboards(&key).await;

use serde_json::{Error as SerdeError, Map};
use ulid::Ulid;

pub async fn list() -> Result<impl Responder, DashboardError> {
let dashboards = DASHBOARDS.list_dashboards().await;
//dashboards list should contain the title, author and modified date
let dashboards: Vec<Map<String, serde_json::Value>> = dashboards
.iter()
.map(|dashboard| {
let mut map = Map::new();
map.insert(
"title".to_string(),
serde_json::Value::String(dashboard.title.clone()),
);
map.insert(
"author".to_string(),
serde_json::Value::String(dashboard.author.as_ref().unwrap().clone()),
);
map.insert(
"modified".to_string(),
serde_json::Value::String(dashboard.modified.unwrap().to_string()),
);
map
})
.collect();
Ok((web::Json(dashboards), StatusCode::OK))
}

pub async fn get(
req: HttpRequest,
dashboard_id: Path<String>,
) -> Result<impl Responder, DashboardError> {
let user_id = get_user_from_request(&req)?;
let dashboard_id = dashboard_id.into_inner();
pub async fn get(dashboard_id: Path<String>) -> Result<impl Responder, DashboardError> {
let dashboard_id = if let Ok(dashboard_id) = Ulid::from_string(&dashboard_id.into_inner()) {
dashboard_id
} else {
return Err(DashboardError::Metadata("Invalid dashboard ID"));
};

if let Some(dashboard) = DASHBOARDS
.get_dashboard(&dashboard_id, &get_hash(&user_id))
.await
{
if let Some(dashboard) = DASHBOARDS.get_dashboard(dashboard_id).await {
return Ok((web::Json(dashboard), StatusCode::OK));
}

Expand All @@ -66,31 +76,9 @@ pub async fn post(
) -> Result<impl Responder, DashboardError> {
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 store = PARSEABLE.storage.get_object_store();
let dashboard_bytes = serde_json::to_vec(&dashboard)?;
store
.put_object(&path, Bytes::from(dashboard_bytes))
.await?;
dashboard.author = Some(user_id.clone());

DASHBOARDS.create(&user_id, &mut dashboard).await?;
Ok((web::Json(dashboard), StatusCode::OK))
}

Expand All @@ -101,33 +89,16 @@ pub async fn update(
) -> Result<impl Responder, DashboardError> {
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"));
}
dashboard.dashboard_id = Some(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));

let store = PARSEABLE.storage.get_object_store();
let dashboard_bytes = serde_json::to_vec(&dashboard)?;
store
.put_object(&path, Bytes::from(dashboard_bytes))
let dashboard_id = if let Ok(dashboard_id) = Ulid::from_string(&dashboard_id.into_inner()) {
dashboard_id
} else {
return Err(DashboardError::Metadata("Invalid dashboard ID"));
};
dashboard.author = Some(user_id.clone());

DASHBOARDS
.update(&user_id, dashboard_id, &mut dashboard)
.await?;

Ok((web::Json(dashboard), StatusCode::OK))
}

Expand All @@ -137,21 +108,42 @@ pub async fn delete(
) -> Result<HttpResponse, DashboardError> {
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)
let dashboard_id = if let Ok(dashboard_id) = Ulid::from_string(&dashboard_id.into_inner()) {
dashboard_id
} else {
return Err(DashboardError::Metadata("Invalid dashboard ID"));
};
DASHBOARDS.delete_dashboard(&user_id, dashboard_id).await?;

Ok(HttpResponse::Ok().finish())
}

pub async fn add_tile(
req: HttpRequest,
dashboard_id: Path<String>,
Json(mut tile): Json<Tile>,
) -> Result<impl Responder, DashboardError> {
let mut user_id = get_user_from_request(&req)?;
user_id = get_hash(&user_id);
let dashboard_id = if let Ok(dashboard_id) = Ulid::from_string(&dashboard_id.into_inner()) {
dashboard_id
} else {
return Err(DashboardError::Metadata("Invalid dashboard ID"));
};

let mut dashboard = DASHBOARDS
.get_dashboard(dashboard_id)
.await
.is_none()
{
return Err(DashboardError::Metadata("Dashboard does not exist"));
.ok_or(DashboardError::Metadata("Dashboard does not exist"))?;
if tile.tile_id.is_nil() {
tile.tile_id = Ulid::new();
}
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;
dashboard.tiles.push(tile.clone());
DASHBOARDS
.update(&user_id, dashboard_id, &mut dashboard)
.await?;

Ok(HttpResponse::Ok().finish())
Ok((web::Json(dashboard), StatusCode::OK))
}

#[derive(Debug, thiserror::Error)]
Expand Down
15 changes: 5 additions & 10 deletions src/prism/home/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub async fn generate_home_response(key: &SessionKey) -> Result<HomeResponse, Pr
get_stream_titles(key),
get_alert_titles(key),
get_correlation_titles(key),
get_dashboard_titles(key),
get_dashboard_titles(),
get_filter_titles(key),
get_alerts_info()
);
Expand Down Expand Up @@ -239,19 +239,14 @@ async fn get_correlation_titles(key: &SessionKey) -> Result<Vec<TitleAndId>, Pri
Ok(correlation_titles)
}

async fn get_dashboard_titles(key: &SessionKey) -> Result<Vec<TitleAndId>, PrismHomeError> {
async fn get_dashboard_titles() -> Result<Vec<TitleAndId>, PrismHomeError> {
let dashboard_titles = DASHBOARDS
.list_dashboards(key)
.list_dashboards()
.await
.iter()
.map(|dashboard| TitleAndId {
title: dashboard.name.clone(),
id: dashboard
.dashboard_id
.as_ref()
.ok_or_else(|| anyhow::Error::msg("Dashboard ID is null"))
.unwrap()
.clone(),
title: dashboard.title.clone(),
id: dashboard.dashboard_id.as_ref().unwrap().to_string(),
})
.collect_vec();

Expand Down
Loading
Loading