use crate::catalog::visibility::VisibilityFilteredAssetRepository; use domain::{ catalog::entities::Asset, catalog::services::resolve_metadata, errors::DomainError, ports::{AssetMetadataRepository, AssetRepository, ShareRepository}, value_objects::{StructuredData, SystemId}, }; use std::sync::Arc; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct GetAssetQuery { pub asset_id: SystemId, pub user_id: SystemId, } pub struct GetAssetHandler { asset_repo: Arc, metadata_repo: Arc, share_repo: Option>, } impl GetAssetHandler { pub fn new( asset_repo: Arc, metadata_repo: Arc, ) -> Self { Self { asset_repo, metadata_repo, share_repo: None, } } /// Enable sharing-aware visibility filtering. When set, the handler /// wraps the inner `AssetRepository` with a `VisibilityFilteredAssetRepository` /// so that shared assets are visible to the caller. pub fn with_visibility_filter(mut self, share_repo: Arc) -> Self { self.share_repo = Some(share_repo); self } /// Returns the effective asset repo — wrapped with a visibility filter /// when a `ShareRepository` has been configured, otherwise the raw inner repo. fn effective_repo(&self, caller_id: SystemId) -> Arc { match &self.share_repo { Some(share_repo) => Arc::new(VisibilityFilteredAssetRepository::new( self.asset_repo.clone(), share_repo.clone(), caller_id, )), None => self.asset_repo.clone(), } } pub async fn execute( &self, query: GetAssetQuery, ) -> Result<(Asset, StructuredData), DomainError> { let repo = self.effective_repo(query.user_id); let asset = repo .find_by_id(&query.asset_id) .await? .ok_or_else(|| DomainError::NotFound(format!("Asset {} not found", query.asset_id)))?; // When the visibility filter is active it already enforces access. // When it is not, fall back to the original owner-only check. if self.share_repo.is_none() && asset.owner_user_id != query.user_id { return Err(DomainError::Forbidden("Access denied".to_string())); } let layers = self.metadata_repo.find_by_asset(&asset.asset_id).await?; let resolved = resolve_metadata(&layers); Ok((asset, resolved)) } }