2025-04-02 03:43:44 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
use async_trait::async_trait;
|
2026-02-08 13:40:23 +01:00
|
|
|
use tracing::info;
|
2025-04-02 03:43:44 +02:00
|
|
|
use crate::common::errors::{Result, DomainError, ErrorKind};
|
2026-02-08 13:40:23 +01:00
|
|
|
use crate::application::ports::favorites_ports::{FavoritesUseCase, FavoritesRepositoryPort};
|
2025-04-02 03:43:44 +02:00
|
|
|
use crate::application::dtos::favorites_dto::FavoriteItemDto;
|
|
|
|
|
|
2026-02-08 13:40:23 +01:00
|
|
|
/// Implementation of the FavoritesUseCase for managing user favorites.
|
|
|
|
|
///
|
|
|
|
|
/// Depends on `FavoritesRepositoryPort` (outbound port) instead of
|
|
|
|
|
/// accessing the database directly, following hexagonal architecture.
|
2025-04-02 03:43:44 +02:00
|
|
|
pub struct FavoritesService {
|
2026-02-08 13:40:23 +01:00
|
|
|
repo: Arc<dyn FavoritesRepositoryPort>,
|
2025-04-02 03:43:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FavoritesService {
|
2026-02-08 13:40:23 +01:00
|
|
|
/// Create a new FavoritesService with the given repository port
|
|
|
|
|
pub fn new(repo: Arc<dyn FavoritesRepositoryPort>) -> Self {
|
|
|
|
|
Self { repo }
|
2025-04-02 03:43:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
|
impl FavoritesUseCase for FavoritesService {
|
|
|
|
|
/// Get all favorites for a user
|
|
|
|
|
async fn get_favorites(&self, user_id: &str) -> Result<Vec<FavoriteItemDto>> {
|
|
|
|
|
info!("Getting favorites for user: {}", user_id);
|
2026-02-08 13:40:23 +01:00
|
|
|
let favorites = self.repo.get_favorites(user_id).await?;
|
2025-04-02 03:43:44 +02:00
|
|
|
info!("Retrieved {} favorites for user {}", favorites.len(), user_id);
|
|
|
|
|
Ok(favorites)
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
2025-04-02 03:43:44 +02:00
|
|
|
/// Add an item to user's favorites
|
|
|
|
|
async fn add_to_favorites(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<()> {
|
|
|
|
|
info!("Adding {} '{}' to favorites for user {}", item_type, item_id, user_id);
|
2026-02-08 13:40:23 +01:00
|
|
|
|
2025-04-02 03:43:44 +02:00
|
|
|
if item_type != "file" && item_type != "folder" {
|
|
|
|
|
return Err(DomainError::new(
|
|
|
|
|
ErrorKind::InvalidInput,
|
|
|
|
|
"Favorites",
|
2026-02-08 13:40:23 +01:00
|
|
|
"Item type must be 'file' or 'folder'",
|
2025-04-02 03:43:44 +02:00
|
|
|
));
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
|
|
|
|
self.repo.add_favorite(user_id, item_id, item_type).await?;
|
2025-04-02 03:43:44 +02:00
|
|
|
info!("Successfully added {} '{}' to favorites for user {}", item_type, item_id, user_id);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
2025-04-02 03:43:44 +02:00
|
|
|
/// Remove an item from user's favorites
|
|
|
|
|
async fn remove_from_favorites(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<bool> {
|
|
|
|
|
info!("Removing {} '{}' from favorites for user {}", item_type, item_id, user_id);
|
2026-02-08 13:40:23 +01:00
|
|
|
let removed = self.repo.remove_favorite(user_id, item_id, item_type).await?;
|
2025-04-02 03:43:44 +02:00
|
|
|
info!(
|
2026-02-08 13:40:23 +01:00
|
|
|
"{} {} '{}' from favorites for user {}",
|
2025-04-02 03:43:44 +02:00
|
|
|
if removed { "Successfully removed" } else { "Did not find" },
|
2026-02-08 13:40:23 +01:00
|
|
|
item_type, item_id, user_id
|
2025-04-02 03:43:44 +02:00
|
|
|
);
|
|
|
|
|
Ok(removed)
|
|
|
|
|
}
|
2026-02-08 13:40:23 +01:00
|
|
|
|
2025-04-02 03:43:44 +02:00
|
|
|
/// Check if an item is in user's favorites
|
|
|
|
|
async fn is_favorite(&self, user_id: &str, item_id: &str, item_type: &str) -> Result<bool> {
|
|
|
|
|
info!("Checking if {} '{}' is favorite for user {}", item_type, item_id, user_id);
|
2026-02-08 13:40:23 +01:00
|
|
|
self.repo.is_favorite(user_id, item_id, item_type).await
|
2025-04-02 03:43:44 +02:00
|
|
|
}
|
|
|
|
|
}
|