2025-03-19 19:52:12 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
use async_trait::async_trait;
|
|
|
|
|
|
|
|
|
|
use crate::application::dtos::file_dto::FileDto;
|
|
|
|
|
use crate::application::ports::file_ports::FileUploadUseCase;
|
|
|
|
|
use crate::application::ports::storage_ports::FileWritePort;
|
|
|
|
|
use crate::common::errors::DomainError;
|
2025-04-09 00:21:20 +02:00
|
|
|
use crate::application::ports::storage_ports::StorageUsagePort;
|
|
|
|
|
use tracing::{debug, warn};
|
|
|
|
|
|
|
|
|
|
/// Helper function to extract username from folder path string
|
|
|
|
|
fn extract_username_from_path(path: &str) -> Option<String> {
|
|
|
|
|
// Check if path contains the folder pattern
|
|
|
|
|
if !path.contains("Mi Carpeta - ") {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Split by the pattern and get the second part
|
|
|
|
|
let parts: Vec<&str> = path.split("Mi Carpeta - ").collect();
|
|
|
|
|
if parts.len() <= 1 {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Trim and return as owned String
|
|
|
|
|
Some(parts[1].trim().to_string())
|
|
|
|
|
}
|
2025-03-19 19:52:12 +01:00
|
|
|
|
|
|
|
|
/// Servicio para operaciones de subida de archivos
|
|
|
|
|
pub struct FileUploadService {
|
|
|
|
|
file_repository: Arc<dyn FileWritePort>,
|
2025-04-09 00:21:20 +02:00
|
|
|
storage_usage_service: Option<Arc<dyn StorageUsagePort>>,
|
2025-03-19 19:52:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FileUploadService {
|
|
|
|
|
/// Crea un nuevo servicio de subida de archivos
|
|
|
|
|
pub fn new(file_repository: Arc<dyn FileWritePort>) -> Self {
|
2025-04-09 00:21:20 +02:00
|
|
|
Self {
|
|
|
|
|
file_repository,
|
|
|
|
|
storage_usage_service: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Configura el servicio de uso de almacenamiento
|
|
|
|
|
pub fn with_storage_usage_service(
|
|
|
|
|
mut self,
|
|
|
|
|
storage_usage_service: Arc<dyn StorageUsagePort>
|
|
|
|
|
) -> Self {
|
|
|
|
|
self.storage_usage_service = Some(storage_usage_service);
|
|
|
|
|
self
|
2025-03-19 19:52:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
|
impl FileUploadUseCase for FileUploadService {
|
|
|
|
|
async fn upload_file(
|
|
|
|
|
&self,
|
|
|
|
|
name: String,
|
|
|
|
|
folder_id: Option<String>,
|
|
|
|
|
content_type: String,
|
|
|
|
|
content: Vec<u8>,
|
|
|
|
|
) -> Result<FileDto, DomainError> {
|
2025-04-09 00:21:20 +02:00
|
|
|
// Upload the file
|
2025-03-19 19:52:12 +01:00
|
|
|
let file = self.file_repository.save_file(name, folder_id, content_type, content).await?;
|
2025-04-09 00:21:20 +02:00
|
|
|
|
|
|
|
|
// Extract the owner's user ID if available
|
|
|
|
|
// We could make this more explicit by adding a user_id parameter
|
|
|
|
|
if let Some(storage_service) = &self.storage_usage_service {
|
|
|
|
|
// Extract user ID from folder pattern 'Mi Carpeta - {username}'
|
|
|
|
|
if let Some(folder_id) = file.folder_id() {
|
|
|
|
|
// Since we don't have direct access to folder details,
|
|
|
|
|
// we'll use pattern matching on the folder ID
|
|
|
|
|
// In a more complete implementation, we would use a folder repository
|
|
|
|
|
let folder_id_str = folder_id;
|
|
|
|
|
|
|
|
|
|
// Check if we can extract a username from context
|
|
|
|
|
if let Ok(folder_path) = self.file_repository.get_folder_path_str(folder_id_str).await {
|
|
|
|
|
// Process the string to extract username without creating borrowing issues
|
|
|
|
|
if let Some(username) = extract_username_from_path(&folder_path) {
|
|
|
|
|
// Find user by username and update their storage usage
|
|
|
|
|
// We do this asynchronously to avoid blocking the upload response
|
|
|
|
|
let service_clone = Arc::clone(storage_service);
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
match service_clone.update_user_storage_usage(&username).await {
|
|
|
|
|
Ok(usage) => {
|
|
|
|
|
debug!("Updated storage usage for user {} to {} bytes", username, usage);
|
|
|
|
|
},
|
|
|
|
|
Err(e) => {
|
|
|
|
|
warn!("Failed to update storage usage for {}: {}", username, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
warn!("Could not get folder path for ID: {}", folder_id_str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-19 19:52:12 +01:00
|
|
|
Ok(FileDto::from(file))
|
|
|
|
|
}
|
|
|
|
|
}
|