mirror of https://github.com/buster-so/buster.git
8.7 KiB
8.7 KiB
API Metrics Sharing REST Endpoints
Problem Statement
Currently, there is no way to manage sharing permissions for metrics through REST endpoints. Users need to be able to share metrics with other users, update sharing permissions, and remove sharing permissions through REST endpoints.
Current State
- The metrics REST API currently only supports basic CRUD operations
- There is no way to manage sharing permissions for metrics through REST endpoints
Desired State
- Add the following endpoints:
- POST /metrics/:id/sharing - Share a metric with users
- PUT /metrics/:id/sharing - Update sharing permissions for users
- DELETE /metrics/:id/sharing - Remove sharing permissions for users
Impact
- Enables programmatic management of metric sharing permissions
- Improves collaboration capabilities for metrics
- Provides consistent API patterns for resource sharing across the application
Technical Design
Components Affected
- REST API routes for metrics
- Handlers for managing metric sharing permissions
New Files
/src/routes/rest/routes/metrics/sharing/mod.rs
- Router configuration for sharing endpoints/src/routes/rest/routes/metrics/sharing/create_sharing.rs
- REST handler for creating sharing permissions/src/routes/rest/routes/metrics/sharing/update_sharing.rs
- REST handler for updating sharing permissions/src/routes/rest/routes/metrics/sharing/delete_sharing.rs
- REST handler for deleting sharing permissions/libs/handlers/src/metrics/sharing/mod.rs
- Export sharing handlers/libs/handlers/src/metrics/sharing/create_sharing_handler.rs
- Business logic for creating sharing permissions/libs/handlers/src/metrics/sharing/update_sharing_handler.rs
- Business logic for updating sharing permissions/libs/handlers/src/metrics/sharing/delete_sharing_handler.rs
- Business logic for deleting sharing permissions
Modified Files
/src/routes/rest/routes/metrics/mod.rs
- Add sharing router/libs/handlers/src/metrics/mod.rs
- Export sharing module
Detailed Design
1. Create Sharing Endpoint (POST /metrics/:id/sharing)
Request Structure:
#[derive(Debug, Deserialize)]
pub struct SharingRequest {
pub emails: Vec<String>,
pub role: AssetPermissionRole,
}
Handler Implementation:
// create_sharing.rs
pub async fn create_metric_sharing_rest_handler(
Extension(user): Extension<AuthenticatedUser>,
Path(id): Path<Uuid>,
Json(request): Json<SharingRequest>,
) -> Result<ApiResponse<()>, (StatusCode, String)> {
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::Success("Sharing permissions created successfully".to_string())),
Err(e) => {
tracing::error!("Error creating sharing permissions: {}", e);
Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to create sharing permissions: {}", e)))
}
}
}
Business Logic: The create_metric_sharing_handler will:
- Validate the user has permission to share the metric
- Validate the metric exists
- Resolve email addresses to user IDs
- Create AssetPermission entries for each user with the specified role
- Return success
2. Update Sharing Endpoint (PUT /metrics/:id/sharing)
Request Structure:
#[derive(Debug, Deserialize)]
pub struct SharingRequest {
pub emails: Vec<String>,
pub role: AssetPermissionRole,
}
Handler Implementation:
// update_sharing.rs
pub async fn update_metric_sharing_rest_handler(
Extension(user): Extension<AuthenticatedUser>,
Path(id): Path<Uuid>,
Json(request): Json<SharingRequest>,
) -> Result<ApiResponse<()>, (StatusCode, String)> {
tracing::info!(
"Processing PUT request for metric sharing with ID: {}, user_id: {}",
id,
user.id
);
match update_metric_sharing_handler(&id, &user.id, request.emails, request.role).await {
Ok(_) => Ok(ApiResponse::Success("Sharing permissions updated successfully".to_string())),
Err(e) => {
tracing::error!("Error updating sharing permissions: {}", e);
Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to update sharing permissions: {}", e)))
}
}
}
Business Logic: The update_metric_sharing_handler will:
- Validate the user has permission to update sharing for the metric
- Validate the metric exists
- Resolve email addresses to user IDs
- Update existing AssetPermission entries for each user with the new role
- Return success
3. Delete Sharing Endpoint (DELETE /metrics/:id/sharing)
Request Structure:
#[derive(Debug, Deserialize)]
pub struct DeleteSharingRequest {
pub emails: Vec<String>,
}
Handler Implementation:
// delete_sharing.rs
pub async fn delete_metric_sharing_rest_handler(
Extension(user): Extension<AuthenticatedUser>,
Path(id): Path<Uuid>,
Json(request): Json<DeleteSharingRequest>,
) -> Result<ApiResponse<()>, (StatusCode, String)> {
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::Success("Sharing permissions deleted successfully".to_string())),
Err(e) => {
tracing::error!("Error deleting sharing permissions: {}", e);
Err((StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to delete sharing permissions: {}", e)))
}
}
}
Business Logic: The delete_metric_sharing_handler will:
- Validate the user has permission to delete sharing for the metric
- Validate the metric exists
- Resolve email addresses to user IDs
- Soft delete AssetPermission entries for each user by setting deleted_at to current UTC timestamp
- Return success
Database Operations
For all endpoints, we'll be working with the AssetPermission table with the following fields:
- identity_id: The UUID of the user being granted access
- identity_type: Set to IdentityType::User
- asset_id: The UUID of the metric
- asset_type: Set to AssetType::MetricFile
- role: The AssetPermissionRole specified in the request
- created_at: Current UTC timestamp
- updated_at: Current UTC timestamp
- deleted_at: Null for active permissions, UTC timestamp for deleted permissions
- created_by: The UUID of the user making the request
- updated_by: The UUID of the user making the request
Implementation Plan
Phase 1: Create Sharing Endpoint
- Create directory structure for sharing handlers and endpoints
- Implement email to user ID resolution utility
- Implement create_sharing_handler.rs
- Implement create_sharing.rs REST endpoint
- Update module exports
- Test the endpoint
Phase 2: Update Sharing Endpoint
- Implement update_sharing_handler.rs
- Implement update_sharing.rs REST endpoint
- Update module exports
- Test the endpoint
Phase 3: Delete Sharing Endpoint
- Implement delete_sharing_handler.rs
- Implement delete_sharing.rs REST endpoint
- Update module exports
- Test the endpoint
Testing Strategy
Unit Tests
- Test email to user ID resolution
- Test permission validation logic
- Test database operations for creating, updating, and deleting permissions
Integration Tests
- Test POST /metrics/:id/sharing with valid and invalid inputs
- Test PUT /metrics/:id/sharing with valid and invalid inputs
- Test DELETE /metrics/:id/sharing with valid and invalid inputs
- Test error handling for all endpoints
Manual Testing
- Use Postman/curl to verify the endpoints work as expected
- Verify permissions are properly created, updated, and deleted in the database
- Verify access control works as expected after permissions are modified
Dependencies
Files
/libs/database/src/models.rs
- AssetPermission model/libs/database/src/enums.rs
- AssetPermissionRole, IdentityType, and AssetType enums/libs/database/src/schema.rs
- Database schema
File References
/src/routes/rest/routes/metrics/mod.rs
/libs/handlers/src/metrics/mod.rs
Security Considerations
- All endpoints require authentication
- Only users with appropriate permissions should be able to manage sharing
- Input validation must be thorough to prevent security issues
- Email addresses must be properly validated and resolved to user IDs
Monitoring and Logging
- All endpoint calls should be logged with tracing
- Errors should be logged with appropriate context
- Metrics should be collected for endpoint performance
Rollback Plan
If issues are discovered:
- Revert the changes to the affected files
- Deploy the previous version
- Investigate and fix the issues in a new PR