sharing work

This commit is contained in:
dal 2025-03-19 14:22:05 -06:00
parent ff8a443e42
commit 709cff0483
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
5 changed files with 86 additions and 59 deletions

View File

@ -15,22 +15,19 @@ use uuid::Uuid;
/// # Arguments
/// * `metric_id` - The UUID of the metric to create sharing permissions for
/// * `user_id` - The UUID of the user making the request
/// * `emails` - List of emails to share the metric with
/// * `role` - The role to assign to the shared users
/// * `emails_and_roles` - List of tuples containing (email, role) pairs
///
/// # Returns
/// * `Result<()>` - Success if all sharing permissions were created
pub async fn create_metric_sharing_handler(
metric_id: &Uuid,
user_id: &Uuid,
emails: Vec<String>,
role: AssetPermissionRole,
emails_and_roles: Vec<(String, AssetPermissionRole)>,
) -> Result<()> {
info!(
metric_id = %metric_id,
user_id = %user_id,
emails_count = emails.len(),
role = ?role,
recipients_count = emails_and_roles.len(),
"Creating sharing permissions for metric"
);
@ -53,8 +50,8 @@ pub async fn create_metric_sharing_handler(
return Err(anyhow!("User does not have permission to share this metric"));
}
// 3. Process each email and create sharing permissions
for email in emails {
// 3. Process each email-role pair and create sharing permissions
for (email, role) in emails_and_roles {
// Validate email format
if !email.contains('@') {
return Err(anyhow!("Invalid email format: {}", email));
@ -69,7 +66,7 @@ pub async fn create_metric_sharing_handler(
*user_id,
).await {
Ok(_) => {
info!("Created sharing permission for email: {} on metric: {}", email, metric_id);
info!("Created sharing permission for email: {} with role: {:?} on metric: {}", email, role, metric_id);
},
Err(e) => {
return Err(anyhow!("Failed to create sharing for email {}: {}", email, e));
@ -89,10 +86,9 @@ mod tests {
async fn test_create_metric_sharing_invalid_email() {
let metric_id = Uuid::new_v4();
let user_id = Uuid::new_v4();
let role = AssetPermissionRole::CanView;
let emails = vec!["invalid-email-format".to_string()];
let emails_and_roles = vec![("invalid-email-format".to_string(), AssetPermissionRole::CanView)];
let result = create_metric_sharing_handler(&metric_id, &user_id, emails, role).await;
let result = create_metric_sharing_handler(&metric_id, &user_id, emails_and_roles).await;
assert!(result.is_err());
let error = result.unwrap_err().to_string();

View File

@ -1,20 +1,20 @@
use axum::{
extract::{Path, Json},
extract::{Json, Path},
http::StatusCode,
Extension,
};
use database::enums::AssetPermissionRole;
use handlers::metrics::sharing::create_metric_sharing_handler;
use middleware::AuthenticatedUser;
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use uuid::Uuid;
use crate::routes::rest::ApiResponse;
/// Request structure for sharing a metric with users
/// Structure for a single share recipient with their role
#[derive(Debug, Deserialize)]
pub struct SharingRequest {
pub emails: Vec<String>,
pub struct ShareRecipient {
pub email: String,
pub role: AssetPermissionRole,
}
@ -22,12 +22,23 @@ pub struct SharingRequest {
pub async fn create_metric_sharing_rest_handler(
Extension(user): Extension<AuthenticatedUser>,
Path(id): Path<Uuid>,
Json(request): Json<SharingRequest>,
Json(request): Json<Vec<ShareRecipient>>,
) -> Result<ApiResponse<String>, (StatusCode, String)> {
tracing::info!("Processing POST request for metric sharing with ID: {}, user_id: {}", id, user.id);
tracing::info!(
"Processing POST request for metric sharing with ID: {}, user_id: {}",
id,
user.id
);
match create_metric_sharing_handler(&id, &user.id, request.emails, request.role).await {
Ok(_) => Ok(ApiResponse::JsonData("Sharing permissions created successfully".to_string())),
let emails_and_roles: Vec<(String, AssetPermissionRole)> = request
.into_iter()
.map(|recipient| (recipient.email, recipient.role))
.collect();
match create_metric_sharing_handler(&id, &user.id, emails_and_roles).await {
Ok(_) => Ok(ApiResponse::JsonData(
"Sharing permissions created successfully".to_string(),
)),
Err(e) => {
tracing::error!("Error creating sharing permissions: {}", e);
@ -37,12 +48,18 @@ pub async fn create_metric_sharing_rest_handler(
if error_message.contains("not found") {
return Err((StatusCode::NOT_FOUND, format!("Metric not found: {}", e)));
} else if error_message.contains("permission") {
return Err((StatusCode::FORBIDDEN, format!("Insufficient permissions: {}", e)));
return Err((
StatusCode::FORBIDDEN,
format!("Insufficient permissions: {}", e),
));
} else if error_message.contains("Invalid email") {
return Err((StatusCode::BAD_REQUEST, format!("Invalid email: {}", e)));
}
Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to create sharing permissions: {}", e)))
Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to create sharing permissions: {}", e),
))
}
}
}

View File

@ -10,22 +10,22 @@ use uuid::Uuid;
use crate::routes::rest::ApiResponse;
/// Request structure for deleting sharing permissions
#[derive(Debug, Deserialize)]
pub struct DeleteSharingRequest {
pub emails: Vec<String>,
}
/// REST handler for deleting sharing permissions for a metric
pub async fn delete_metric_sharing_rest_handler(
Extension(user): Extension<AuthenticatedUser>,
Path(id): Path<Uuid>,
Json(request): Json<DeleteSharingRequest>,
Json(request): Json<Vec<String>>,
) -> Result<ApiResponse<String>, (StatusCode, String)> {
tracing::info!("Processing DELETE request for metric sharing with ID: {}, user_id: {}", id, user.id);
tracing::info!(
"Processing DELETE request for metric sharing with ID: {}, user_id: {}",
id,
user.id
);
match delete_metric_sharing_handler(&id, &user.id, request.emails).await {
Ok(_) => Ok(ApiResponse::JsonData("Sharing permissions deleted successfully".to_string())),
match delete_metric_sharing_handler(&id, &user.id, request).await {
Ok(_) => Ok(ApiResponse::JsonData(
"Sharing permissions deleted successfully".to_string(),
)),
Err(e) => {
tracing::error!("Error deleting sharing permissions: {}", e);
@ -33,12 +33,18 @@ pub async fn delete_metric_sharing_rest_handler(
if e.to_string().contains("not found") {
return Err((StatusCode::NOT_FOUND, format!("Metric not found: {}", e)));
} else if e.to_string().contains("permission") {
return Err((StatusCode::FORBIDDEN, format!("Insufficient permissions: {}", e)));
return Err((
StatusCode::FORBIDDEN,
format!("Insufficient permissions: {}", e),
));
} else if e.to_string().contains("invalid email") {
return Err((StatusCode::BAD_REQUEST, format!("Invalid email: {}", e)));
}
Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to delete sharing permissions: {}", e)))
Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to delete sharing permissions: {}", e),
))
}
}
}

View File

@ -1,8 +1,4 @@
use axum::{
extract::Path,
http::StatusCode,
Extension,
};
use axum::{extract::Path, http::StatusCode, Extension};
use handlers::metrics::sharing::list_metric_sharing_handler;
use middleware::AuthenticatedUser;
use serde::{Deserialize, Serialize};
@ -30,22 +26,27 @@ pub struct SharingPermission {
pub async fn list_metric_sharing_rest_handler(
Extension(user): Extension<AuthenticatedUser>,
Path(id): Path<Uuid>,
) -> Result<ApiResponse<SharingResponse>, (StatusCode, String)> {
tracing::info!("Processing GET request for metric sharing with ID: {}, user_id: {}", id, user.id);
) -> Result<ApiResponse<Vec<SharingPermission>>, (StatusCode, String)> {
tracing::info!(
"Processing GET request for metric sharing with ID: {}, user_id: {}",
id,
user.id
);
match list_metric_sharing_handler(&id, &user.id).await {
Ok(permissions) => {
let response = SharingResponse {
permissions: permissions.into_iter().map(|p| SharingPermission {
let response = permissions
.into_iter()
.map(|p| SharingPermission {
user_id: p.user.as_ref().map(|u| u.id).unwrap_or_default(),
email: p.user.as_ref().map(|u| u.email.clone()).unwrap_or_default(),
name: p.user.as_ref().and_then(|u| u.name.clone()),
avatar_url: p.user.as_ref().and_then(|u| u.avatar_url.clone()),
role: p.permission.role,
}).collect(),
};
})
.collect();
Ok(ApiResponse::JsonData(response))
},
}
Err(e) => {
tracing::error!("Error listing sharing permissions: {}", e);
let error_message = e.to_string();
@ -56,7 +57,10 @@ pub async fn list_metric_sharing_rest_handler(
} else if error_message.contains("permission") {
return Err((StatusCode::FORBIDDEN, format!("Permission denied: {}", e)));
} else {
return Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to list sharing permissions: {}", e)));
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Failed to list sharing permissions: {}", e),
));
}
}
}

View File

@ -74,8 +74,12 @@ async fn test_create_metric_sharing_success() {
.post(&format!("/metrics/{}/sharing", metric.id))
.with_auth(&owner.id.to_string())
.json(&json!({
"emails": ["shared@example.com"],
"recipients": [
{
"email": "shared@example.com",
"role": "CanView"
}
]
}))
.send()
.await;