refactor: extract inline test modules to separate files
This commit is contained in:
284
crates/application/src/use_cases/social/mod.rs
Normal file
284
crates/application/src/use_cases/social/mod.rs
Normal file
@@ -0,0 +1,284 @@
|
||||
use chrono::Utc;
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
events::DomainEvent,
|
||||
models::social::{Block, Boost, Follow, FollowState, Like},
|
||||
ports::{
|
||||
BlockRepository, BoostRepository, EventPublisher, FederationFollowPort, FollowRepository,
|
||||
LikeRepository, UserReader,
|
||||
},
|
||||
value_objects::{BoostId, LikeId, ThoughtId, UserId, Username},
|
||||
};
|
||||
|
||||
pub async fn like_thought(
|
||||
likes: &dyn LikeRepository,
|
||||
events: &dyn EventPublisher,
|
||||
user_id: &UserId,
|
||||
thought_id: &ThoughtId,
|
||||
) -> Result<(), DomainError> {
|
||||
let like = Like {
|
||||
id: LikeId::new(),
|
||||
user_id: user_id.clone(),
|
||||
thought_id: thought_id.clone(),
|
||||
ap_id: None,
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
likes.save(&like).await?;
|
||||
events
|
||||
.publish(&DomainEvent::LikeAdded {
|
||||
like_id: like.id,
|
||||
user_id: user_id.clone(),
|
||||
thought_id: thought_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unlike_thought(
|
||||
likes: &dyn LikeRepository,
|
||||
events: &dyn EventPublisher,
|
||||
user_id: &UserId,
|
||||
thought_id: &ThoughtId,
|
||||
) -> Result<(), DomainError> {
|
||||
likes.delete(user_id, thought_id).await?;
|
||||
events
|
||||
.publish(&DomainEvent::LikeRemoved {
|
||||
user_id: user_id.clone(),
|
||||
thought_id: thought_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn boost_thought(
|
||||
boosts: &dyn BoostRepository,
|
||||
events: &dyn EventPublisher,
|
||||
user_id: &UserId,
|
||||
thought_id: &ThoughtId,
|
||||
) -> Result<(), DomainError> {
|
||||
let boost = Boost {
|
||||
id: BoostId::new(),
|
||||
user_id: user_id.clone(),
|
||||
thought_id: thought_id.clone(),
|
||||
ap_id: None,
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
boosts.save(&boost).await?;
|
||||
events
|
||||
.publish(&DomainEvent::BoostAdded {
|
||||
boost_id: boost.id,
|
||||
user_id: user_id.clone(),
|
||||
thought_id: thought_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unboost_thought(
|
||||
boosts: &dyn BoostRepository,
|
||||
events: &dyn EventPublisher,
|
||||
user_id: &UserId,
|
||||
thought_id: &ThoughtId,
|
||||
) -> Result<(), DomainError> {
|
||||
boosts.delete(user_id, thought_id).await?;
|
||||
events
|
||||
.publish(&DomainEvent::BoostRemoved {
|
||||
user_id: user_id.clone(),
|
||||
thought_id: thought_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn follow_actor(
|
||||
follows: &dyn FollowRepository,
|
||||
users: &dyn UserReader,
|
||||
federation: &dyn FederationFollowPort,
|
||||
events: &dyn EventPublisher,
|
||||
follower_id: &UserId,
|
||||
username: &str,
|
||||
) -> Result<(), DomainError> {
|
||||
if username.contains('@') {
|
||||
federation.follow_remote(follower_id, username).await
|
||||
} else {
|
||||
let uname = Username::new(username)
|
||||
.map_err(|_| DomainError::InvalidInput("invalid username".into()))?;
|
||||
let target = users
|
||||
.find_by_username(&uname)
|
||||
.await?
|
||||
.ok_or(DomainError::NotFound)?;
|
||||
follow_user(follows, events, follower_id, &target.id).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn follow_user(
|
||||
follows: &dyn FollowRepository,
|
||||
events: &dyn EventPublisher,
|
||||
follower_id: &UserId,
|
||||
following_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
if follower_id == following_id {
|
||||
return Err(DomainError::InvalidInput("cannot follow yourself".into()));
|
||||
}
|
||||
let follow = Follow {
|
||||
follower_id: follower_id.clone(),
|
||||
following_id: following_id.clone(),
|
||||
state: FollowState::Accepted,
|
||||
ap_id: None,
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
follows.save(&follow).await?;
|
||||
events
|
||||
.publish(&DomainEvent::FollowAccepted {
|
||||
follower_id: follower_id.clone(),
|
||||
following_id: following_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unfollow_actor(
|
||||
follows: &dyn FollowRepository,
|
||||
users: &dyn UserReader,
|
||||
federation: &dyn FederationFollowPort,
|
||||
events: &dyn EventPublisher,
|
||||
follower_id: &UserId,
|
||||
username: &str,
|
||||
) -> Result<(), DomainError> {
|
||||
if username.contains('@') {
|
||||
federation.unfollow_remote(follower_id, username).await
|
||||
} else {
|
||||
let uname = Username::new(username)
|
||||
.map_err(|_| DomainError::InvalidInput("invalid username".into()))?;
|
||||
let target = users
|
||||
.find_by_username(&uname)
|
||||
.await?
|
||||
.ok_or(DomainError::NotFound)?;
|
||||
unfollow_user(follows, events, follower_id, &target.id).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn unfollow_user(
|
||||
follows: &dyn FollowRepository,
|
||||
events: &dyn EventPublisher,
|
||||
follower_id: &UserId,
|
||||
following_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
follows.delete(follower_id, following_id).await?;
|
||||
events
|
||||
.publish(&DomainEvent::Unfollowed {
|
||||
follower_id: follower_id.clone(),
|
||||
following_id: following_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn accept_follow(
|
||||
follows: &dyn FollowRepository,
|
||||
events: &dyn EventPublisher,
|
||||
follower_id: &UserId,
|
||||
following_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
follows
|
||||
.update_state(follower_id, following_id, &FollowState::Accepted)
|
||||
.await?;
|
||||
events
|
||||
.publish(&DomainEvent::FollowAccepted {
|
||||
follower_id: follower_id.clone(),
|
||||
following_id: following_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reject_follow(
|
||||
follows: &dyn FollowRepository,
|
||||
events: &dyn EventPublisher,
|
||||
follower_id: &UserId,
|
||||
following_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
follows
|
||||
.update_state(follower_id, following_id, &FollowState::Rejected)
|
||||
.await?;
|
||||
events
|
||||
.publish(&DomainEvent::FollowRejected {
|
||||
follower_id: follower_id.clone(),
|
||||
following_id: following_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn block_by_username(
|
||||
blocks: &dyn BlockRepository,
|
||||
users: &dyn UserReader,
|
||||
events: &dyn EventPublisher,
|
||||
blocker_id: &UserId,
|
||||
username: &str,
|
||||
) -> Result<(), DomainError> {
|
||||
let uname = Username::new(username).map_err(|_| DomainError::NotFound)?;
|
||||
let target = users
|
||||
.find_by_username(&uname)
|
||||
.await?
|
||||
.ok_or(DomainError::NotFound)?;
|
||||
block_user(blocks, events, blocker_id, &target.id).await
|
||||
}
|
||||
|
||||
pub async fn unblock_by_username(
|
||||
blocks: &dyn BlockRepository,
|
||||
users: &dyn UserReader,
|
||||
events: &dyn EventPublisher,
|
||||
blocker_id: &UserId,
|
||||
username: &str,
|
||||
) -> Result<(), DomainError> {
|
||||
let uname = Username::new(username).map_err(|_| DomainError::NotFound)?;
|
||||
let target = users
|
||||
.find_by_username(&uname)
|
||||
.await?
|
||||
.ok_or(DomainError::NotFound)?;
|
||||
unblock_user(blocks, events, blocker_id, &target.id).await
|
||||
}
|
||||
|
||||
pub async fn block_user(
|
||||
blocks: &dyn BlockRepository,
|
||||
events: &dyn EventPublisher,
|
||||
blocker_id: &UserId,
|
||||
blocked_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
if blocker_id == blocked_id {
|
||||
return Err(DomainError::InvalidInput("cannot block yourself".into()));
|
||||
}
|
||||
let block = Block {
|
||||
blocker_id: blocker_id.clone(),
|
||||
blocked_id: blocked_id.clone(),
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
blocks.save(&block).await?;
|
||||
events
|
||||
.publish(&DomainEvent::UserBlocked {
|
||||
blocker_id: blocker_id.clone(),
|
||||
blocked_id: blocked_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unblock_user(
|
||||
blocks: &dyn BlockRepository,
|
||||
events: &dyn EventPublisher,
|
||||
blocker_id: &UserId,
|
||||
blocked_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
blocks.delete(blocker_id, blocked_id).await?;
|
||||
events
|
||||
.publish(&DomainEvent::UserUnblocked {
|
||||
blocker_id: blocker_id.clone(),
|
||||
blocked_id: blocked_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user