diff --git a/api/libs/handlers/Cargo.toml b/api/libs/handlers/Cargo.toml index 9fd24690b..ae7b1fcc2 100644 --- a/api/libs/handlers/Cargo.toml +++ b/api/libs/handlers/Cargo.toml @@ -30,6 +30,7 @@ agents = { path = "../agents" } litellm = { path = "../litellm" } query_engine = { path = "../query_engine" } middleware = { path = "../middleware" } +sharing = { path = "../sharing" } # Add any handler-specific dependencies here diff --git a/api/libs/sharing/src/check_access.rs b/api/libs/sharing/src/check_access.rs new file mode 100644 index 000000000..a99e772ec --- /dev/null +++ b/api/libs/sharing/src/check_access.rs @@ -0,0 +1,9 @@ +use anyhow::Result; +use diesel::prelude::*; +use diesel_async::RunQueryDsl; +use uuid::Uuid; + +/// Checks if a user has access to a resource +pub async fn check_access() -> Result<()> { + Ok(()) +} diff --git a/api/libs/sharing/src/create_share.rs b/api/libs/sharing/src/create_share.rs new file mode 100644 index 000000000..11ceec141 --- /dev/null +++ b/api/libs/sharing/src/create_share.rs @@ -0,0 +1,9 @@ +use anyhow::Result; +use diesel::prelude::*; +use diesel_async::RunQueryDsl; +use uuid::Uuid; + +/// Creates a new sharing record +pub async fn create_share() -> Result<()> { + Ok(()) +} diff --git a/api/libs/sharing/src/errors.rs b/api/libs/sharing/src/errors.rs index f955670ce..e69de29bb 100644 --- a/api/libs/sharing/src/errors.rs +++ b/api/libs/sharing/src/errors.rs @@ -1,22 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Error { - #[error("Resource not found: {0}")] - ResourceNotFound(String), - - #[error("Permission denied: {0}")] - PermissionDenied(String), - - #[error("Invalid sharing configuration: {0}")] - InvalidConfiguration(String), - - #[error("Resource already shared with user: {0}")] - AlreadyShared(String), - - #[error(transparent)] - Database(#[from] diesel::result::Error), - - #[error(transparent)] - Other(#[from] anyhow::Error), -} \ No newline at end of file diff --git a/api/libs/sharing/src/lib.rs b/api/libs/sharing/src/lib.rs index fdad05912..886f905eb 100644 --- a/api/libs/sharing/src/lib.rs +++ b/api/libs/sharing/src/lib.rs @@ -1,69 +1,9 @@ -//! Sharing Library -//! -//! This library provides functionality for managing sharing of various resources -//! such as metrics, dashboards, collections, and chats. It handles the creation, -//! verification, and management of sharing records. +pub mod check_access; +pub mod create_share; +pub mod list_shares; +pub mod remove_share; -use anyhow::Result; - -pub mod models; -pub mod utils; -mod errors; - -// Re-exports -pub use errors::Error; -pub use models::Share; -pub use utils::{create_share, check_access, remove_share, list_shares}; - -/// Represents the different types of resources that can be shared -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub enum ShareableResource { - /// A metric resource - Metric(uuid::Uuid), - /// A dashboard resource - Dashboard(uuid::Uuid), - /// A collection resource - Collection(uuid::Uuid), - /// A chat resource - Chat(uuid::Uuid), -} - -/// Represents the different levels of sharing permissions -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub enum SharePermission { - /// Read-only access - View, - /// Can modify the resource - Edit, - /// Full control over the resource - Admin, -} - -/// A trait for types that can be shared -pub trait Shareable { - /// Convert the type into a ShareableResource - fn into_shareable(&self) -> ShareableResource; -} - -#[cfg(test)] -mod tests { - use super::*; - use uuid::Uuid; - - #[test] - fn test_shareable_resource_serialization() { - let id = Uuid::new_v4(); - let resource = ShareableResource::Metric(id); - let serialized = serde_json::to_string(&resource).unwrap(); - let deserialized: ShareableResource = serde_json::from_str(&serialized).unwrap(); - assert_eq!(resource, deserialized); - } - - #[test] - fn test_share_permission_serialization() { - let permission = SharePermission::Edit; - let serialized = serde_json::to_string(&permission).unwrap(); - let deserialized: SharePermission = serde_json::from_str(&serialized).unwrap(); - assert_eq!(permission, deserialized); - } -} \ No newline at end of file +pub use check_access::check_access; +pub use create_share::create_share; +pub use list_shares::list_shares; +pub use remove_share::remove_share; diff --git a/api/libs/sharing/src/list_shares.rs b/api/libs/sharing/src/list_shares.rs new file mode 100644 index 000000000..9e1066719 --- /dev/null +++ b/api/libs/sharing/src/list_shares.rs @@ -0,0 +1,6 @@ +use anyhow::Result; + +/// Lists all shares for a resource +pub async fn list_shares() -> Result<()> { + Ok(()) +} diff --git a/api/libs/sharing/src/remove_share.rs b/api/libs/sharing/src/remove_share.rs new file mode 100644 index 000000000..d7131d468 --- /dev/null +++ b/api/libs/sharing/src/remove_share.rs @@ -0,0 +1,10 @@ +use anyhow::Result; +use uuid::Uuid; + +/// Removes a sharing record +pub async fn remove_share( + conn: &mut diesel_async::AsyncPgConnection, + shared_with: Uuid, +) -> Result<()> { + Ok(()) +} diff --git a/api/libs/sharing/src/types.rs b/api/libs/sharing/src/types.rs new file mode 100644 index 000000000..e69de29bb diff --git a/api/libs/sharing/src/utils/mod.rs b/api/libs/sharing/src/utils/mod.rs deleted file mode 100644 index 7df4decbb..000000000 --- a/api/libs/sharing/src/utils/mod.rs +++ /dev/null @@ -1,127 +0,0 @@ -use anyhow::Result; -use diesel::prelude::*; -use diesel_async::RunQueryDsl; -use uuid::Uuid; - -use crate::{ - models::Share, - ShareableResource, - SharePermission, - Error, -}; - -/// Creates a new sharing record -pub async fn create_share( - conn: &mut diesel_async::AsyncPgConnection, - resource: ShareableResource, - shared_by: Uuid, - shared_with: Uuid, - permission: SharePermission, -) -> Result { - use crate::models::sharing::dsl::*; - - // Check if sharing already exists - let existing = sharing - .filter(resource_id.eq(match &resource { - ShareableResource::Metric(id) | - ShareableResource::Dashboard(id) | - ShareableResource::Collection(id) | - ShareableResource::Chat(id) => id, - })) - .filter(shared_with.eq(shared_with)) - .first::(conn) - .await - .optional()?; - - if existing.is_some() { - return Err(Error::AlreadyShared("Resource already shared with this user".to_string()).into()); - } - - let share = Share::new(resource, shared_by, shared_with, permission, None); - diesel::insert_into(sharing) - .values(&share) - .get_result(conn) - .await - .map_err(Into::into) -} - -/// Checks if a user has access to a resource -pub async fn check_access( - conn: &mut diesel_async::AsyncPgConnection, - resource: &ShareableResource, - user_id: Uuid, - required_permission: SharePermission, -) -> Result { - use crate::models::sharing::dsl::*; - - let resource_id_val = match resource { - ShareableResource::Metric(id) | - ShareableResource::Dashboard(id) | - ShareableResource::Collection(id) | - ShareableResource::Chat(id) => *id, - }; - - let share = sharing - .filter(resource_id.eq(resource_id_val)) - .filter(shared_with.eq(user_id)) - .first::(conn) - .await - .optional()?; - - Ok(match share { - Some(share) => { - match (share.permission.as_str(), required_permission) { - (_, SharePermission::View) => true, - ("admin", _) => true, - ("edit", SharePermission::Edit) => true, - _ => false, - } - } - None => false, - }) -} - -/// Removes a sharing record -pub async fn remove_share( - conn: &mut diesel_async::AsyncPgConnection, - resource: &ShareableResource, - shared_with: Uuid, -) -> Result { - use crate::models::sharing::dsl::*; - - let resource_id_val = match resource { - ShareableResource::Metric(id) | - ShareableResource::Dashboard(id) | - ShareableResource::Collection(id) | - ShareableResource::Chat(id) => *id, - }; - - let deleted = diesel::delete(sharing) - .filter(resource_id.eq(resource_id_val)) - .filter(shared_with.eq(shared_with)) - .execute(conn) - .await?; - - Ok(deleted > 0) -} - -/// Lists all shares for a resource -pub async fn list_shares( - conn: &mut diesel_async::AsyncPgConnection, - resource: &ShareableResource, -) -> Result> { - use crate::models::sharing::dsl::*; - - let resource_id_val = match resource { - ShareableResource::Metric(id) | - ShareableResource::Dashboard(id) | - ShareableResource::Collection(id) | - ShareableResource::Chat(id) => *id, - }; - - sharing - .filter(resource_id.eq(resource_id_val)) - .load::(conn) - .await - .map_err(Into::into) -} \ No newline at end of file