diff --git a/api/Cargo.toml b/api/Cargo.toml index 354ab1e98..07532fa64 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -110,7 +110,6 @@ diesel_migrations = "2.0.0" html-escape = "0.2.13" tokio-cron-scheduler = "0.13.0" tokio-retry = "0.3.0" -fastembed = "4.8.0" [profile.release] debug = false diff --git a/api/libs/handlers/src/dashboards/get_dashboard_handler.rs b/api/libs/handlers/src/dashboards/get_dashboard_handler.rs index e0baea354..b279ae641 100644 --- a/api/libs/handlers/src/dashboards/get_dashboard_handler.rs +++ b/api/libs/handlers/src/dashboards/get_dashboard_handler.rs @@ -130,9 +130,22 @@ pub async fn get_dashboard_handler( tracing::debug!(dashboard_id = %dashboard_id, ?direct_permission_level, has_sufficient_direct_permission, "Direct permission check result"); if has_sufficient_direct_permission { - // User has direct/admin permission, use that role - permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case - tracing::debug!(dashboard_id = %dashboard_id, user_id = %user.id, ?permission, "Granting access via direct/admin permission."); + // Check if user is WorkspaceAdmin or DataAdmin for this organization + let is_admin = user.organizations.iter().any(|org| { + org.id == dashboard_file.organization_id + && (org.role == database::enums::UserOrganizationRole::WorkspaceAdmin + || org.role == database::enums::UserOrganizationRole::DataAdmin) + }); + + if is_admin { + // Admin users get Owner permissions + permission = AssetPermissionRole::Owner; + tracing::debug!(dashboard_id = %dashboard_id, user_id = %user.id, ?permission, "Granting Owner access to admin user."); + } else { + // User has direct permission, use that role + permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case + tracing::debug!(dashboard_id = %dashboard_id, user_id = %user.id, ?permission, "Granting access via direct permission."); + } } else { // No sufficient direct/admin permission, check public access rules tracing::debug!(dashboard_id = %dashboard_id, "Insufficient direct/admin permission. Checking public access rules."); diff --git a/api/libs/handlers/src/metrics/get_metric_handler.rs b/api/libs/handlers/src/metrics/get_metric_handler.rs index 1219b3694..0b3957475 100644 --- a/api/libs/handlers/src/metrics/get_metric_handler.rs +++ b/api/libs/handlers/src/metrics/get_metric_handler.rs @@ -138,9 +138,22 @@ pub async fn get_metric_handler( tracing::debug!(metric_id = %metric_id, ?direct_permission_level, has_sufficient_direct_permission, "Direct permission check result"); if has_sufficient_direct_permission { - // User has direct/admin permission, use that role - permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case - tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting access via direct/admin permission."); + // Check if user is WorkspaceAdmin or DataAdmin for this organization + let is_admin = user.organizations.iter().any(|org| { + org.id == metric_file.organization_id + && (org.role == database::enums::UserOrganizationRole::WorkspaceAdmin + || org.role == database::enums::UserOrganizationRole::DataAdmin) + }); + + if is_admin { + // Admin users get Owner permissions + permission = AssetPermissionRole::Owner; + tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting Owner access to admin user."); + } else { + // User has direct permission, use that role + permission = direct_permission_level.unwrap_or(AssetPermissionRole::CanView); // Default just in case + tracing::debug!(metric_id = %metric_id, user_id = %user.id, ?permission, "Granting access via direct permission."); + } } else { // No sufficient direct/admin permission, check public access rules tracing::debug!(metric_id = %metric_id, "Insufficient direct/admin permission. Checking public access rules."); diff --git a/api/libs/handlers/tests/dashboards/get_dashboard_handler_permission_test.rs b/api/libs/handlers/tests/dashboards/get_dashboard_handler_permission_test.rs index ae809222f..8edf5ee17 100644 --- a/api/libs/handlers/tests/dashboards/get_dashboard_handler_permission_test.rs +++ b/api/libs/handlers/tests/dashboards/get_dashboard_handler_permission_test.rs @@ -202,9 +202,9 @@ async fn test_get_dashboard_admin_role_public_password() -> Result<()> { let result = get_dashboard_handler(&dashboard.id, &auth_user, None, None).await; // No password assert!(result.is_ok()); - // Admins currently default to CanView if no explicit permission exists on the asset itself + // Admins should get Owner permissions regardless of explicit asset permissions let response = result.unwrap(); - assert_eq!(response.permission, AssetPermissionRole::CanView); + assert_eq!(response.permission, AssetPermissionRole::Owner); cleanup_test_data(&[dashboard.id]).await?; Ok(()) diff --git a/api/libs/handlers/tests/metrics/get_metric_handler_permission_test.rs b/api/libs/handlers/tests/metrics/get_metric_handler_permission_test.rs index a2b006780..34b7cbdad 100644 --- a/api/libs/handlers/tests/metrics/get_metric_handler_permission_test.rs +++ b/api/libs/handlers/tests/metrics/get_metric_handler_permission_test.rs @@ -232,11 +232,9 @@ async fn test_get_metric_admin_role_public_password() -> Result<()> { let result = get_metric_handler(&metric.id, &auth_user, None, None).await; // No password provided assert!(result.is_ok()); - // Admins currently default to CanView if no explicit permission exists on the asset itself, - // even though check_permission_access returns true. This might be desired or not. - // Let's assert CanView for now, reflecting current check_permission_access behavior combined with handler logic. + // Admins should get Owner permissions regardless of explicit asset permissions let response = result.unwrap(); - assert_eq!(response.permission, AssetPermissionRole::CanView); + assert_eq!(response.permission, AssetPermissionRole::Owner); cleanup_test_data(&[metric.id]).await?; Ok(()) diff --git a/api/libs/rerank/Cargo.toml b/api/libs/rerank/Cargo.toml index 52ad7369c..2c0b57863 100644 --- a/api/libs/rerank/Cargo.toml +++ b/api/libs/rerank/Cargo.toml @@ -8,7 +8,6 @@ reqwest = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } dotenv = { workspace = true } -fastembed = "4.8.0" [dev-dependencies] dotenv = { workspace = true } diff --git a/api/libs/rerank/src/lib.rs b/api/libs/rerank/src/lib.rs index 95fb716b9..fe7cea322 100644 --- a/api/libs/rerank/src/lib.rs +++ b/api/libs/rerank/src/lib.rs @@ -1,8 +1,8 @@ +use dotenv::dotenv; use reqwest::Client; use serde::{Deserialize, Serialize}; -use std::error::Error; -use dotenv::dotenv; use std::env; +use std::error::Error; pub struct Reranker { api_key: String, @@ -16,7 +16,7 @@ impl Reranker { pub fn new() -> Result> { dotenv().ok(); let environment = env::var("ENVIRONMENT").unwrap_or_else(|_| "production".to_string()); - + // If local environment, we don't need these values let (api_key, model, base_url) = if environment == "local" { (String::new(), String::new(), String::new()) @@ -27,7 +27,7 @@ impl Reranker { env::var("RERANK_BASE_URL")?, ) }; - + let client = Client::new(); Ok(Self { api_key, @@ -44,11 +44,6 @@ impl Reranker { documents: &[&str], top_n: usize, ) -> Result, Box> { - // Use local fastembed reranking if ENVIRONMENT is set to local - if self.environment == "local" { - return self.local_rerank(query, documents, top_n).await; - } - // Otherwise use the remote API let request_body = RerankRequest { query: query.to_string(), @@ -66,37 +61,6 @@ impl Reranker { let response_body: RerankResponse = response.json().await?; Ok(response_body.results) } - - async fn local_rerank( - &self, - query: &str, - documents: &[&str], - top_n: usize, - ) -> Result, Box> { - use fastembed::{TextRerank, RerankInitOptions, RerankerModel}; - - // Initialize the reranker model - let model = TextRerank::try_new( - RerankInitOptions::new(RerankerModel::JINARerankerV1TurboEn).with_show_download_progress(true), - )?; - - // Limit top_n to the number of documents - let actual_top_n = std::cmp::min(top_n, documents.len()); - - // Perform reranking - let fastembed_results = model.rerank(query, documents.to_vec(),false, Some(actual_top_n))?; - - // Convert fastembed results to our RerankResult format - let results = fastembed_results - .iter() - .map(|result| RerankResult { - index: result.index, - relevance_score: result.score, - }) - .collect(); - - Ok(results) - } } #[derive(Serialize)] @@ -116,4 +80,4 @@ struct RerankResponse { pub struct RerankResult { pub index: usize, pub relevance_score: f32, -} \ No newline at end of file +} diff --git a/api/server/Cargo.toml b/api/server/Cargo.toml index 9eadbf44b..8d54a687d 100644 --- a/api/server/Cargo.toml +++ b/api/server/Cargo.toml @@ -39,7 +39,6 @@ tower-http = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } uuid = { workspace = true } -fastembed = { workspace = true } # Local dependencies handlers = { path = "../libs/handlers" } diff --git a/api/server/src/main.rs b/api/server/src/main.rs index 7b799fe1d..674d82524 100644 --- a/api/server/src/main.rs +++ b/api/server/src/main.rs @@ -22,7 +22,6 @@ use tower::ServiceBuilder; use tower_http::{compression::CompressionLayer, trace::TraceLayer}; use tracing::{error, info, warn}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; -use fastembed::{InitOptions, RerankInitOptions, RerankerModel, TextRerank}; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); @@ -34,13 +33,6 @@ async fn main() -> Result<(), anyhow::Error> { let environment = env::var("ENVIRONMENT").unwrap_or_else(|_| "development".to_string()); let is_development = environment == "development"; - if environment == "local" { - let options = - RerankInitOptions::new(RerankerModel::JINARerankerV1TurboEn).with_show_download_progress(true); - let model = TextRerank::try_new(options)?; - println!("Model loaded and ready!"); - } - ring::default_provider() .install_default() .expect("Failed to install default crypto provider");