From 28d3e3ee142df0b2ec70970d1626229f844eee6c Mon Sep 17 00:00:00 2001 From: dal Date: Fri, 4 Apr 2025 16:15:31 -0600 Subject: [PATCH] fix the user org id --- .../dashboards/create_dashboard_handler.rs | 7 +- .../rest/routes/api_keys/post_api_key.rs | 15 +- .../rest/routes/assets/get_asset_access.rs | 7 +- .../dataset_groups/assets/list_datasets.rs | 7 +- .../assets/list_permission_groups.rs | 7 +- .../dataset_groups/assets/list_users.rs | 7 +- .../dataset_groups/assets/put_datasets.rs | 7 +- .../assets/put_permission_groups.rs | 7 +- .../routes/dataset_groups/assets/put_users.rs | 7 +- .../dataset_groups/delete_dataset_group.rs | 14 +- .../dataset_groups/list_dataset_groups.rs | 7 +- .../dataset_groups/post_dataset_group.rs | 19 +- .../dataset_groups/put_dataset_group.rs | 14 +- .../datasets/assets/get_dataset_overview.rs | 14 +- .../datasets/assets/list_dataset_assets.rs | 14 +- .../datasets/assets/put_dataset_assets.rs | 7 +- .../rest/routes/datasets/post_dataset.rs | 27 +- .../assets/list_dataset_groups.rs | 7 +- .../permission_groups/assets/list_datasets.rs | 7 +- .../permission_groups/assets/list_users.rs | 7 +- .../assets/put_dataset_groups.rs | 7 +- .../permission_groups/assets/put_datasets.rs | 7 +- .../permission_groups/assets/put_users.rs | 7 +- .../delete_permission_group.rs | 19 +- .../permission_groups/get_permission_group.rs | 7 +- .../list_permission_groups.rs | 7 +- .../post_permission_group.rs | 19 +- .../permission_groups/put_permission_group.rs | 7 +- .../routes/users/assets/list_attributes.rs | 13 +- .../users/assets/list_dataset_groups.rs | 13 +- .../rest/routes/users/assets/list_datasets.rs | 13 +- .../users/assets/list_permission_groups.rs | 7 +- .../rest/routes/users/assets/list_teams.rs | 13 +- .../routes/users/assets/put_dataset_groups.rs | 13 +- .../rest/routes/users/assets/put_datasets.rs | 13 +- .../users/assets/put_permission_groups.rs | 13 +- .../rest/routes/users/assets/put_teams.rs | 13 +- .../routes/rest/routes/users/update_user.rs | 7 +- api/server/src/utils/mod.rs | 3 - api/server/src/utils/search_engine/mod.rs | 1 - .../src/utils/search_engine/search_engine.rs | 291 ----- api/server/src/utils/sharing/asset_sharing.rs | 1163 ----------------- api/server/src/utils/sharing/mod.rs | 1 - api/server/src/utils/user/mod.rs | 1 - api/server/src/utils/user/user_info.rs | 55 - 45 files changed, 293 insertions(+), 1628 deletions(-) delete mode 100644 api/server/src/utils/search_engine/mod.rs delete mode 100644 api/server/src/utils/search_engine/search_engine.rs delete mode 100644 api/server/src/utils/sharing/asset_sharing.rs delete mode 100644 api/server/src/utils/sharing/mod.rs delete mode 100644 api/server/src/utils/user/mod.rs delete mode 100644 api/server/src/utils/user/user_info.rs diff --git a/api/libs/handlers/src/dashboards/create_dashboard_handler.rs b/api/libs/handlers/src/dashboards/create_dashboard_handler.rs index 09a026f5f..76fb338e9 100644 --- a/api/libs/handlers/src/dashboards/create_dashboard_handler.rs +++ b/api/libs/handlers/src/dashboards/create_dashboard_handler.rs @@ -12,7 +12,7 @@ use uuid::Uuid; use crate::metrics::Version; use super::{BusterDashboard, BusterDashboardResponse, DashboardConfig}; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use database::enums::{AssetPermissionRole, AssetType, IdentityType, Verification}; use database::schema::asset_permissions; use std::collections::HashMap; @@ -37,7 +37,10 @@ pub async fn create_dashboard_handler(user: &AuthenticatedUser) -> Result organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; // Current timestamp let now = Utc::now(); diff --git a/api/server/src/routes/rest/routes/api_keys/post_api_key.rs b/api/server/src/routes/rest/routes/api_keys/post_api_key.rs index e9fefc8b6..a66e970a9 100644 --- a/api/server/src/routes/rest/routes/api_keys/post_api_key.rs +++ b/api/server/src/routes/rest/routes/api_keys/post_api_key.rs @@ -5,16 +5,16 @@ use chrono::Utc; use diesel::insert_into; use diesel_async::RunQueryDsl; use jsonwebtoken::{encode, EncodingKey, Header}; +use middleware::AuthenticatedUser; use serde::{Deserialize, Serialize}; use std::env; use uuid::Uuid; -use middleware::AuthenticatedUser; -use database::pool::get_pg_pool; -use database::models::ApiKey; -use database::schema::api_keys; use crate::routes::rest::ApiResponse; -use crate::utils::user::user_info::get_user_organization_id; +use database::models::ApiKey; +use database::organization::get_user_organization_id; +use database::pool::get_pg_pool; +use database::schema::api_keys; #[derive(Debug, Serialize)] pub struct PostApiKeyResponse { @@ -70,7 +70,10 @@ async fn post_api_key_handler(user: AuthenticatedUser) -> Result { }; let organization_id = match get_user_organization_id(&user.id).await { - Ok(organization_id) => organization_id, + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } Err(e) => { tracing::error!("Error getting organization ID: {:?}", e); return Err(anyhow::anyhow!("Error getting organization ID")); diff --git a/api/server/src/routes/rest/routes/assets/get_asset_access.rs b/api/server/src/routes/rest/routes/assets/get_asset_access.rs index 1a8ac2612..f1701d47f 100644 --- a/api/server/src/routes/rest/routes/assets/get_asset_access.rs +++ b/api/server/src/routes/rest/routes/assets/get_asset_access.rs @@ -12,7 +12,7 @@ use axum::http::StatusCode; use middleware::AuthenticatedUser; use crate::routes::rest::ApiResponse; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use database::enums::{AssetPermissionRole, AssetType, UserOrganizationRole}; use database::pool::{get_pg_pool, PgPool}; use database::schema::{ @@ -370,7 +370,10 @@ async fn is_organization_admin_or_owner( user_id: Arc, ) -> anyhow::Result { let user_organization_id = match get_user_organization_id(&user_id).await { - Ok(organization_id) => organization_id, + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } Err(e) => { tracing::error!("Error getting user organization id: {}", e); return Ok(false); diff --git a/api/server/src/routes/rest/routes/dataset_groups/assets/list_datasets.rs b/api/server/src/routes/rest/routes/dataset_groups/assets/list_datasets.rs index 207d77f67..b45ad0939 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/assets/list_datasets.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/assets/list_datasets.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{datasets, datasets_to_dataset_groups}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; /// Represents dataset information with its assignment status to a dataset group @@ -44,7 +44,10 @@ pub async fn list_datasets( async fn list_datasets_handler(user: AuthenticatedUser, dataset_group_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/dataset_groups/assets/list_permission_groups.rs b/api/server/src/routes/rest/routes/dataset_groups/assets/list_permission_groups.rs index f98e8f6ef..94143e1e1 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/assets/list_permission_groups.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/assets/list_permission_groups.rs @@ -14,7 +14,7 @@ use database::schema::{ }; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; /// Represents permission group information with its assignment status to a dataset group @@ -52,7 +52,10 @@ async fn list_permission_groups_handler( dataset_group_id: Uuid, ) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/dataset_groups/assets/list_users.rs b/api/server/src/routes/rest/routes/dataset_groups/assets/list_users.rs index caa18c908..4c1c31fb7 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/assets/list_users.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/assets/list_users.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{dataset_groups_permissions, users, users_to_organizations}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; /// Represents user information with their assignment status to a dataset group @@ -45,7 +45,10 @@ pub async fn list_users( async fn list_users_handler(user: AuthenticatedUser, dataset_group_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/dataset_groups/assets/put_datasets.rs b/api/server/src/routes/rest/routes/dataset_groups/assets/put_datasets.rs index 949229391..812c9e844 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/assets/put_datasets.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/assets/put_datasets.rs @@ -13,7 +13,7 @@ use database::models::DatasetToDatasetGroup; use database::schema::datasets_to_dataset_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -46,7 +46,10 @@ async fn put_datasets_handler( dataset_group_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/dataset_groups/assets/put_permission_groups.rs b/api/server/src/routes/rest/routes/dataset_groups/assets/put_permission_groups.rs index af0a79251..924d789e8 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/assets/put_permission_groups.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/assets/put_permission_groups.rs @@ -13,7 +13,7 @@ use database::models::DatasetGroupPermission; use database::schema::dataset_groups_permissions; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -46,7 +46,10 @@ async fn put_permission_groups_handler( dataset_group_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/dataset_groups/assets/put_users.rs b/api/server/src/routes/rest/routes/dataset_groups/assets/put_users.rs index 7c1953494..d50dd2d47 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/assets/put_users.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/assets/put_users.rs @@ -13,7 +13,7 @@ use database::models::DatasetGroupPermission; use database::schema::dataset_groups_permissions; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -46,7 +46,10 @@ async fn put_users_handler( dataset_group_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/dataset_groups/delete_dataset_group.rs b/api/server/src/routes/rest/routes/dataset_groups/delete_dataset_group.rs index ec23bf2d7..31103503c 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/delete_dataset_group.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/delete_dataset_group.rs @@ -9,7 +9,7 @@ use database::pool::get_pg_pool; use database::schema::dataset_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; pub async fn delete_dataset_group( @@ -17,10 +17,14 @@ pub async fn delete_dataset_group( Path(dataset_group_id): Path, ) -> Result, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), diff --git a/api/server/src/routes/rest/routes/dataset_groups/list_dataset_groups.rs b/api/server/src/routes/rest/routes/dataset_groups/list_dataset_groups.rs index b405aac9e..49e6b71aa 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/list_dataset_groups.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/list_dataset_groups.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::models::DatasetGroup; use database::schema::dataset_groups; use crate::routes::rest::ApiResponse; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -41,7 +41,10 @@ pub async fn list_dataset_groups( async fn list_dataset_groups_handler(user: AuthenticatedUser) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let dataset_groups = dataset_groups::table .filter(dataset_groups::deleted_at.is_null()) diff --git a/api/server/src/routes/rest/routes/dataset_groups/post_dataset_group.rs b/api/server/src/routes/rest/routes/dataset_groups/post_dataset_group.rs index 63df34894..a89c778e5 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/post_dataset_group.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/post_dataset_group.rs @@ -12,7 +12,7 @@ use database::models::DatasetGroup; use database::schema::dataset_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Deserialize)] @@ -33,10 +33,14 @@ pub async fn post_dataset_group( Json(request): Json, ) -> Result, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), @@ -75,7 +79,10 @@ async fn post_dataset_group_handler( ) -> Result { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let dataset_group = DatasetGroup { id: Uuid::new_v4(), diff --git a/api/server/src/routes/rest/routes/dataset_groups/put_dataset_group.rs b/api/server/src/routes/rest/routes/dataset_groups/put_dataset_group.rs index f5195d058..865392e8d 100644 --- a/api/server/src/routes/rest/routes/dataset_groups/put_dataset_group.rs +++ b/api/server/src/routes/rest/routes/dataset_groups/put_dataset_group.rs @@ -10,7 +10,7 @@ use database::pool::get_pg_pool; use database::schema::dataset_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Deserialize, Clone)] @@ -24,10 +24,14 @@ pub async fn put_dataset_group( Json(request): Json>, ) -> Result, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), diff --git a/api/server/src/routes/rest/routes/datasets/assets/get_dataset_overview.rs b/api/server/src/routes/rest/routes/datasets/assets/get_dataset_overview.rs index 104108ae1..c4fed31d0 100644 --- a/api/server/src/routes/rest/routes/datasets/assets/get_dataset_overview.rs +++ b/api/server/src/routes/rest/routes/datasets/assets/get_dataset_overview.rs @@ -19,7 +19,7 @@ use database::{ }; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; #[derive(Debug, Serialize)] pub struct UserPermissionLineage { @@ -49,10 +49,14 @@ pub async fn get_dataset_overview( Path(dataset_id): Path, ) -> Result, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), diff --git a/api/server/src/routes/rest/routes/datasets/assets/list_dataset_assets.rs b/api/server/src/routes/rest/routes/datasets/assets/list_dataset_assets.rs index c999eb5f9..9adb96582 100644 --- a/api/server/src/routes/rest/routes/datasets/assets/list_dataset_assets.rs +++ b/api/server/src/routes/rest/routes/datasets/assets/list_dataset_assets.rs @@ -15,7 +15,7 @@ use database::{ }; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; #[derive(Debug, Serialize)] pub struct AssetWithAssignment { @@ -35,10 +35,14 @@ pub async fn list_assets( Path((dataset_id, permission_type)): Path<(Uuid, String)>, ) -> Result>, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), diff --git a/api/server/src/routes/rest/routes/datasets/assets/put_dataset_assets.rs b/api/server/src/routes/rest/routes/datasets/assets/put_dataset_assets.rs index adff9a884..56cd0f838 100644 --- a/api/server/src/routes/rest/routes/datasets/assets/put_dataset_assets.rs +++ b/api/server/src/routes/rest/routes/datasets/assets/put_dataset_assets.rs @@ -16,7 +16,7 @@ use database::{ }; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; #[derive(Debug, Deserialize)] pub struct AssetAssignment { @@ -45,7 +45,10 @@ pub async fn put_permissions_handler( (dataset_id, permission_type): (Uuid, String), assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), diff --git a/api/server/src/routes/rest/routes/datasets/post_dataset.rs b/api/server/src/routes/rest/routes/datasets/post_dataset.rs index 0e55de96a..a8ca1dd26 100644 --- a/api/server/src/routes/rest/routes/datasets/post_dataset.rs +++ b/api/server/src/routes/rest/routes/datasets/post_dataset.rs @@ -2,25 +2,24 @@ use anyhow::{anyhow, Result}; use axum::{extract::Json, Extension}; use diesel::{ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; +use middleware::AuthenticatedUser; use reqwest::StatusCode; use serde::Deserialize; use uuid::Uuid; -use middleware::AuthenticatedUser; use crate::{ database::{ enums::DatasetType, - pool::get_pg_pool, models::{DataSource, Dataset}, + pool::get_pg_pool, schema::{data_sources, datasets}, }, routes::rest::ApiResponse, - utils::{ - security::checks::is_user_workspace_admin_or_data_admin, - user::user_info::get_user_organization_id, - }, + utils::security::checks::is_user_workspace_admin_or_data_admin, }; +use database::organization::get_user_organization_id; + #[derive(Debug, Deserialize)] pub struct PostDatasetReq { pub name: String, @@ -33,12 +32,18 @@ pub async fn post_dataset( ) -> Result, (axum::http::StatusCode, String)> { // Check if user is workspace admin or data admin let organization_id = match get_user_organization_id(&user.id).await { - Ok(id) => id, + Ok(Some(id)) => id, + Ok(None) => { + return Err(( + StatusCode::FORBIDDEN, + "User does not belong to any organization", + )); + } Err(e) => { tracing::error!("Error getting user organization id: {:?}", e); return Err(( StatusCode::INTERNAL_SERVER_ERROR, - "Error getting user organization id".to_string(), + "Error getting user organization id", )); } }; @@ -48,14 +53,14 @@ pub async fn post_dataset( Ok(false) => { return Err(( StatusCode::FORBIDDEN, - "Insufficient permissions".to_string(), + "Insufficient permissions", )) } Err(e) => { tracing::error!("Error checking user permissions: {:?}", e); return Err(( StatusCode::INTERNAL_SERVER_ERROR, - "Error checking user permissions".to_string(), + "Error checking user permissions", )); } } @@ -73,7 +78,7 @@ pub async fn post_dataset( tracing::error!("Error creating dataset: {:?}", e); return Err(( StatusCode::INTERNAL_SERVER_ERROR, - "Error creating dataset".to_string(), + "Error creating dataset", )); } }; diff --git a/api/server/src/routes/rest/routes/permission_groups/assets/list_dataset_groups.rs b/api/server/src/routes/rest/routes/permission_groups/assets/list_dataset_groups.rs index 7d4ae7a73..ea5cf4508 100644 --- a/api/server/src/routes/rest/routes/permission_groups/assets/list_dataset_groups.rs +++ b/api/server/src/routes/rest/routes/permission_groups/assets/list_dataset_groups.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{dataset_groups, dataset_groups_permissions}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; /// Represents dataset group information with its assignment status to a permission group @@ -47,7 +47,10 @@ async fn list_dataset_groups_handler( permission_group_id: Uuid, ) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/permission_groups/assets/list_datasets.rs b/api/server/src/routes/rest/routes/permission_groups/assets/list_datasets.rs index b2b29e721..e7c73b3da 100644 --- a/api/server/src/routes/rest/routes/permission_groups/assets/list_datasets.rs +++ b/api/server/src/routes/rest/routes/permission_groups/assets/list_datasets.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{dataset_permissions, datasets}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; /// Represents dataset information with its assignment status to a permission group @@ -44,7 +44,10 @@ pub async fn list_datasets( async fn list_datasets_handler(user: AuthenticatedUser, permission_group_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/permission_groups/assets/list_users.rs b/api/server/src/routes/rest/routes/permission_groups/assets/list_users.rs index 8fa6a1501..0a79626ef 100644 --- a/api/server/src/routes/rest/routes/permission_groups/assets/list_users.rs +++ b/api/server/src/routes/rest/routes/permission_groups/assets/list_users.rs @@ -12,7 +12,7 @@ use database::pool::get_pg_pool; use database::schema::{permission_groups_to_identities, users, users_to_organizations}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; /// Represents user information with their assignment status to a permission group @@ -46,7 +46,10 @@ pub async fn list_users( async fn list_users_handler(user: AuthenticatedUser, permission_group_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/permission_groups/assets/put_dataset_groups.rs b/api/server/src/routes/rest/routes/permission_groups/assets/put_dataset_groups.rs index b78cc9a52..e2e51345f 100644 --- a/api/server/src/routes/rest/routes/permission_groups/assets/put_dataset_groups.rs +++ b/api/server/src/routes/rest/routes/permission_groups/assets/put_dataset_groups.rs @@ -13,7 +13,7 @@ use database::models::DatasetGroupPermission; use database::schema::dataset_groups_permissions; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -46,7 +46,10 @@ async fn put_dataset_groups_handler( permission_group_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/permission_groups/assets/put_datasets.rs b/api/server/src/routes/rest/routes/permission_groups/assets/put_datasets.rs index b2de19e3f..a90d777a8 100644 --- a/api/server/src/routes/rest/routes/permission_groups/assets/put_datasets.rs +++ b/api/server/src/routes/rest/routes/permission_groups/assets/put_datasets.rs @@ -13,7 +13,7 @@ use database::models::DatasetPermission; use database::schema::dataset_permissions; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -46,7 +46,10 @@ async fn put_datasets_handler( permission_group_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/permission_groups/assets/put_users.rs b/api/server/src/routes/rest/routes/permission_groups/assets/put_users.rs index e85dfbce3..e4a1c34bc 100644 --- a/api/server/src/routes/rest/routes/permission_groups/assets/put_users.rs +++ b/api/server/src/routes/rest/routes/permission_groups/assets/put_users.rs @@ -14,7 +14,7 @@ use database::models::PermissionGroupToIdentity; use database::schema::permission_groups_to_identities; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -47,7 +47,10 @@ async fn put_users_handler( permission_group_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/permission_groups/delete_permission_group.rs b/api/server/src/routes/rest/routes/permission_groups/delete_permission_group.rs index af0aa880c..f333bea91 100644 --- a/api/server/src/routes/rest/routes/permission_groups/delete_permission_group.rs +++ b/api/server/src/routes/rest/routes/permission_groups/delete_permission_group.rs @@ -9,7 +9,7 @@ use database::pool::get_pg_pool; use database::schema::permission_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; pub async fn delete_permission_group( @@ -17,10 +17,14 @@ pub async fn delete_permission_group( Path(permission_group_id): Path, ) -> Result, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), @@ -48,7 +52,10 @@ pub async fn delete_permission_group( async fn delete_permission_group_handler(user: AuthenticatedUser, permission_group_id: Uuid) -> Result<()> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let rows_affected = diesel::update( permission_groups::table diff --git a/api/server/src/routes/rest/routes/permission_groups/get_permission_group.rs b/api/server/src/routes/rest/routes/permission_groups/get_permission_group.rs index 8bb5011f5..5dbc7208d 100644 --- a/api/server/src/routes/rest/routes/permission_groups/get_permission_group.rs +++ b/api/server/src/routes/rest/routes/permission_groups/get_permission_group.rs @@ -10,7 +10,7 @@ use database::pool::get_pg_pool; use database::models::PermissionGroup; use database::schema::permission_groups; use crate::routes::rest::ApiResponse; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -47,7 +47,10 @@ async fn get_permission_group_handler( permission_group_id: Uuid, ) -> Result { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let permission_group = permission_groups::table .filter(permission_groups::id.eq(permission_group_id)) diff --git a/api/server/src/routes/rest/routes/permission_groups/list_permission_groups.rs b/api/server/src/routes/rest/routes/permission_groups/list_permission_groups.rs index e9e8248fb..f20da6f04 100644 --- a/api/server/src/routes/rest/routes/permission_groups/list_permission_groups.rs +++ b/api/server/src/routes/rest/routes/permission_groups/list_permission_groups.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{permission_groups, permission_groups_to_identities, dataset_permissions, dataset_groups_permissions}; use database::enums::IdentityType; use crate::routes::rest::ApiResponse; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -47,7 +47,10 @@ pub async fn list_permission_groups( async fn list_permission_groups_handler(user: AuthenticatedUser) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let permission_groups = permission_groups::table .left_join( diff --git a/api/server/src/routes/rest/routes/permission_groups/post_permission_group.rs b/api/server/src/routes/rest/routes/permission_groups/post_permission_group.rs index 256814cd5..42a162757 100644 --- a/api/server/src/routes/rest/routes/permission_groups/post_permission_group.rs +++ b/api/server/src/routes/rest/routes/permission_groups/post_permission_group.rs @@ -12,7 +12,7 @@ use database::models::PermissionGroup; use database::schema::permission_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Deserialize)] @@ -36,10 +36,14 @@ pub async fn post_permission_group( Json(request): Json, ) -> Result, (StatusCode, &'static str)> { // Check if user is workspace admin or data admin - let organization_id = get_user_organization_id(&user.id).await.map_err(|e| { - tracing::error!("Error getting user organization id: {:?}", e); - (StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id") - })?; + let organization_id = match get_user_organization_id(&user.id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => return Err((StatusCode::FORBIDDEN, "User does not belong to any organization")), + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err((StatusCode::INTERNAL_SERVER_ERROR, "Error getting user organization id")); + } + }; match is_user_workspace_admin_or_data_admin(&user, &organization_id).await { Ok(true) => (), @@ -80,7 +84,10 @@ async fn post_permission_group_handler( request: PostPermissionGroupRequest, ) -> Result { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let permission_group = PermissionGroup { id: Uuid::new_v4(), diff --git a/api/server/src/routes/rest/routes/permission_groups/put_permission_group.rs b/api/server/src/routes/rest/routes/permission_groups/put_permission_group.rs index 8cac6f5e0..aed15ab4c 100644 --- a/api/server/src/routes/rest/routes/permission_groups/put_permission_group.rs +++ b/api/server/src/routes/rest/routes/permission_groups/put_permission_group.rs @@ -10,7 +10,7 @@ use database::pool::get_pg_pool; use database::schema::permission_groups; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Deserialize, Clone)] @@ -39,7 +39,10 @@ async fn put_permission_group_handler( user: AuthenticatedUser, request: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; let now = Utc::now(); // Check if user is workspace admin or data admin diff --git a/api/server/src/routes/rest/routes/users/assets/list_attributes.rs b/api/server/src/routes/rest/routes/users/assets/list_attributes.rs index 5a4956813..bd9405673 100644 --- a/api/server/src/routes/rest/routes/users/assets/list_attributes.rs +++ b/api/server/src/routes/rest/routes/users/assets/list_attributes.rs @@ -12,7 +12,7 @@ use database::pool::get_pg_pool; use database::schema::{users, users_to_organizations}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -43,7 +43,16 @@ pub async fn list_attributes( async fn list_attributes_handler(user: AuthenticatedUser, user_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/users/assets/list_dataset_groups.rs b/api/server/src/routes/rest/routes/users/assets/list_dataset_groups.rs index a2a0851cd..675427018 100644 --- a/api/server/src/routes/rest/routes/users/assets/list_dataset_groups.rs +++ b/api/server/src/routes/rest/routes/users/assets/list_dataset_groups.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{dataset_groups, dataset_groups_permissions, dataset_permissions}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -42,7 +42,16 @@ pub async fn list_dataset_groups( async fn list_dataset_groups_handler(user: AuthenticatedUser, user_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!("User is not authorized to list dataset groups")); diff --git a/api/server/src/routes/rest/routes/users/assets/list_datasets.rs b/api/server/src/routes/rest/routes/users/assets/list_datasets.rs index b965b7404..74b11eed1 100644 --- a/api/server/src/routes/rest/routes/users/assets/list_datasets.rs +++ b/api/server/src/routes/rest/routes/users/assets/list_datasets.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{dataset_permissions, datasets}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -38,7 +38,16 @@ pub async fn list_datasets( async fn list_datasets_handler(user: AuthenticatedUser, user_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!("User is not authorized to list datasets")); diff --git a/api/server/src/routes/rest/routes/users/assets/list_permission_groups.rs b/api/server/src/routes/rest/routes/users/assets/list_permission_groups.rs index b880ebec8..b03eb2871 100644 --- a/api/server/src/routes/rest/routes/users/assets/list_permission_groups.rs +++ b/api/server/src/routes/rest/routes/users/assets/list_permission_groups.rs @@ -14,7 +14,7 @@ use database::schema::{ }; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -45,7 +45,10 @@ pub async fn list_permission_groups( async fn list_permission_groups_handler(user: AuthenticatedUser, user_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user.id).await?; + let organization_id = match get_user_organization_id(&user.id).await? { + Some(organization_id) => organization_id, + None => return Err(anyhow::anyhow!("User does not belong to any organization")), + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/users/assets/list_teams.rs b/api/server/src/routes/rest/routes/users/assets/list_teams.rs index 6913f16ae..71150abac 100644 --- a/api/server/src/routes/rest/routes/users/assets/list_teams.rs +++ b/api/server/src/routes/rest/routes/users/assets/list_teams.rs @@ -11,7 +11,7 @@ use database::pool::get_pg_pool; use database::schema::{teams, teams_to_users}; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize)] @@ -47,7 +47,16 @@ pub async fn list_teams( async fn list_teams_handler(user: AuthenticatedUser, user_id: Uuid) -> Result> { let mut conn = get_pg_pool().get().await?; - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!("User is not authorized to list teams")); diff --git a/api/server/src/routes/rest/routes/users/assets/put_dataset_groups.rs b/api/server/src/routes/rest/routes/users/assets/put_dataset_groups.rs index a419d2cca..218803ccd 100644 --- a/api/server/src/routes/rest/routes/users/assets/put_dataset_groups.rs +++ b/api/server/src/routes/rest/routes/users/assets/put_dataset_groups.rs @@ -13,7 +13,7 @@ use database::models::DatasetGroupPermission; use database::schema::dataset_groups_permissions; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -44,7 +44,16 @@ async fn put_dataset_groups_handler( user_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/users/assets/put_datasets.rs b/api/server/src/routes/rest/routes/users/assets/put_datasets.rs index 6f361c879..23830f1a6 100644 --- a/api/server/src/routes/rest/routes/users/assets/put_datasets.rs +++ b/api/server/src/routes/rest/routes/users/assets/put_datasets.rs @@ -13,7 +13,7 @@ use database::models::DatasetPermission; use database::schema::dataset_permissions; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -44,7 +44,16 @@ async fn put_datasets_handler( user_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!("User is not authorized to assign datasets")); diff --git a/api/server/src/routes/rest/routes/users/assets/put_permission_groups.rs b/api/server/src/routes/rest/routes/users/assets/put_permission_groups.rs index 0e002fbab..4a71a76b7 100644 --- a/api/server/src/routes/rest/routes/users/assets/put_permission_groups.rs +++ b/api/server/src/routes/rest/routes/users/assets/put_permission_groups.rs @@ -14,7 +14,7 @@ use database::models::PermissionGroupToIdentity; use database::schema::permission_groups_to_identities; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize)] @@ -45,7 +45,16 @@ async fn put_permission_groups_handler( user_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!( diff --git a/api/server/src/routes/rest/routes/users/assets/put_teams.rs b/api/server/src/routes/rest/routes/users/assets/put_teams.rs index 86e8c0582..dd1a59c6c 100644 --- a/api/server/src/routes/rest/routes/users/assets/put_teams.rs +++ b/api/server/src/routes/rest/routes/users/assets/put_teams.rs @@ -15,7 +15,7 @@ use database::models::TeamToUser; use database::schema::teams_to_users; use crate::routes::rest::ApiResponse; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use middleware::AuthenticatedUser; #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -51,7 +51,16 @@ async fn put_teams_handler( user_id: Uuid, assignments: Vec, ) -> Result<()> { - let organization_id = get_user_organization_id(&user_id).await?; + let organization_id = match get_user_organization_id(&user_id).await { + Ok(Some(organization_id)) => organization_id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } + Err(e) => { + tracing::error!("Error getting user organization id: {:?}", e); + return Err(anyhow::anyhow!("Error getting user organization id")); + } + }; if !is_user_workspace_admin_or_data_admin(&user, &organization_id).await? { return Err(anyhow::anyhow!("User is not authorized to list teams")); diff --git a/api/server/src/routes/rest/routes/users/update_user.rs b/api/server/src/routes/rest/routes/users/update_user.rs index 9d3ad2abb..48ad8be2a 100644 --- a/api/server/src/routes/rest/routes/users/update_user.rs +++ b/api/server/src/routes/rest/routes/users/update_user.rs @@ -8,7 +8,7 @@ use database::{enums::UserOrganizationRole, pool::get_pg_pool}; use crate::routes::rest::ApiResponse; use crate::utils::clients::sentry_utils::send_sentry_error; use crate::utils::security::checks::is_user_workspace_admin_or_data_admin; -use crate::utils::user::user_info::get_user_organization_id; +use database::organization::get_user_organization_id; use axum::http::StatusCode; use diesel::{update, ExpressionMethods}; use diesel_async::RunQueryDsl; @@ -64,7 +64,10 @@ pub async fn update_user_handler( }; let user_organization_id = match get_user_organization_id(&user_id).await { - Ok(id) => id, + Ok(Some(id)) => id, + Ok(None) => { + return Err(anyhow::anyhow!("User does not belong to any organization")); + } Err(e) => { return Err(anyhow::anyhow!( "Error getting user organization id: {:?}", diff --git a/api/server/src/utils/mod.rs b/api/server/src/utils/mod.rs index 1cf68a0f2..7ba03c04e 100644 --- a/api/server/src/utils/mod.rs +++ b/api/server/src/utils/mod.rs @@ -2,13 +2,10 @@ pub mod charting; pub mod clients; pub mod security; pub mod serde_helpers; -pub mod sharing; pub mod stored_values; -pub mod user; pub mod validation; pub use agents::*; pub use security::*; pub use stored_values::*; -pub use user::*; pub use validation::*; diff --git a/api/server/src/utils/search_engine/mod.rs b/api/server/src/utils/search_engine/mod.rs deleted file mode 100644 index cdef6776b..000000000 --- a/api/server/src/utils/search_engine/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod search_engine; \ No newline at end of file diff --git a/api/server/src/utils/search_engine/search_engine.rs b/api/server/src/utils/search_engine/search_engine.rs deleted file mode 100644 index 88af0b2bf..000000000 --- a/api/server/src/utils/search_engine/search_engine.rs +++ /dev/null @@ -1,291 +0,0 @@ -use sqlx::Row; -use tokio_stream::StreamExt; - -use anyhow::{anyhow, Result}; -use chrono::{DateTime, Utc}; -use serde::Serialize; -use uuid::Uuid; - -use database::pool::get_sqlx_pool; - -#[derive(Serialize, Debug)] -pub struct MessageSearchResult { - pub id: Uuid, - #[serde(rename = "name")] - pub title: String, - pub summary_question: String, - pub updated_at: DateTime, - pub highlights: Vec, - pub score: f64, - #[serde(rename = "type")] - pub type_: SearchObjectType, -} - -#[derive(Serialize, Debug)] -pub struct GenericSearchResult { - pub id: Uuid, - pub name: String, - pub updated_at: DateTime, - pub highlights: Vec, - pub score: f64, - #[serde(rename = "type")] - pub type_: SearchObjectType, -} - -#[derive(Serialize, Debug)] -#[serde(untagged)] -pub enum SearchObject { - Message(MessageSearchResult), - Collection(GenericSearchResult), - Dashboard(GenericSearchResult), - DataSource(GenericSearchResult), - Dataset(GenericSearchResult), - PermissionGroup(GenericSearchResult), - Team(GenericSearchResult), - Term(GenericSearchResult), -} - -impl SearchObject { - pub fn updated_at(&self) -> DateTime { - match self { - SearchObject::Message(m) => m.updated_at, - SearchObject::Collection(c) => c.updated_at, - SearchObject::Dashboard(d) => d.updated_at, - SearchObject::DataSource(ds) => ds.updated_at, - SearchObject::Dataset(d) => d.updated_at, - SearchObject::PermissionGroup(pg) => pg.updated_at, - SearchObject::Team(t) => t.updated_at, - SearchObject::Term(t) => t.updated_at, - } - } - - pub fn score(&self) -> f64 { - match self { - SearchObject::Message(m) => m.score, - SearchObject::Collection(c) => c.score, - SearchObject::Dashboard(d) => d.score, - SearchObject::DataSource(ds) => ds.score, - SearchObject::Dataset(d) => d.score, - SearchObject::PermissionGroup(pg) => pg.score, - SearchObject::Team(t) => t.score, - SearchObject::Term(t) => t.score, - } - } -} - -#[derive(Serialize, Debug)] -#[serde(rename_all = "snake_case")] -pub enum SearchObjectType { - Thread, - Collection, - Dashboard, - DataSource, - Dataset, - PermissionGroup, - Team, - Term, -} - -impl ToString for SearchObjectType { - fn to_string(&self) -> String { - match self { - SearchObjectType::Thread => "thread".to_string(), - SearchObjectType::Collection => "collection".to_string(), - SearchObjectType::Dashboard => "dashboard".to_string(), - SearchObjectType::DataSource => "data_source".to_string(), - SearchObjectType::Dataset => "dataset".to_string(), - SearchObjectType::PermissionGroup => "permission_group".to_string(), - SearchObjectType::Team => "team".to_string(), - SearchObjectType::Term => "term".to_string(), - } - } -} - -pub struct SearchOptions { - pub num_results: i64, - pub asset_types: Vec, -} - -impl Default for SearchOptions { - fn default() -> Self { - SearchOptions { - num_results: 10, - asset_types: vec![], - } - } -} - -impl SearchOptions { - pub fn new() -> Self { - Self::default() - } - - pub fn with_custom_options(num_results: i64, asset_types: Vec) -> Self { - SearchOptions { - num_results, - asset_types, - } - } - - pub fn asset_types_to_string(&self) -> String { - self.asset_types - .iter() - .map(|t| format!("'{}'", t.to_string())) - .collect::>() - .join(",") - } -} - -// TODO: Will need to implement search for shared assets via team. Likely will just fetch user teams or get them from a cache. -pub async fn search_engine( - user_id: Uuid, - organization_id: Uuid, - query_text: String, - options: SearchOptions, -) -> Result> { - let mut conn = get_sqlx_pool().acquire().await?; - - let search_terms: Vec = query_text - .split_whitespace() - .map(|term| sanitize_search_term(term.to_lowercase())) - .collect(); - - let query = format!( - r#" - SELECT DISTINCT ON (asset_search.content, asset_search.asset_type) - asset_search.asset_id, - asset_search.content, - asset_search.updated_at, - asset_search.asset_type, - pgroonga_score(asset_search.tableoid, asset_search.ctid) AS rank - FROM - asset_search - INNER JOIN - asset_permissions - ON - asset_search.asset_id = asset_permissions.asset_id - WHERE - asset_search.asset_type IN ({}) - AND asset_search.content &@~ '{}' - AND (asset_permissions.identity_id = '{}' OR asset_permissions.identity_id = '{}') - AND asset_permissions.deleted_at IS NULL - AND asset_search.deleted_at IS NULL - ORDER BY asset_search.content, asset_search.asset_type, rank DESC - LIMIT {}; - "#, - options.asset_types_to_string(), - search_terms - .iter() - .map(|term| term.replace('\'', "''")) - .collect::>() - .join(" OR "), - user_id, - organization_id, - options.num_results - ); - - let mut results = sqlx::raw_sql(&query).fetch(&mut *conn); - let mut results_vec = Vec::new(); - while let Some(row) = results.try_next().await? { - let content: String = match row.try_get("content") { - Ok(content) => content, - Err(e) => return Err(anyhow!("Error getting content: {:?}", e)), - }; - - // Skip empty content - if content.trim().is_empty() { - continue; - } - - let id: Uuid = match row.try_get("asset_id") { - Ok(id) => id, - Err(e) => return Err(anyhow!("Error getting asset_id: {:?}", e)), - }; - let updated_at: DateTime = match row.try_get("updated_at") { - Ok(updated_at) => updated_at, - Err(e) => return Err(anyhow!("Error getting updated_at: {:?}", e)), - }; - let score: f64 = match row.try_get("rank") { - Ok(score) => score, - Err(e) => return Err(anyhow!("Error getting rank: {:?}", e)), - }; - - let asset_type: SearchObjectType = match row.try_get("asset_type") { - Ok(asset_type) => match asset_type { - "thread" => SearchObjectType::Thread, - "collection" => SearchObjectType::Collection, - "dashboard" => SearchObjectType::Dashboard, - "data_source" => SearchObjectType::DataSource, - "dataset" => SearchObjectType::Dataset, - "permission_group" => SearchObjectType::PermissionGroup, - "team" => SearchObjectType::Team, - "term" => SearchObjectType::Term, - _ => return Err(anyhow!("Invalid asset type: {:?}", asset_type)), - }, - Err(e) => return Err(anyhow!("Error getting asset_type: {:?}", e)), - }; - - let highlights = find_highlights(&content, &search_terms); - - results_vec.push(SearchObject::Message(MessageSearchResult { - id, - title: content.clone(), - updated_at, - summary_question: content, - highlights, - score, - type_: asset_type, - })); - } - let results = results_vec; - - Ok(results) -} - -fn find_highlights(content: &str, search_terms: &[String]) -> Vec { - let content_lower = content.to_lowercase(); - let mut highlights = Vec::new(); - - for term in search_terms { - if let Some(pos) = content_lower.find(term) { - // Just grab the exact matching portion from the original content - highlights.push(content[pos..pos + term.len()].to_string()); - } - } - - highlights -} - -fn sanitize_search_term(term: String) -> String { - // First pass: only allow alphanumeric, spaces, and basic punctuation - let filtered = term - .chars() - .filter(|c| { - c.is_alphanumeric() - || c.is_whitespace() - || matches!(c, '-' | '_' | '.' | ',' | '@' | '#') - }) - .collect::(); - - // Second pass: escape special PostgreSQL operators and wildcards - let escaped = filtered - .replace('\\', "\\\\") // Escape backslashes first - .replace('%', "\\%") // Escape LIKE wildcards - .replace('_', "\\_") - .replace('*', "\\*") // Escape full-text search wildcards - .replace(':', "\\:") - .replace('&', "\\&") - .replace('|', "\\|") - .replace('!', "\\!") - .replace('(', "\\(") // Escape parentheses - .replace(')', "\\)"); - - // Third pass: prevent SQL comments - let no_comments = escaped - .replace("--", "") - .replace("/*", "") - .replace("*/", ""); - - // Fourth pass: limit length to prevent buffer overflow attacks - no_comments.chars().take(100).collect() -} diff --git a/api/server/src/utils/sharing/asset_sharing.rs b/api/server/src/utils/sharing/asset_sharing.rs deleted file mode 100644 index 84ff6f3a6..000000000 --- a/api/server/src/utils/sharing/asset_sharing.rs +++ /dev/null @@ -1,1163 +0,0 @@ -use anyhow::{anyhow, Result}; -use chrono::{DateTime, Utc}; -use diesel::{ - dsl::{count, sql}, - insert_into, - sql_types::Bool, - update, - upsert::excluded, - ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, -}; -use diesel_async::RunQueryDsl; -use serde_json::json; -use std::{ - collections::{HashMap, HashSet}, - sync::Arc, -}; - -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -use crate::utils::clients::{ - email::resend::{send_email, CollectionInvite, DashboardInvite, EmailType, ThreadInvite}, - sentry_utils::send_sentry_error, -}; -use database::{ - enums::{AssetPermissionRole, AssetType, IdentityType}, - models::{AssetPermission, CollectionToAsset, User}, - pool::get_pg_pool, - schema::{ - asset_permissions, collections, collections_to_assets, dashboards, messages_deprecated, - organizations, teams, teams_to_users, threads_deprecated, user_favorites, users, - }, -}; -use middleware::AuthenticatedUser; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ShareWithTeamsReqObject { - team_id: Uuid, - role: AssetPermissionRole, -} - -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] -pub struct ShareWithUsersReqObject { - user_email: String, - role: AssetPermissionRole, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TeamPermissions { - pub id: Uuid, - pub name: Option, - pub role: AssetPermissionRole, - pub user_permissions: Vec, -} - -#[derive(Debug)] -pub struct AssetSharingInfo { - pub individual_permissions: Option>, - pub team_permissions: Option>, - pub organization_permissions: bool, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct IndividualPermission { - pub id: Uuid, - pub name: Option, - pub email: String, - pub role: AssetPermissionRole, -} - -pub async fn update_asset_permissions( - user: Arc, - asset_id: Arc, - asset_type: AssetType, - team_permissions: Option>, - user_permissions: Option>, - remove_teams: Option>, - remove_users: Option>, -) -> Result<()> { - let user_id = Arc::new(user.id); - let team_permissions_handle = if let Some(team_permissions) = team_permissions { - let asset_id = Arc::clone(&asset_id); - let user_id = Arc::clone(&user_id); - Some(tokio::spawn(async move { - grant_team_access_to_asset(&team_permissions, asset_id, asset_type, user_id).await - })) - } else { - None - }; - - let user_permissions_handle = if let Some(user_permissions) = user_permissions { - let asset_id = Arc::clone(&asset_id); - let user = Arc::clone(&user); - Some(tokio::spawn(async move { - grant_user_access_to_asset(&user_permissions, asset_id, asset_type, user).await - })) - } else { - None - }; - - let remove_teams_handle = if let Some(remove_teams) = remove_teams { - let asset_id = Arc::clone(&asset_id); - let user_id = Arc::clone(&user_id); - Some(tokio::spawn(async move { - remove_team_access_to_asset(&remove_teams, asset_id, asset_type, user_id).await - })) - } else { - None - }; - - let remove_users_handle = if let Some(remove_users) = remove_users { - let asset_id = Arc::clone(&asset_id); - let user_id = Arc::clone(&user_id); - Some(tokio::spawn(async move { - remove_user_access_to_asset(&remove_users, asset_id, asset_type, user_id).await - })) - } else { - None - }; - - if let Some(team_permissions_handle) = team_permissions_handle { - match team_permissions_handle.await { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error granting team access to collection: {}", e)); - } - } - }; - - if let Some(user_permissions_handle) = user_permissions_handle { - match user_permissions_handle.await { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error granting user access to collection: {}", e)); - } - } - }; - - if let Some(remove_teams_handle) = remove_teams_handle { - match remove_teams_handle.await { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error removing team access from collection: {}", e)); - } - } - }; - - if let Some(remove_users_handle) = remove_users_handle { - match remove_users_handle.await { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error removing user access from collection: {}", e)); - } - } - }; - - Ok(()) -} - -async fn grant_team_access_to_asset( - team_permissions: &Vec, - asset_id: Arc, - asset_type: AssetType, - user_id: Arc, -) -> Result<()> { - let mut asset_permissions = Vec::new(); - - for team_permission in team_permissions { - let asset_permission = AssetPermission { - identity_id: team_permission.team_id, - identity_type: IdentityType::Team, - asset_id: *asset_id, - asset_type, - role: team_permission.role, - created_at: chrono::Utc::now(), - updated_at: chrono::Utc::now(), - deleted_at: None, - created_by: *user_id, - updated_by: *user_id, - }; - - asset_permissions.push(asset_permission); - } - - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => return Err(anyhow!("Error getting pg connection: {}", e)), - }; - - match insert_into(asset_permissions::table) - .values(asset_permissions) - .on_conflict(( - asset_permissions::asset_id, - asset_permissions::identity_id, - asset_permissions::identity_type, - asset_permissions::asset_type, - )) - .do_update() - .set(( - asset_permissions::role.eq(excluded(asset_permissions::role)), - asset_permissions::updated_at.eq(chrono::Utc::now()), - asset_permissions::updated_by.eq(user_id.as_ref()), - asset_permissions::deleted_at.eq(None::>), - )) - .execute(&mut conn) - .await - { - Ok(_) => (), - Err(e) => { - return Err(anyhow!( - "Unable to insert or update asset permissions: {}", - e - )) - } - }; - - Ok(()) -} - -async fn remove_team_access_to_asset( - team_ids: &Vec, - asset_id: Arc, - asset_type: AssetType, - user_id: Arc, -) -> Result<()> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => return Err(anyhow!("Error getting pg connection: {}", e)), - }; - - let team_ids = match update(asset_permissions::table) - .filter(asset_permissions::identity_id.eq_any(team_ids)) - .filter(asset_permissions::asset_id.eq(asset_id.as_ref())) - .filter(asset_permissions::identity_type.eq(IdentityType::Team)) - .filter(asset_permissions::asset_type.eq(asset_type)) - .set(( - asset_permissions::deleted_at.eq(chrono::Utc::now()), - asset_permissions::updated_by.eq(user_id.as_ref()), - )) - .returning(asset_permissions::identity_id) - .get_results(&mut conn) - .await - { - Ok(ids) => ids, - Err(e) => { - return Err(anyhow!( - "Unable to insert or update asset permissions: {}", - e - )) - } - }; - - tokio::spawn(async move { - match remove_from_users_on_teams_favorites(asset_id, asset_type, team_ids).await { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error removing asset from user favorites: {}", e)); - } - }; - - Ok(()) - }); - - Ok(()) -} - -async fn remove_from_users_on_teams_favorites( - asset_id: Arc, - asset_type: AssetType, - team_ids: Vec, -) -> Result<()> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => return Err(anyhow!("Error getting pg connection: {}", e)), - }; - - let user_ids = match teams_to_users::table - .filter(teams_to_users::team_id.eq_any(team_ids)) - .select(teams_to_users::user_id) - .load::(&mut conn) - .await - { - Ok(ids) => ids, - Err(e) => return Err(anyhow!("Error getting user IDs: {}", e)), - }; - - match update(user_favorites::table) - .filter(user_favorites::asset_id.eq(asset_id.as_ref())) - .filter(user_favorites::asset_type.eq(asset_type)) - .filter(user_favorites::user_id.eq_any(user_ids)) - .set(user_favorites::deleted_at.eq(chrono::Utc::now())) - .execute(&mut conn) - .await - { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error removing asset from user favorites: {}", e)); - } - }; - - Ok(()) -} - -async fn remove_user_access_to_asset( - user_ids: &Vec, - asset_id: Arc, - asset_type: AssetType, - user_id: Arc, -) -> Result<()> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - tracing::error!("Error getting pg connection: {}", e); - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let updated_ids: Vec = match update(asset_permissions::table) - .filter(asset_permissions::identity_id.eq_any(user_ids)) - .filter(asset_permissions::asset_id.eq(asset_id.as_ref())) - .filter(asset_permissions::identity_type.eq(IdentityType::User)) - .filter(asset_permissions::asset_type.eq(asset_type)) - .set(( - asset_permissions::deleted_at.eq(chrono::Utc::now()), - asset_permissions::updated_by.eq(user_id.as_ref()), - )) - .returning(asset_permissions::identity_id) - .get_results(&mut conn) - .await - { - Ok(ids) => ids, - Err(e) => { - return Err(anyhow!( - "Unable to insert or update asset permissions: {}", - e - )) - } - }; - - tokio::spawn(async move { - match remove_from_user_favorites(asset_id, asset_type, updated_ids).await { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error removing asset from user favorites: {}", e)); - } - } - - Ok(()) - }); - - Ok(()) -} - -async fn remove_from_user_favorites( - asset_id: Arc, - asset_type: AssetType, - user_ids: Vec, -) -> Result<()> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => return Err(anyhow!("Error getting pg connection: {}", e)), - }; - - match update(user_favorites::table) - .filter(user_favorites::asset_id.eq(asset_id.as_ref())) - .filter(user_favorites::asset_type.eq(asset_type)) - .filter(user_favorites::user_id.eq_any(user_ids)) - .set(user_favorites::deleted_at.eq(chrono::Utc::now())) - .execute(&mut conn) - .await - { - Ok(_) => Ok(()), - Err(e) => Err(anyhow!("Error removing asset from user favorites: {}", e)), - } -} - -async fn grant_user_access_to_asset( - user_permissions: &Vec, - asset_id: Arc, - asset_type: AssetType, - user: Arc, -) -> Result<()> { - let mut asset_permissions = Vec::new(); - - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let user_records: Vec<(Uuid, String, AssetPermissionRole)> = match users::table - .filter( - users::email.eq_any( - user_permissions - .iter() - .map(|u| &u.user_email) - .collect::>(), - ), - ) - .select((users::id, users::email)) - .load::<(Uuid, String)>(&mut conn) - .await - { - Ok(user_ids) => user_ids - .into_iter() - .map(|(id, email)| { - let role = user_permissions - .iter() - .find(|u| u.user_email == email) - .map(|u| u.role) - .unwrap_or(AssetPermissionRole::CanView); - (id, email, role) - }) - .collect(), - Err(e) => { - tracing::error!("Error getting user IDs: {}", e); - return Err(anyhow!("Error getting user IDs: {}", e)); - } - }; - - let existing_users: HashSet = user_records - .iter() - .map(|(_, email, _)| email.clone()) - .collect(); - let non_existing_users: HashSet = user_permissions - .iter() - .filter(|u| !existing_users.contains(&u.user_email)) - .cloned() - .collect(); - - for (user_id, _, role) in &user_records { - let asset_permission = AssetPermission { - identity_id: *user_id, - identity_type: IdentityType::User, - asset_id: *asset_id, - asset_type, - role: *role, - created_at: chrono::Utc::now(), - updated_at: chrono::Utc::now(), - deleted_at: None, - created_by: user.id.clone(), - updated_by: user.id.clone(), - }; - - asset_permissions.push(asset_permission); - } - - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - tracing::error!("Error getting pg connection: {}", e); - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let updated_records = match insert_into(asset_permissions::table) - .values(&asset_permissions) - .on_conflict(( - asset_permissions::asset_id, - asset_permissions::identity_id, - asset_permissions::identity_type, - asset_permissions::asset_type, - )) - .do_update() - .set(( - asset_permissions::role.eq(excluded(asset_permissions::role)), - asset_permissions::updated_at.eq(chrono::Utc::now()), - asset_permissions::updated_by.eq(user.id.clone()), - asset_permissions::deleted_at.eq(None::>), - )) - .returning(( - asset_permissions::identity_id, - asset_permissions::role, - sql::("(xmax = 0) as inserted"), - )) - .get_results::<(Uuid, AssetPermissionRole, bool)>(&mut conn) - .await - { - Ok(records) => records, - Err(e) => { - tracing::error!("Unable to insert or update asset permissions: {:?}", e); - let err = anyhow!("Unable to insert or update asset permissions: {}", e); - send_sentry_error(&e.to_string(), None); - return Err(err); - } - }; - - let updated_records: Vec<(Uuid, AssetPermissionRole)> = updated_records - .into_iter() - .filter(|(_, _, inserted)| !inserted) - .map(|(id, role, _)| (id, role)) - .collect(); - - // Create a HashSet of updated user IDs - let updated_user_ids: HashSet = updated_records.iter().map(|(id, _)| *id).collect(); - - // Filter out existing_users whose IDs are in updated_records - let existing_users: HashSet = existing_users - .into_iter() - .filter(|email| { - user_records - .iter() - .find(|(id, user_email, _)| user_email == email && !updated_user_ids.contains(id)) - .is_some() - }) - .collect(); - - // Now `updated_records` contains only the records that were updated - asset_notification_and_invites( - non_existing_users, - existing_users, - asset_id, - asset_type, - user, - ) - .await; - - Ok(()) -} - -async fn asset_notification_and_invites( - non_existing_users: HashSet, - existing_users: HashSet, - asset_id: Arc, - asset_type: AssetType, - user: Arc, -) -> () { - let asset_name = match get_asset_name(asset_id.clone(), asset_type).await { - Ok(name) => name, - Err(e) => { - tracing::error!("Error getting asset name: {}", e); - return; - } - }; - - if !non_existing_users.is_empty() { - let asset_name = asset_name.clone(); - let inviter_name = user.name.clone().unwrap_or(user.email.clone()); - let user_id = user.id.clone(); - let asset_id = asset_id.clone(); - let new_users = match create_new_users_and_add_permissions( - non_existing_users, - &asset_id, - asset_type, - user_id, - ) - .await - { - Ok(new_users) => new_users, - Err(e) => { - tracing::error!("Error creating new users: {}", e); - return; - } - }; - - tokio::spawn(async move { - let email_type = - create_invitation_email_type(inviter_name, asset_name, *asset_id, asset_type, true); - - match send_email(new_users, email_type).await { - Ok(_) => {} - Err(e) => { - tracing::error!("Error sending email: {}", e); - send_sentry_error(&e.to_string(), None); - } - } - }); - }; - - if !existing_users.is_empty() { - let email_type = create_invitation_email_type( - user.name.clone().unwrap_or(user.email.clone()), - asset_name, - *asset_id, - asset_type, - false, - ); - tokio::spawn(async move { - match send_email(existing_users, email_type).await { - Ok(_) => {} - Err(e) => { - tracing::error!("Error sending email: {}", e); - send_sentry_error(&e.to_string(), None); - } - } - }); - }; -} - -fn create_invitation_email_type( - inviter_name: String, - asset_name: String, - asset_id: Uuid, - asset_type: AssetType, - new_user: bool, -) -> EmailType { - let email_type = match asset_type { - AssetType::Collection => EmailType::CollectionInvite(CollectionInvite { - inviter_name, - new_user, - collection_name: asset_name, - collection_id: asset_id, - }), - AssetType::Dashboard => EmailType::DashboardInvite(DashboardInvite { - inviter_name, - new_user, - dashboard_name: asset_name, - dashboard_id: asset_id, - }), - AssetType::Thread => EmailType::ThreadInvite(ThreadInvite { - inviter_name, - new_user, - thread_name: asset_name, - thread_id: asset_id, - }), - _ => EmailType::ThreadInvite(ThreadInvite { - inviter_name, - new_user, - thread_name: asset_name, - thread_id: asset_id, - }), - }; - - email_type -} - -async fn get_asset_name(asset_id: Arc, asset_type: AssetType) -> Result { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let name = match asset_type { - AssetType::Collection => { - match collections::table - .filter(collections::id.eq(asset_id.as_ref())) - .select(collections::name) - .first::(&mut conn) - .await - { - Ok(name) => name, - Err(e) => { - tracing::error!("Error getting asset name: {}", e); - return Err(anyhow!("Error getting asset name: {}", e)); - } - } - } - AssetType::Dashboard => { - match dashboards::table - .filter(dashboards::id.eq(asset_id.as_ref())) - .select(dashboards::name) - .first::(&mut conn) - .await - { - Ok(name) => name, - Err(e) => { - tracing::error!("Error getting asset name: {}", e); - return Err(anyhow!("Error getting asset name: {}", e)); - } - } - } - AssetType::Thread => { - match messages_deprecated::table - .inner_join( - threads_deprecated::table - .on(messages_deprecated::thread_id.eq(threads_deprecated::id)), - ) - .filter(threads_deprecated::id.eq(asset_id.as_ref())) - .select(messages_deprecated::title.nullable()) - .order(messages_deprecated::created_at.desc()) - .first::>(&mut conn) - .await - { - Ok(Some(name)) => name, - Ok(None) => "a thread".to_string(), - Err(e) => { - tracing::error!("Error getting asset name: {}", e); - return Err(anyhow!("Error getting asset name: {}", e)); - } - } - } - _ => { - return Err(anyhow!("Public access is not supported for chats yet")); - } - }; - - Ok(name) -} - -async fn create_new_users_and_add_permissions( - new_users: HashSet, - collection_id: &Uuid, - asset_type: AssetType, - user_id: Uuid, -) -> Result> { - let mut new_users_records = Vec::new(); - let mut new_permissions_records = Vec::new(); - - for new_user in new_users { - let new_user_id = Uuid::new_v4(); - - let user = User { - id: new_user_id, - email: new_user.user_email.clone(), - name: None, - attributes: json!({"user_id": new_user_id.to_string(), "user_email": new_user.user_email}), - created_at: chrono::Utc::now(), - updated_at: chrono::Utc::now(), - config: json!({}), - avatar_url: None, - }; - - let permission = AssetPermission { - identity_id: user.id, - identity_type: IdentityType::User, - asset_id: *collection_id, - asset_type, - role: new_user.role, - created_at: chrono::Utc::now(), - updated_at: chrono::Utc::now(), - deleted_at: None, - created_by: user_id, - updated_by: user_id, - }; - - new_users_records.push(user); - new_permissions_records.push(permission); - } - - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - match insert_into(users::table) - .values(&new_users_records) - .execute(&mut conn) - .await - { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error inserting new users: {}", e)); - } - }; - - match insert_into(asset_permissions::table) - .values(new_permissions_records) - .on_conflict(( - asset_permissions::identity_id, - asset_permissions::identity_type, - asset_permissions::asset_id, - asset_permissions::asset_type, - )) - .do_update() - .set(( - asset_permissions::role.eq(excluded(asset_permissions::role)), - asset_permissions::updated_at.eq(chrono::Utc::now()), - asset_permissions::updated_by.eq(user_id), - )) - .execute(&mut conn) - .await - { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error inserting new permissions: {}", e)); - } - }; - - Ok(new_users_records.iter().map(|u| u.email.clone()).collect()) -} - -pub async fn get_asset_sharing_info( - asset_id: Arc, - asset_type: AssetType, -) -> Result { - let individual_permissions_handle = { - let id = Arc::clone(&asset_id); - tokio::spawn(async move { get_individual_permissions(id, asset_type).await }) - }; - - let team_permissions_handle = { - let id = Arc::clone(&asset_id); - tokio::spawn(async move { get_team_permissions(id, asset_type).await }) - }; - - let org_permissions_handle = { - let id = Arc::clone(&asset_id); - tokio::spawn(async move { get_organization_permissions(id, asset_type).await }) - }; - - let (individual_permissions_result, team_permissions_result, org_permissions_result) = match tokio::try_join!( - individual_permissions_handle, - team_permissions_handle, - org_permissions_handle - ) { - Ok((individual_permissions, team_permissions, org_permissions)) => { - (individual_permissions, team_permissions, org_permissions) - } - Err(e) => { - return Err(anyhow!("Error getting thread sharing info: {}", e)); - } - }; - - let individual_permissions = match individual_permissions_result { - Ok(individual_permissions) => individual_permissions, - Err(e) => { - return Err(anyhow!("Error getting individual permissions: {}", e)); - } - }; - - let team_permissions = match team_permissions_result { - Ok(team_permissions) => team_permissions, - Err(e) => { - return Err(anyhow!("Error getting team permissions: {}", e)); - } - }; - - let org_permissions = match org_permissions_result { - Ok(org_permissions) => org_permissions, - Err(e) => { - return Err(anyhow!("Error getting organization permissions: {}", e)); - } - }; - - Ok(AssetSharingInfo { - individual_permissions, - team_permissions, - organization_permissions: org_permissions, - }) -} - -async fn get_individual_permissions( - asset_id: Arc, - asset_type: AssetType, -) -> Result>> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let individual_records = match asset_permissions::table - .inner_join(users::table.on(asset_permissions::identity_id.eq(users::id))) - .select(( - users::id, - users::name.nullable(), - users::email, - asset_permissions::role, - )) - .filter(asset_permissions::identity_type.eq(IdentityType::User)) - .filter(asset_permissions::asset_id.eq(asset_id.as_ref())) - .filter(asset_permissions::asset_type.eq(asset_type)) - .filter(asset_permissions::deleted_at.is_null()) - .load::<(Uuid, Option, String, AssetPermissionRole)>(&mut conn) - .await - { - Ok(individual_records) => individual_records, - Err(diesel::result::Error::NotFound) => return Ok(None), - Err(e) => { - return Err(anyhow!("Error querying individual permissions: {}", e)); - } - }; - - if individual_records.is_empty() { - return Ok(None); - } - - let individual_permissions = individual_records - .into_iter() - .map(|(id, name, email, role)| IndividualPermission { - id, - name, - email, - role, - }) - .collect(); - - Ok(Some(individual_permissions)) -} - -async fn get_team_permissions( - asset_id: Arc, - asset_type: AssetType, -) -> Result>> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let team_records = match asset_permissions::table - .inner_join( - teams_to_users::table.on(asset_permissions::identity_id.eq(teams_to_users::team_id)), - ) - .inner_join(teams::table.on(teams_to_users::team_id.eq(teams::id))) - .inner_join(users::table.on(teams_to_users::user_id.eq(users::id))) - .select(( - users::id, - users::name.nullable(), - users::email, - asset_permissions::role, - teams::name, - teams::id, - )) - .filter(asset_permissions::identity_type.eq(IdentityType::Team)) - .filter(asset_permissions::asset_id.eq(asset_id.as_ref())) - .filter(asset_permissions::asset_type.eq(asset_type)) - .filter(asset_permissions::deleted_at.is_null()) - .load::<( - Uuid, - Option, - String, - AssetPermissionRole, - String, - Uuid, - )>(&mut conn) - .await - { - Ok(team_records) => team_records, - Err(diesel::result::Error::NotFound) => return Ok(None), - Err(e) => { - return Err(anyhow!("Error querying team permissions: {}", e)); - } - }; - - let team_permissions: HashMap = team_records.into_iter().fold( - HashMap::new(), - |mut acc, (user_id, user_name, email, role, team_name, team_id)| { - acc.entry(team_id) - .or_insert_with(|| TeamPermissions { - id: team_id, - name: Some(team_name.clone()), - role, - user_permissions: Vec::new(), - }) - .user_permissions - .push(IndividualPermission { - id: user_id, - name: user_name, - email, - role, - }); - acc - }, - ); - - let team_permissions = team_permissions.into_values().collect(); - - Ok(Some(team_permissions)) -} - -async fn get_organization_permissions(asset_id: Arc, asset_type: AssetType) -> Result { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let org_has_permission = match asset_permissions::table - .inner_join(organizations::table.on(asset_permissions::identity_id.eq(organizations::id))) - .select(count(asset_permissions::identity_id)) - .filter(asset_permissions::identity_type.eq(IdentityType::Organization)) - .filter(asset_permissions::asset_id.eq(asset_id.as_ref())) - .filter(asset_permissions::asset_type.eq(asset_type)) - .filter(asset_permissions::deleted_at.is_null()) - .first::(&mut conn) - .await - { - Ok(count) => count > 0, - Err(diesel::result::Error::NotFound) => false, - Err(e) => { - return Err(anyhow!("Error querying organization permissions: {}", e)); - } - }; - - Ok(org_has_permission) -} - -#[derive(Serialize, Deserialize, Clone)] -pub struct CollectionNameAndId { - pub id: Uuid, - pub name: String, -} - -pub async fn get_asset_collections( - asset_id: Arc, - asset_type: AssetType, -) -> Result> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let collection_records = match collections::table - .inner_join( - collections_to_assets::table - .on(collections::id.eq(collections_to_assets::collection_id)), - ) - .select((collections::id, collections::name)) - .filter(collections_to_assets::asset_id.eq(asset_id.as_ref())) - .filter(collections_to_assets::asset_type.eq(asset_type)) - .filter(collections_to_assets::deleted_at.is_null()) - .filter(collections::deleted_at.is_null()) - .load::<(Uuid, String)>(&mut conn) - .await - { - Ok(collections) => collections, - Err(e) => { - return Err(anyhow!("Error querying collections: {}", e)); - } - }; - - let collections = collection_records - .into_iter() - .map(|(id, name)| CollectionNameAndId { id, name }) - .collect(); - - Ok(collections) -} - -pub async fn create_asset_collection_association( - collection_ids: Vec, - asset_id: Arc, - asset_type: AssetType, - user_id: Arc, -) -> Result<()> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let mut collections_to_assets = Vec::new(); - - for collection_id in collection_ids { - let collections_to_assets_record = CollectionToAsset { - collection_id, - asset_id: *asset_id, - asset_type, - created_at: chrono::Utc::now(), - updated_at: chrono::Utc::now(), - deleted_at: None, - created_by: *user_id, - updated_by: *user_id, - }; - - collections_to_assets.push(collections_to_assets_record); - } - - match insert_into(collections_to_assets::table) - .values(&collections_to_assets) - .on_conflict(( - collections_to_assets::collection_id, - collections_to_assets::asset_id, - collections_to_assets::asset_type, - )) - .do_update() - .set(( - collections_to_assets::updated_at.eq(chrono::Utc::now()), - collections_to_assets::updated_by.eq(*user_id), - collections_to_assets::deleted_at.eq(None::>), - )) - .execute(&mut conn) - .await - { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error inserting collection: {}", e)); - } - }; - - Ok(()) -} - -pub async fn delete_asset_collection_association( - collection_ids: Vec, - asset_id: Arc, - asset_type: AssetType, - user_id: Arc, -) -> Result<()> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - match update(collections_to_assets::table) - .filter(collections_to_assets::collection_id.eq_any(collection_ids)) - .filter(collections_to_assets::asset_id.eq(asset_id.as_ref())) - .filter(collections_to_assets::asset_type.eq(asset_type)) - .set(( - collections_to_assets::deleted_at.eq(chrono::Utc::now()), - collections_to_assets::updated_by.eq(*user_id), - )) - .execute(&mut conn) - .await - { - Ok(_) => (), - Err(e) => { - return Err(anyhow!("Error deleting collection: {}", e)); - } - }; - - Ok(()) -} - -pub async fn check_if_assets_are_shared( - asset_ids: &Vec, - asset_type: AssetType, -) -> Result> { - let mut conn = match get_pg_pool().get().await { - Ok(conn) => conn, - Err(e) => { - return Err(anyhow!("Error getting pg connection: {}", e)); - } - }; - - let asset_records = match asset_permissions::table - .select(( - asset_permissions::asset_id, - sql::("COUNT(DISTINCT identity_id) > 1 AS is_shared"), - )) - .filter(asset_permissions::asset_id.eq_any(asset_ids)) - .filter(asset_permissions::asset_type.eq(asset_type)) - .filter(asset_permissions::deleted_at.is_null()) - .group_by(asset_permissions::asset_id) - .load::<(Uuid, bool)>(&mut conn) - .await - { - Ok(asset_records) => asset_records, - Err(e) => { - tracing::error!("Unable to query asset permissions: {:?}", e); - let err = anyhow!("Error querying asset permissions: {}", e); - send_sentry_error(&e.to_string(), None); - return Err(err); - } - }; - - // For assets not in the result, add them with false (not shared) - let result: Vec<(Uuid, bool)> = asset_ids - .iter() - .map(|&id| { - asset_records - .iter() - .find(|&(aid, _)| *aid == id) - .map_or((id, false), |&(aid, shared)| (aid, shared)) - }) - .collect(); - - Ok(result) -} diff --git a/api/server/src/utils/sharing/mod.rs b/api/server/src/utils/sharing/mod.rs deleted file mode 100644 index 8af39607a..000000000 --- a/api/server/src/utils/sharing/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod asset_sharing; diff --git a/api/server/src/utils/user/mod.rs b/api/server/src/utils/user/mod.rs deleted file mode 100644 index b576e42e1..000000000 --- a/api/server/src/utils/user/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod user_info; diff --git a/api/server/src/utils/user/user_info.rs b/api/server/src/utils/user/user_info.rs deleted file mode 100644 index 3eaf9ef81..000000000 --- a/api/server/src/utils/user/user_info.rs +++ /dev/null @@ -1,55 +0,0 @@ -use anyhow::{anyhow, Result}; -use diesel::{BoolExpressionMethods, ExpressionMethods, JoinOnDsl, QueryDsl}; -use diesel_async::RunQueryDsl; -use uuid::Uuid; - -use database::{ - pool::get_pg_pool, - models::Organization, - schema::{organizations, users_to_organizations}, -}; - -pub async fn get_user_organization_id(user_id: &Uuid) -> Result { - let mut conn = get_pg_pool().get().await?; - - let organization_id = match users_to_organizations::table - .select(users_to_organizations::organization_id) - .filter(users_to_organizations::user_id.eq(user_id)) - .filter(users_to_organizations::deleted_at.is_null()) - .first::(&mut conn) - .await - { - Ok(organization_id) => organization_id, - Err(diesel::NotFound) => return Err(anyhow!("User not found")), - Err(e) => return Err(anyhow!("Error getting user organization id: {}", e)), - }; - - Ok(organization_id) -} - -pub async fn get_user_organization(user_id: &Uuid) -> Result { - let mut conn = get_pg_pool().get().await?; - - let organization = match organizations::table - .inner_join( - users_to_organizations::table.on(users_to_organizations::organization_id - .eq(organizations::id) - .and( - users_to_organizations::user_id - .eq(user_id) - .and(users_to_organizations::deleted_at.is_null()), - )), - ) - .select(organizations::all_columns) - .filter(users_to_organizations::user_id.eq(user_id)) - .filter(users_to_organizations::deleted_at.is_null()) - .first::(&mut conn) - .await - { - Ok(organization) => organization, - Err(diesel::NotFound) => return Err(anyhow!("Organization not found.")), - Err(e) => return Err(anyhow!("Error getting user organization id: {}", e)), - }; - - Ok(organization) -}