249 lines
7.0 KiB
Rust
249 lines
7.0 KiB
Rust
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<dyn PersonRepository>,
|
|
face_repo: Arc<dyn FaceRegionRepository>,
|
|
person_share_repo: Arc<dyn PersonShareRepository>,
|
|
auth_service: Arc<dyn AuthorizationService>,
|
|
}
|
|
|
|
impl PersonServiceImpl {
|
|
pub fn new(
|
|
person_repo: Arc<dyn PersonRepository>,
|
|
face_repo: Arc<dyn FaceRegionRepository>,
|
|
person_share_repo: Arc<dyn PersonShareRepository>,
|
|
auth_service: Arc<dyn AuthorizationService>,
|
|
) -> Self {
|
|
Self {
|
|
person_repo,
|
|
face_repo,
|
|
person_share_repo,
|
|
auth_service,
|
|
}
|
|
}
|
|
|
|
async fn get_person(&self, person_id: Uuid) -> CoreResult<Person> {
|
|
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<Person> {
|
|
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<Person> {
|
|
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<Vec<Person>> {
|
|
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::<Vec<Person>>();
|
|
|
|
owned_people.extend(shared_people);
|
|
|
|
Ok(owned_people)
|
|
}
|
|
|
|
async fn update_person(
|
|
&self,
|
|
person_id: Uuid,
|
|
name: &str,
|
|
user_id: Uuid,
|
|
) -> CoreResult<Person> {
|
|
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<FaceRegion> {
|
|
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<Vec<FaceRegion>> {
|
|
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
|
|
}
|
|
}
|