mirror of https://github.com/buster-so/buster.git
Created sharing create permissions
This commit is contained in:
parent
2058b0551f
commit
7a63b97e35
|
@ -13,6 +13,7 @@ tracing = { workspace = true }
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
diesel = { workspace = true }
|
diesel = { workspace = true }
|
||||||
diesel-async = { workspace = true }
|
diesel-async = { workspace = true }
|
||||||
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
database = { path = "../database" }
|
database = { path = "../database" }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result, anyhow};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use database::{
|
use database::{
|
||||||
enums::{AssetPermissionRole, AssetType, IdentityType},
|
enums::{AssetPermissionRole, AssetType, IdentityType},
|
||||||
|
@ -10,6 +10,9 @@ use diesel::{prelude::*, upsert::excluded};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::errors::SharingError;
|
||||||
|
use crate::types::find_user_by_email;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ShareCreationInput {
|
pub struct ShareCreationInput {
|
||||||
pub asset_id: Uuid,
|
pub asset_id: Uuid,
|
||||||
|
@ -70,6 +73,53 @@ pub async fn create_share(
|
||||||
.context("Failed to create/update asset permission")
|
.context("Failed to create/update asset permission")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates or updates an asset permission for a user identified by email
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `email` - The email address of the user to grant access to
|
||||||
|
/// * `asset_id` - The ID of the asset to share
|
||||||
|
/// * `asset_type` - The type of asset (must not be deprecated)
|
||||||
|
/// * `role` - The permission role to assign (must be Owner or FullAccess)
|
||||||
|
/// * `created_by` - The ID of the user creating the permission
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Result<AssetPermission>` - The created or updated permission record
|
||||||
|
pub async fn create_share_by_email(
|
||||||
|
email: &str,
|
||||||
|
asset_id: Uuid,
|
||||||
|
asset_type: AssetType,
|
||||||
|
role: AssetPermissionRole,
|
||||||
|
created_by: Uuid,
|
||||||
|
) -> Result<AssetPermission> {
|
||||||
|
// Validate asset type is not deprecated
|
||||||
|
if matches!(asset_type, AssetType::Dashboard | AssetType::Thread) {
|
||||||
|
return Err(anyhow!(SharingError::DeprecatedAssetType(format!("{:?}", asset_type))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate role is either Owner or FullAccess
|
||||||
|
if !matches!(role, AssetPermissionRole::Owner | AssetPermissionRole::FullAccess) {
|
||||||
|
return Err(anyhow!(SharingError::InvalidPermissionRole(format!(
|
||||||
|
"Role must be Owner or FullAccess, got {:?}",
|
||||||
|
role
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the user by email
|
||||||
|
let user = find_user_by_email(email).await?
|
||||||
|
.ok_or_else(|| anyhow!(SharingError::UserNotFound(email.to_string())))?;
|
||||||
|
|
||||||
|
// Create or update the permission
|
||||||
|
create_share(
|
||||||
|
asset_id,
|
||||||
|
asset_type,
|
||||||
|
user.id,
|
||||||
|
IdentityType::User,
|
||||||
|
role,
|
||||||
|
created_by,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates multiple sharing records in bulk
|
/// Creates multiple sharing records in bulk
|
||||||
pub async fn create_shares_bulk(
|
pub async fn create_shares_bulk(
|
||||||
shares: Vec<ShareCreationInput>,
|
shares: Vec<ShareCreationInput>,
|
||||||
|
@ -122,3 +172,47 @@ pub async fn create_shares_bulk(
|
||||||
.await
|
.await
|
||||||
.context("Failed to create/update asset permissions in bulk")
|
.context("Failed to create/update asset permissions in bulk")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::errors::SharingError;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_create_share_by_email_validates_role() {
|
||||||
|
// Test that only Owner and FullAccess roles are accepted
|
||||||
|
let result = create_share_by_email(
|
||||||
|
"test@example.com",
|
||||||
|
Uuid::new_v4(),
|
||||||
|
AssetType::Chat,
|
||||||
|
AssetPermissionRole::CanEdit,
|
||||||
|
Uuid::new_v4(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
let err = result.unwrap_err().to_string();
|
||||||
|
assert!(err.contains("Role must be Owner or FullAccess"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_create_share_by_email_validates_asset_type() {
|
||||||
|
// Test that deprecated asset types are rejected
|
||||||
|
let result = create_share_by_email(
|
||||||
|
"test@example.com",
|
||||||
|
Uuid::new_v4(),
|
||||||
|
AssetType::Dashboard, // Deprecated asset type
|
||||||
|
AssetPermissionRole::Owner,
|
||||||
|
Uuid::new_v4(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
let err = result.unwrap_err().to_string();
|
||||||
|
assert!(err.contains("Asset type"));
|
||||||
|
assert!(err.contains("is deprecated"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Additional integration tests would be needed to test the database interactions
|
||||||
|
// These would require mocking the database or using a test database
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum SharingError {
|
||||||
|
#[error("User not found: {0}")]
|
||||||
|
UserNotFound(String),
|
||||||
|
|
||||||
|
#[error("Invalid permission role: {0}")]
|
||||||
|
InvalidPermissionRole(String),
|
||||||
|
|
||||||
|
#[error("Asset type {0:?} is deprecated")]
|
||||||
|
DeprecatedAssetType(String),
|
||||||
|
|
||||||
|
#[error("Permission denied: {0}")]
|
||||||
|
PermissionDenied(String),
|
||||||
|
|
||||||
|
#[error("Database error: {0}")]
|
||||||
|
DatabaseError(#[from] diesel::result::Error),
|
||||||
|
|
||||||
|
#[error("Unknown error: {0}")]
|
||||||
|
Unknown(String),
|
||||||
|
}
|
|
@ -1,9 +1,13 @@
|
||||||
// pub mod check_asset_permission;
|
// pub mod check_asset_permission;
|
||||||
pub mod create_asset_permission;
|
pub mod create_asset_permission;
|
||||||
|
pub mod errors;
|
||||||
pub mod list_asset_permissions;
|
pub mod list_asset_permissions;
|
||||||
pub mod remove_asset_permissions;
|
pub mod remove_asset_permissions;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
// pub use check_asset_permission::check_access;
|
// pub use check_asset_permission::check_access;
|
||||||
pub use create_asset_permission::create_share;
|
pub use create_asset_permission::create_share;
|
||||||
|
pub use create_asset_permission::create_share_by_email;
|
||||||
pub use list_asset_permissions::list_shares;
|
pub use list_asset_permissions::list_shares;
|
||||||
pub use remove_asset_permissions::remove_share;
|
pub use remove_asset_permissions::remove_share;
|
||||||
|
pub use types::find_user_by_email;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use database::{
|
||||||
|
models::User,
|
||||||
|
pool::get_pg_pool,
|
||||||
|
schema::users,
|
||||||
|
};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
|
/// Finds a user by their email address
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `email` - The email address to search for
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Result<Option<User>>` - The user if found, None otherwise
|
||||||
|
pub async fn find_user_by_email(email: &str) -> Result<Option<User>> {
|
||||||
|
let mut conn = get_pg_pool().get().await?;
|
||||||
|
|
||||||
|
users::table
|
||||||
|
.filter(users::email.eq(email))
|
||||||
|
.first::<User>(&mut conn)
|
||||||
|
.await
|
||||||
|
.optional()
|
||||||
|
.context("Failed to look up user by email")
|
||||||
|
}
|
|
@ -77,17 +77,17 @@ The function should handle the following error cases:
|
||||||
- Error handling utilities
|
- Error handling utilities
|
||||||
|
|
||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
1. Enhance the `create_asset_permission.rs` file
|
1. ✅ Enhance the `create_asset_permission.rs` file
|
||||||
2. Implement the `create_share_by_email` function
|
2. ✅ Implement the `create_share_by_email` function
|
||||||
3. Add validation and error handling
|
3. ✅ Add validation and error handling
|
||||||
4. Write tests
|
4. ✅ Write tests
|
||||||
5. Update the library exports in `lib.rs`
|
5. ✅ Update the library exports in `lib.rs`
|
||||||
|
|
||||||
## Success Criteria
|
## Success Criteria
|
||||||
- Function correctly creates or updates permissions using email addresses
|
- ✅ Function correctly creates or updates permissions using email addresses
|
||||||
- Appropriate validation and error handling is implemented
|
- ✅ Appropriate validation and error handling is implemented
|
||||||
- Tests pass successfully
|
- ✅ Tests pass successfully
|
||||||
- Code is well-documented
|
- ✅ Code is well-documented
|
||||||
|
|
||||||
## Permission Requirements
|
## Permission Requirements
|
||||||
- Requires Owner or FullAccess permission to execute
|
- Requires Owner or FullAccess permission to execute
|
||||||
|
|
Loading…
Reference in New Issue