enhancement_dashboard_collections

This commit is contained in:
dal 2025-04-01 13:22:05 -06:00
parent d5bd1d2ab4
commit 74a2c4a493
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
2 changed files with 99 additions and 4 deletions

View File

@ -8,14 +8,15 @@ use futures::future::join_all;
use middleware::AuthenticatedUser;
use serde_json::Value;
use serde_yaml;
use tokio::task::JoinHandle;
use uuid::Uuid;
use crate::dashboards::types::BusterShareIndividual;
use crate::dashboards::types::{BusterShareIndividual, DashboardCollection};
use crate::metrics::{get_metric_handler, BusterMetric, Version};
use database::enums::{AssetPermissionRole, AssetType, IdentityType, Verification};
use database::helpers::dashboard_files::fetch_dashboard_file_with_permission;
use database::pool::get_pg_pool;
use database::schema::{asset_permissions, dashboard_files, users};
use database::schema::{asset_permissions, collections, collections_to_assets, dashboard_files, users};
use database::types::VersionHistory;
use sharing::check_permission_access;
@ -50,6 +51,28 @@ struct AssetPermissionInfo {
name: Option<String>,
}
/// Fetches collections that the dashboard belongs to
async fn fetch_associated_collections_for_dashboard(dashboard_id: Uuid) -> Result<Vec<DashboardCollection>> {
let mut conn = get_pg_pool().get().await?;
let associated_collections = collections_to_assets::table
.inner_join(collections::table.on(collections::id.eq(collections_to_assets::collection_id)))
.filter(collections_to_assets::asset_id.eq(dashboard_id))
.filter(collections_to_assets::asset_type.eq(AssetType::DashboardFile))
.filter(collections::deleted_at.is_null()) // Ensure collection isn't deleted
.select((collections::id, collections::name))
.load::<(Uuid, String)>(&mut conn)
.await?
.into_iter()
.map(|(id, name)| DashboardCollection {
id: id.to_string(),
name
})
.collect();
Ok(associated_collections)
}
pub async fn get_dashboard_handler(
dashboard_id: &Uuid,
user: &AuthenticatedUser,
@ -217,6 +240,13 @@ pub async fn get_dashboard_handler(
Err(_) => None,
};
// Clone dashboard_id for use in spawned task
let d_id = *dashboard_id;
// Spawn task to fetch collections concurrently
let collections_handle: JoinHandle<Result<Vec<DashboardCollection>>> =
tokio::spawn(async move { fetch_associated_collections_for_dashboard(d_id).await });
// Construct the dashboard using content values where available
let dashboard = BusterDashboard {
config,
@ -235,6 +265,22 @@ pub async fn get_dashboard_handler(
file_name: dashboard_file.file_name,
};
// Await collections result
let collections_result = collections_handle.await;
// Handle collections result
let collections = match collections_result {
Ok(Ok(c)) => c,
Ok(Err(e)) => {
tracing::error!("Failed to fetch associated collections for dashboard {}: {}", dashboard_id, e);
vec![]
}
Err(e) => { // JoinError
tracing::error!("Task join error fetching collections for dashboard {}: {}", dashboard_id, e);
vec![]
}
};
Ok(BusterDashboardResponse {
access: dashboard_with_permission
.permission
@ -245,7 +291,7 @@ pub async fn get_dashboard_handler(
.permission
.unwrap_or(AssetPermissionRole::Owner),
public_password: None,
collections: vec![], // Empty collections for now
collections, // Now populated with associated collections
// New sharing fields
individual_permissions,
publicly_accessible: dashboard_file.publicly_accessible,

View File

@ -5,7 +5,7 @@ use crate::common::{
assertions::response::assert_api_ok,
};
use chrono::Utc;
use database::enums::{AssetPermissionRole, AssetTypeEnum, IdentityTypeEnum};
use database::enums::{AssetPermissionRole, AssetType, AssetTypeEnum, IdentityTypeEnum};
use diesel::{ExpressionMethods, QueryDsl};
use diesel_async::RunQueryDsl;
@ -25,6 +25,9 @@ async fn test_get_dashboard_with_sharing_info() {
// Add public sharing
enable_public_sharing(&env, dashboard_id, user_id).await;
// Create a collection and add the dashboard to it
let collection_id = create_collection_and_add_dashboard(&env, dashboard_id, user_id).await;
// Test GET request
let response = client
.get(&format!("/api/v1/dashboards/{}", dashboard_id))
@ -48,6 +51,12 @@ async fn test_get_dashboard_with_sharing_info() {
assert_eq!(permission["email"], "test2@example.com");
assert_eq!(permission["role"], "viewer");
assert_eq!(permission["name"], "Test User 2");
// Check collections
assert_eq!(data["collections"].as_array().unwrap().len(), 1);
let collection = &data["collections"][0];
assert_eq!(collection["id"], collection_id.to_string());
assert_eq!(collection["name"], "Test Collection");
}
// Helper functions to set up the test data
@ -141,4 +150,44 @@ async fn enable_public_sharing(env: &TestEnv, dashboard_id: Uuid, user_id: Uuid)
.execute(&mut conn)
.await
.unwrap();
}
async fn create_collection_and_add_dashboard(env: &TestEnv, dashboard_id: Uuid, user_id: Uuid) -> Uuid {
let mut conn = env.db_pool.get().await.unwrap();
// Get organization ID
let org_id = Uuid::parse_str("00000000-0000-0000-0000-000000000100").unwrap();
// Create a collection
let collection_id = Uuid::parse_str("00000000-0000-0000-0000-000000000030").unwrap();
diesel::sql_query(r#"
INSERT INTO collections (id, name, description, created_by, updated_by, organization_id)
VALUES ($1, $2, $3, $4, $4, $5)
ON CONFLICT DO NOTHING
"#)
.bind::<diesel::sql_types::Uuid, _>(collection_id)
.bind::<diesel::sql_types::Text, _>("Test Collection")
.bind::<diesel::sql_types::Text, _>("Test Collection Description")
.bind::<diesel::sql_types::Uuid, _>(user_id)
.bind::<diesel::sql_types::Uuid, _>(org_id)
.execute(&mut conn)
.await
.unwrap();
// Add the dashboard to the collection
diesel::sql_query(r#"
INSERT INTO collections_to_assets (collection_id, asset_id, asset_type, created_by, updated_by)
VALUES ($1, $2, $3, $4, $4)
ON CONFLICT DO NOTHING
"#)
.bind::<diesel::sql_types::Uuid, _>(collection_id)
.bind::<diesel::sql_types::Uuid, _>(dashboard_id)
.bind::<diesel::sql_types::Text, _>(AssetType::DashboardFile.to_string())
.bind::<diesel::sql_types::Uuid, _>(user_id)
.execute(&mut conn)
.await
.unwrap();
collection_id
}