92 lines
3.0 KiB
Rust
92 lines
3.0 KiB
Rust
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
|
|
use crate::users::{commands::UpdateProfileCommand, deps::UpdateProfileDeps};
|
|
|
|
pub async fn execute(deps: &UpdateProfileDeps, cmd: UpdateProfileCommand) -> Result<(), DomainError> {
|
|
let user_id = UserId::from_uuid(cmd.user_id);
|
|
|
|
let user = deps
|
|
.user
|
|
.find_by_id(&user_id)
|
|
.await?
|
|
.ok_or_else(|| DomainError::NotFound("User not found".into()))?;
|
|
|
|
// Handle avatar
|
|
let new_avatar_path = if let Some(bytes) = cmd.avatar_bytes {
|
|
let content_type = cmd.avatar_content_type.as_deref().unwrap_or("");
|
|
if !["image/jpeg", "image/png", "image/webp"].contains(&content_type) {
|
|
return Err(DomainError::ValidationError(
|
|
"Avatar must be jpeg, png, or webp".into(),
|
|
));
|
|
}
|
|
if let Some(old_path) = user.avatar_path() {
|
|
let _ = deps.object_storage.delete(old_path).await;
|
|
}
|
|
let key = format!("avatars/{}", user_id.value());
|
|
let stored = deps.object_storage.store(&key, &bytes).await?;
|
|
if let Err(e) = deps
|
|
.event_publisher
|
|
.publish(&DomainEvent::ImageStored {
|
|
key: stored.clone(),
|
|
})
|
|
.await
|
|
{
|
|
tracing::warn!("failed to emit ImageStored for avatar {stored}: {e}");
|
|
}
|
|
Some(stored)
|
|
} else {
|
|
user.avatar_path().map(|s| s.to_string())
|
|
};
|
|
|
|
// Handle banner
|
|
let new_banner_path = if let Some(bytes) = cmd.banner_bytes {
|
|
let content_type = cmd.banner_content_type.as_deref().unwrap_or("");
|
|
if !["image/jpeg", "image/png", "image/webp"].contains(&content_type) {
|
|
return Err(DomainError::ValidationError(
|
|
"Banner must be jpeg, png, or webp".into(),
|
|
));
|
|
}
|
|
if let Some(old_path) = user.banner_path() {
|
|
let _ = deps.object_storage.delete(old_path).await;
|
|
}
|
|
let key = format!("banners/{}", user_id.value());
|
|
let stored = deps.object_storage.store(&key, &bytes).await?;
|
|
if let Err(e) = deps
|
|
.event_publisher
|
|
.publish(&DomainEvent::ImageStored {
|
|
key: stored.clone(),
|
|
})
|
|
.await
|
|
{
|
|
tracing::warn!("failed to emit ImageStored for banner {stored}: {e}");
|
|
}
|
|
Some(stored)
|
|
} else {
|
|
user.banner_path().map(|s| s.to_string())
|
|
};
|
|
|
|
deps.user
|
|
.update_profile(
|
|
&user_id,
|
|
&domain::models::UserProfile {
|
|
display_name: cmd.display_name,
|
|
bio: cmd.bio,
|
|
avatar_path: new_avatar_path,
|
|
banner_path: new_banner_path,
|
|
also_known_as: cmd.also_known_as,
|
|
profile_fields: vec![],
|
|
},
|
|
)
|
|
.await?;
|
|
|
|
deps.event_publisher
|
|
.publish(&DomainEvent::UserUpdated { user_id })
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "tests/update_profile.rs"]
|
|
mod tests;
|