use std::sync::Arc; use async_trait::async_trait; use chrono::Utc; use libertas_core::{ authz::{self, Permission}, error::{CoreError, CoreResult}, models::{Album, Media, PublicAlbumBundle}, repositories::{AlbumRepository, AlbumShareRepository}, schema::{AddMediaToAlbumData, CreateAlbumData, ShareAlbumData, UpdateAlbumData}, services::{AlbumService, AuthorizationService}, }; use uuid::Uuid; pub struct AlbumServiceImpl { album_repo: Arc, album_share_repo: Arc, auth_service: Arc, } impl AlbumServiceImpl { pub fn new( album_repo: Arc, album_share_repo: Arc, auth_service: Arc, ) -> Self { Self { album_repo, album_share_repo, auth_service, } } } #[async_trait] impl AlbumService for AlbumServiceImpl { async fn create_album(&self, data: CreateAlbumData<'_>) -> CoreResult<()> { if data.name.is_empty() { return Err(CoreError::Validation( "Album name cannot be empty".to_string(), )); } let now = Utc::now(); let album = Album { id: Uuid::new_v4(), owner_id: data.owner_id, name: data.name.to_string(), description: data.description.map(String::from), is_public: data.is_public, created_at: now, updated_at: now, }; self.album_repo.create(album).await } async fn get_album_details(&self, album_id: Uuid, user_id: Uuid) -> CoreResult { self.auth_service .check_permission(Some(user_id), Permission::ViewAlbum(album_id)) .await?; let album = self .album_repo .find_by_id(album_id) .await? .ok_or(CoreError::NotFound("Album".to_string(), album_id))?; Ok(album) } async fn add_media_to_album(&self, data: AddMediaToAlbumData, user_id: Uuid) -> CoreResult<()> { self.auth_service .check_permission(Some(user_id), Permission::AddToAlbum(data.album_id)) .await?; for media_id in &data.media_ids { self.auth_service .check_permission(Some(user_id), Permission::ViewMedia(*media_id)) .await?; } self.album_repo .add_media_to_album(data.album_id, &data.media_ids) .await } async fn list_user_albums(&self, user_id: Uuid) -> CoreResult> { self.album_repo.list_by_user(user_id).await } async fn share_album(&self, data: ShareAlbumData, owner_id: Uuid) -> CoreResult<()> { self.auth_service .check_permission(Some(owner_id), Permission::ShareAlbum(data.album_id)) .await?; if data.target_user_id == owner_id { return Err(CoreError::Validation( "Cannot share album with oneself".to_string(), )); } self.album_share_repo .create_or_update_share(data.album_id, data.target_user_id, data.permission) .await } async fn update_album( &self, album_id: Uuid, user_id: Uuid, data: UpdateAlbumData<'_>, ) -> CoreResult { self.auth_service .check_permission(Some(user_id), Permission::EditAlbum(album_id)) .await?; let mut album = self .album_repo .find_by_id(album_id) .await? .ok_or(CoreError::NotFound("Album".to_string(), album_id))?; if let Some(name) = data.name { if name.is_empty() { return Err(CoreError::Validation( "Album name cannot be empty".to_string(), )); } album.name = name.to_string(); } if let Some(description) = data.description { album.description = description.map(|s| s.to_string()); } if let Some(is_public) = data.is_public { if !authz::is_owner(user_id, &album) && is_public { return Err(CoreError::Auth( "Only the owner can make an album public".to_string(), )); } album.is_public = is_public; } self.album_repo.update(album.clone()).await?; Ok(album) } async fn delete_album(&self, album_id: Uuid, user_id: Uuid) -> CoreResult<()> { self.auth_service .check_permission(Some(user_id), Permission::DeleteAlbum(album_id)) .await?; self.album_repo.delete(album_id).await } async fn get_public_album_bundle(&self, album_id: Uuid) -> CoreResult { let album = self .album_repo .find_by_id(album_id) .await? .ok_or(CoreError::NotFound("Album".to_string(), album_id))?; if !album.is_public { return Err(CoreError::Auth("Album is not public".to_string())); } let media = self.album_repo.list_media_by_album_id(album_id).await?; Ok(PublicAlbumBundle { album, media }) } async fn set_album_thumbnail( &self, album_id: Uuid, media_id: Uuid, user_id: Uuid, ) -> CoreResult<()> { self.auth_service .check_permission(Some(user_id), Permission::EditAlbum(album_id)) .await?; self.auth_service .check_permission(Some(user_id), Permission::ViewMedia(media_id)) .await?; self.album_repo .set_thumbnail_media_id(album_id, media_id) .await } async fn get_album_media(&self, album_id: Uuid, user_id: Uuid) -> CoreResult> { self.auth_service .check_permission(Some(user_id), Permission::ViewAlbum(album_id)) .await?; let media = self.album_repo.list_media_by_album_id(album_id).await?; Ok(media) } async fn remove_media_from_album( &self, album_id: Uuid, media_ids: &[Uuid], user_id: Uuid, ) -> CoreResult<()> { self.auth_service .check_permission(Some(user_id), Permission::EditAlbum(album_id)) .await?; self.album_repo .remove_media_from_album(album_id, media_ids) .await } }