use std::sync::Arc; use async_trait::async_trait; use libertas_core::{ authz, error::{CoreError, CoreResult}, models::{FaceRegion, Person, PersonPermission}, repositories::{FaceRegionRepository, PersonRepository, PersonShareRepository}, services::{AuthorizationService, PersonService}, }; use uuid::Uuid; pub struct PersonServiceImpl { person_repo: Arc, face_repo: Arc, person_share_repo: Arc, auth_service: Arc, } impl PersonServiceImpl { pub fn new( person_repo: Arc, face_repo: Arc, person_share_repo: Arc, auth_service: Arc, ) -> Self { Self { person_repo, face_repo, person_share_repo, auth_service, } } async fn get_person(&self, person_id: Uuid) -> CoreResult { let person = self .person_repo .find_by_id(person_id) .await? .ok_or(CoreError::NotFound("Person".to_string(), person_id))?; Ok(person) } } #[async_trait] impl PersonService for PersonServiceImpl { async fn create_person(&self, name: &str, owner_id: Uuid) -> CoreResult { let person = Person { id: Uuid::new_v4(), owner_id, name: name.to_string(), thumbnail_media_id: None, }; self.person_repo.create(person.clone()).await?; Ok(person) } async fn get_person(&self, person_id: Uuid, user_id: Uuid) -> CoreResult { self.auth_service .check_permission(Some(user_id), authz::Permission::ViewPerson(person_id)) .await?; self.person_repo .find_by_id(person_id) .await? .ok_or(CoreError::NotFound("Person".to_string(), person_id)) } async fn list_people(&self, user_id: Uuid) -> CoreResult> { let mut owned_people = self.person_repo.list_by_user(user_id).await?; let shared_people_with_perms = self .person_share_repo .list_people_shared_with_user(user_id) .await?; let shared_people = shared_people_with_perms .into_iter() .map(|(person, _permission)| person) .collect::>(); owned_people.extend(shared_people); Ok(owned_people) } async fn update_person( &self, person_id: Uuid, name: &str, user_id: Uuid, ) -> CoreResult { self.auth_service .check_permission(Some(user_id), authz::Permission::EditPerson(person_id)) .await?; let mut person = self.get_person(person_id).await?; person.name = name.to_string(); self.person_repo.update(person.clone()).await?; Ok(person) } async fn delete_person(&self, person_id: Uuid, user_id: Uuid) -> CoreResult<()> { self.auth_service .check_permission(Some(user_id), authz::Permission::DeletePerson(person_id)) .await?; self.person_repo.delete(person_id).await } async fn assign_face_to_person( &self, face_region_id: Uuid, person_id: Uuid, user_id: Uuid, ) -> CoreResult { self.auth_service .check_permission(Some(user_id), authz::Permission::UsePerson(person_id)) .await?; self.auth_service .check_permission(Some(user_id), authz::Permission::AssignFace(face_region_id)) .await?; let mut face = self.face_repo .find_by_id(face_region_id) .await? .ok_or(CoreError::NotFound( "FaceRegion".to_string(), face_region_id, ))?; self.face_repo .update_person_id(face_region_id, person_id) .await?; face.person_id = Some(person_id); Ok(face) } async fn list_faces_for_media( &self, media_id: Uuid, user_id: Uuid, ) -> CoreResult> { self.auth_service .check_permission(Some(user_id), authz::Permission::ViewFaces(media_id)) .await?; self.face_repo.find_by_media_id(media_id).await } async fn share_person( &self, person_id: Uuid, target_user_id: Uuid, permission: PersonPermission, owner_id: Uuid, ) -> CoreResult<()> { self.auth_service .check_permission(Some(owner_id), authz::Permission::SharePerson(person_id)) .await?; self.person_share_repo .create_or_update_share(person_id, target_user_id, permission) .await } async fn unshare_person( &self, person_id: Uuid, target_user_id: Uuid, owner_id: Uuid, ) -> CoreResult<()> { self.auth_service .check_permission(Some(owner_id), authz::Permission::SharePerson(person_id)) .await?; self.person_share_repo .remove_share(person_id, target_user_id) .await } async fn merge_people( &self, target_person_id: Uuid, source_person_id: Uuid, user_id: Uuid, ) -> CoreResult<()> { if target_person_id == source_person_id { return Err(CoreError::Validation( "Cannot merge the same person".to_string(), )); } self.auth_service .check_permission( Some(user_id), authz::Permission::EditPerson(target_person_id), ) .await?; self.auth_service .check_permission( Some(user_id), authz::Permission::EditPerson(source_person_id), ) .await?; self.face_repo .reassign_person(source_person_id, target_person_id) .await?; self.person_repo.delete(source_person_id).await } async fn set_person_thumbnail( &self, person_id: Uuid, face_region_id: Uuid, user_id: Uuid, ) -> CoreResult<()> { self.auth_service .check_permission(Some(user_id), authz::Permission::EditPerson(person_id)) .await?; let face_region = self.face_repo .find_by_id(face_region_id) .await? .ok_or(CoreError::NotFound( "FaceRegion".to_string(), face_region_id, ))?; if face_region.person_id != Some(person_id) { return Err(CoreError::Validation( "FaceRegion does not belong to the specified person".to_string(), )); } self.person_repo .set_thumbnail_media_id(person_id, face_region.media_id) .await } }