refactor: consolidate 11 social use cases → SocialCmd/SocialQry enum dispatch
-280 net lines. 11 one-file use cases replaced by execute_command/ execute_query with enum dispatch. Added FollowRejected event (reject was silently dropping). Command→event mapping now explicit in one match.
This commit is contained in:
@@ -72,6 +72,11 @@ pub enum EventPayload {
|
|||||||
requester_kind: String,
|
requester_kind: String,
|
||||||
requester_id: String,
|
requester_id: String,
|
||||||
},
|
},
|
||||||
|
FollowRejected {
|
||||||
|
owner_id: String,
|
||||||
|
requester_kind: String,
|
||||||
|
requester_id: String,
|
||||||
|
},
|
||||||
Unfollowed {
|
Unfollowed {
|
||||||
follower_id: String,
|
follower_id: String,
|
||||||
target_kind: String,
|
target_kind: String,
|
||||||
@@ -164,6 +169,7 @@ impl EventPayload {
|
|||||||
EventPayload::WatchlistEntryRemoved { .. } => "WatchlistEntryRemoved",
|
EventPayload::WatchlistEntryRemoved { .. } => "WatchlistEntryRemoved",
|
||||||
EventPayload::FollowRequested { .. } => "FollowRequested",
|
EventPayload::FollowRequested { .. } => "FollowRequested",
|
||||||
EventPayload::FollowAccepted { .. } => "FollowAccepted",
|
EventPayload::FollowAccepted { .. } => "FollowAccepted",
|
||||||
|
EventPayload::FollowRejected { .. } => "FollowRejected",
|
||||||
EventPayload::Unfollowed { .. } => "Unfollowed",
|
EventPayload::Unfollowed { .. } => "Unfollowed",
|
||||||
EventPayload::FollowerRemoved { .. } => "FollowerRemoved",
|
EventPayload::FollowerRemoved { .. } => "FollowerRemoved",
|
||||||
EventPayload::ActorBlocked { .. } => "ActorBlocked",
|
EventPayload::ActorBlocked { .. } => "ActorBlocked",
|
||||||
@@ -328,6 +334,14 @@ impl From<&DomainEvent> for EventPayload {
|
|||||||
requester_id: id,
|
requester_id: id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DomainEvent::FollowRejected { owner, requester } => {
|
||||||
|
let (kind, id) = identity_to_payload(requester);
|
||||||
|
EventPayload::FollowRejected {
|
||||||
|
owner_id: owner.value().to_string(),
|
||||||
|
requester_kind: kind,
|
||||||
|
requester_id: id,
|
||||||
|
}
|
||||||
|
}
|
||||||
DomainEvent::Unfollowed { follower, target } => {
|
DomainEvent::Unfollowed { follower, target } => {
|
||||||
let (kind, id) = identity_to_payload(target);
|
let (kind, id) = identity_to_payload(target);
|
||||||
EventPayload::Unfollowed {
|
EventPayload::Unfollowed {
|
||||||
@@ -559,6 +573,14 @@ impl TryFrom<EventPayload> for DomainEvent {
|
|||||||
owner: UserId::from_uuid(parse_uuid(&owner_id, "owner_id")?),
|
owner: UserId::from_uuid(parse_uuid(&owner_id, "owner_id")?),
|
||||||
requester: payload_to_identity(&requester_kind, requester_id)?,
|
requester: payload_to_identity(&requester_kind, requester_id)?,
|
||||||
}),
|
}),
|
||||||
|
EventPayload::FollowRejected {
|
||||||
|
owner_id,
|
||||||
|
requester_kind,
|
||||||
|
requester_id,
|
||||||
|
} => Ok(DomainEvent::FollowRejected {
|
||||||
|
owner: UserId::from_uuid(parse_uuid(&owner_id, "owner_id")?),
|
||||||
|
requester: payload_to_identity(&requester_kind, requester_id)?,
|
||||||
|
}),
|
||||||
EventPayload::Unfollowed {
|
EventPayload::Unfollowed {
|
||||||
follower_id,
|
follower_id,
|
||||||
target_kind,
|
target_kind,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub fn event_to_subject(prefix: &str, event: &DomainEvent) -> String {
|
|||||||
DomainEvent::WatchlistEntryRemoved { .. } => "watchlist.entry.removed",
|
DomainEvent::WatchlistEntryRemoved { .. } => "watchlist.entry.removed",
|
||||||
DomainEvent::FollowRequested { .. } => "follow.requested",
|
DomainEvent::FollowRequested { .. } => "follow.requested",
|
||||||
DomainEvent::FollowAccepted { .. } => "follow.accepted",
|
DomainEvent::FollowAccepted { .. } => "follow.accepted",
|
||||||
|
DomainEvent::FollowRejected { .. } => "follow.rejected",
|
||||||
DomainEvent::Unfollowed { .. } => "follow.unfollowed",
|
DomainEvent::Unfollowed { .. } => "follow.unfollowed",
|
||||||
DomainEvent::FollowerRemoved { .. } => "follower.removed",
|
DomainEvent::FollowerRemoved { .. } => "follower.removed",
|
||||||
DomainEvent::ActorBlocked { .. } => "actor.blocked",
|
DomainEvent::ActorBlocked { .. } => "actor.blocked",
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::AcceptFollowCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialCommandDeps,
|
|
||||||
cmd: AcceptFollowCommand,
|
|
||||||
) -> Result<(), DomainError> {
|
|
||||||
let owner = UserId::from_uuid(cmd.owner_id);
|
|
||||||
deps.social_command
|
|
||||||
.accept_follow(&owner, &cmd.requester)
|
|
||||||
.await?;
|
|
||||||
deps.event_publisher
|
|
||||||
.publish(&DomainEvent::FollowAccepted {
|
|
||||||
owner,
|
|
||||||
requester: cmd.requester,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/accept.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::BlockCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(deps: &SocialCommandDeps, cmd: BlockCommand) -> Result<(), DomainError> {
|
|
||||||
let blocker = UserId::from_uuid(cmd.blocker_id);
|
|
||||||
deps.social_command.block(&blocker, &cmd.target).await?;
|
|
||||||
deps.event_publisher
|
|
||||||
.publish(&DomainEvent::ActorBlocked {
|
|
||||||
blocker,
|
|
||||||
target: cmd.target,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/block.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,37 +1,33 @@
|
|||||||
use domain::value_objects::{FollowTarget, SocialIdentity};
|
use domain::value_objects::{FollowTarget, SocialIdentity};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub struct FollowCommand {
|
pub enum SocialCmd {
|
||||||
pub follower_id: Uuid,
|
Follow {
|
||||||
pub target: FollowTarget,
|
follower_id: Uuid,
|
||||||
}
|
target: FollowTarget,
|
||||||
|
},
|
||||||
pub struct UnfollowCommand {
|
Unfollow {
|
||||||
pub follower_id: Uuid,
|
follower_id: Uuid,
|
||||||
pub target: SocialIdentity,
|
target: SocialIdentity,
|
||||||
}
|
},
|
||||||
|
AcceptFollow {
|
||||||
pub struct AcceptFollowCommand {
|
owner_id: Uuid,
|
||||||
pub owner_id: Uuid,
|
requester: SocialIdentity,
|
||||||
pub requester: SocialIdentity,
|
},
|
||||||
}
|
RejectFollow {
|
||||||
|
owner_id: Uuid,
|
||||||
pub struct RejectFollowCommand {
|
requester: SocialIdentity,
|
||||||
pub owner_id: Uuid,
|
},
|
||||||
pub requester: SocialIdentity,
|
RemoveFollower {
|
||||||
}
|
owner_id: Uuid,
|
||||||
|
follower: SocialIdentity,
|
||||||
pub struct RemoveFollowerCommand {
|
},
|
||||||
pub owner_id: Uuid,
|
Block {
|
||||||
pub follower: SocialIdentity,
|
blocker_id: Uuid,
|
||||||
}
|
target: SocialIdentity,
|
||||||
|
},
|
||||||
pub struct BlockCommand {
|
Unblock {
|
||||||
pub blocker_id: Uuid,
|
blocker_id: Uuid,
|
||||||
pub target: SocialIdentity,
|
target: SocialIdentity,
|
||||||
}
|
},
|
||||||
|
|
||||||
pub struct UnblockCommand {
|
|
||||||
pub blocker_id: Uuid,
|
|
||||||
pub target: SocialIdentity,
|
|
||||||
}
|
}
|
||||||
|
|||||||
101
crates/application/src/social/execute.rs
Normal file
101
crates/application/src/social/execute.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
use domain::{
|
||||||
|
errors::DomainError,
|
||||||
|
events::DomainEvent,
|
||||||
|
value_objects::{SocialActor, UserId},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
commands::SocialCmd,
|
||||||
|
deps::{SocialCommandDeps, SocialQueryDeps},
|
||||||
|
queries::SocialQry,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn execute_command(
|
||||||
|
deps: &SocialCommandDeps,
|
||||||
|
cmd: SocialCmd,
|
||||||
|
) -> Result<(), DomainError> {
|
||||||
|
let event = match cmd {
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target,
|
||||||
|
} => {
|
||||||
|
let follower = UserId::from_uuid(follower_id);
|
||||||
|
deps.social_command.follow(&follower, &target).await?;
|
||||||
|
DomainEvent::FollowRequested { follower, target }
|
||||||
|
}
|
||||||
|
SocialCmd::Unfollow {
|
||||||
|
follower_id,
|
||||||
|
target,
|
||||||
|
} => {
|
||||||
|
let follower = UserId::from_uuid(follower_id);
|
||||||
|
deps.social_command.unfollow(&follower, &target).await?;
|
||||||
|
DomainEvent::Unfollowed { follower, target }
|
||||||
|
}
|
||||||
|
SocialCmd::AcceptFollow {
|
||||||
|
owner_id,
|
||||||
|
requester,
|
||||||
|
} => {
|
||||||
|
let owner = UserId::from_uuid(owner_id);
|
||||||
|
deps.social_command
|
||||||
|
.accept_follow(&owner, &requester)
|
||||||
|
.await?;
|
||||||
|
DomainEvent::FollowAccepted { owner, requester }
|
||||||
|
}
|
||||||
|
SocialCmd::RejectFollow {
|
||||||
|
owner_id,
|
||||||
|
requester,
|
||||||
|
} => {
|
||||||
|
let owner = UserId::from_uuid(owner_id);
|
||||||
|
deps.social_command
|
||||||
|
.reject_follow(&owner, &requester)
|
||||||
|
.await?;
|
||||||
|
DomainEvent::FollowRejected { owner, requester }
|
||||||
|
}
|
||||||
|
SocialCmd::RemoveFollower { owner_id, follower } => {
|
||||||
|
let owner = UserId::from_uuid(owner_id);
|
||||||
|
deps.social_command
|
||||||
|
.remove_follower(&owner, &follower)
|
||||||
|
.await?;
|
||||||
|
DomainEvent::FollowerRemoved { owner, follower }
|
||||||
|
}
|
||||||
|
SocialCmd::Block {
|
||||||
|
blocker_id,
|
||||||
|
target,
|
||||||
|
} => {
|
||||||
|
let blocker = UserId::from_uuid(blocker_id);
|
||||||
|
deps.social_command.block(&blocker, &target).await?;
|
||||||
|
DomainEvent::ActorBlocked { blocker, target }
|
||||||
|
}
|
||||||
|
SocialCmd::Unblock {
|
||||||
|
blocker_id,
|
||||||
|
target,
|
||||||
|
} => {
|
||||||
|
let blocker = UserId::from_uuid(blocker_id);
|
||||||
|
deps.social_command.unblock(&blocker, &target).await?;
|
||||||
|
DomainEvent::ActorUnblocked { blocker, target }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deps.event_publisher.publish(&event).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute_query(
|
||||||
|
deps: &SocialQueryDeps,
|
||||||
|
query: SocialQry,
|
||||||
|
) -> Result<Vec<SocialActor>, DomainError> {
|
||||||
|
let user_id = match &query {
|
||||||
|
SocialQry::GetFollowing { user_id }
|
||||||
|
| SocialQry::GetFollowers { user_id }
|
||||||
|
| SocialQry::GetPending { user_id }
|
||||||
|
| SocialQry::GetBlocked { user_id } => UserId::from_uuid(*user_id),
|
||||||
|
};
|
||||||
|
match query {
|
||||||
|
SocialQry::GetFollowing { .. } => deps.social_query.get_following(&user_id).await,
|
||||||
|
SocialQry::GetFollowers { .. } => deps.social_query.get_followers(&user_id).await,
|
||||||
|
SocialQry::GetPending { .. } => deps.social_query.get_pending_followers(&user_id).await,
|
||||||
|
SocialQry::GetBlocked { .. } => deps.social_query.get_blocked(&user_id).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "tests/execute.rs"]
|
||||||
|
mod tests;
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::FollowCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(deps: &SocialCommandDeps, cmd: FollowCommand) -> Result<(), DomainError> {
|
|
||||||
let follower = UserId::from_uuid(cmd.follower_id);
|
|
||||||
deps.social_command.follow(&follower, &cmd.target).await?;
|
|
||||||
deps.event_publisher
|
|
||||||
.publish(&DomainEvent::FollowRequested {
|
|
||||||
follower,
|
|
||||||
target: cmd.target,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/follow.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
use domain::{
|
|
||||||
errors::DomainError,
|
|
||||||
value_objects::{SocialActor, UserId},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{deps::SocialQueryDeps, queries::GetBlockedQuery};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialQueryDeps,
|
|
||||||
query: GetBlockedQuery,
|
|
||||||
) -> Result<Vec<SocialActor>, DomainError> {
|
|
||||||
let user_id = UserId::from_uuid(query.user_id);
|
|
||||||
deps.social_query.get_blocked(&user_id).await
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{
|
|
||||||
errors::DomainError,
|
|
||||||
value_objects::{SocialActor, UserId},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{deps::SocialQueryDeps, queries::GetFollowersQuery};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialQueryDeps,
|
|
||||||
query: GetFollowersQuery,
|
|
||||||
) -> Result<Vec<SocialActor>, DomainError> {
|
|
||||||
let user_id = UserId::from_uuid(query.user_id);
|
|
||||||
deps.social_query.get_followers(&user_id).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/get_followers.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{
|
|
||||||
errors::DomainError,
|
|
||||||
value_objects::{SocialActor, UserId},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{deps::SocialQueryDeps, queries::GetFollowingQuery};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialQueryDeps,
|
|
||||||
query: GetFollowingQuery,
|
|
||||||
) -> Result<Vec<SocialActor>, DomainError> {
|
|
||||||
let user_id = UserId::from_uuid(query.user_id);
|
|
||||||
deps.social_query.get_following(&user_id).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/get_following.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{
|
|
||||||
errors::DomainError,
|
|
||||||
value_objects::{SocialActor, UserId},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{deps::SocialQueryDeps, queries::GetPendingFollowersQuery};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialQueryDeps,
|
|
||||||
query: GetPendingFollowersQuery,
|
|
||||||
) -> Result<Vec<SocialActor>, DomainError> {
|
|
||||||
let user_id = UserId::from_uuid(query.user_id);
|
|
||||||
deps.social_query.get_pending_followers(&user_id).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/get_pending.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,15 +1,4 @@
|
|||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod deps;
|
pub mod deps;
|
||||||
|
pub mod execute;
|
||||||
pub mod queries;
|
pub mod queries;
|
||||||
|
|
||||||
pub mod accept;
|
|
||||||
pub mod block;
|
|
||||||
pub mod follow;
|
|
||||||
pub mod get_blocked;
|
|
||||||
pub mod get_followers;
|
|
||||||
pub mod get_following;
|
|
||||||
pub mod get_pending;
|
|
||||||
pub mod reject;
|
|
||||||
pub mod remove_follower;
|
|
||||||
pub mod unblock;
|
|
||||||
pub mod unfollow;
|
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub struct GetFollowingQuery {
|
pub enum SocialQry {
|
||||||
pub user_id: Uuid,
|
GetFollowing { user_id: Uuid },
|
||||||
}
|
GetFollowers { user_id: Uuid },
|
||||||
|
GetPending { user_id: Uuid },
|
||||||
pub struct GetFollowersQuery {
|
GetBlocked { user_id: Uuid },
|
||||||
pub user_id: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GetPendingFollowersQuery {
|
|
||||||
pub user_id: Uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GetBlockedQuery {
|
|
||||||
pub user_id: Uuid,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
use domain::{errors::DomainError, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::RejectFollowCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialCommandDeps,
|
|
||||||
cmd: RejectFollowCommand,
|
|
||||||
) -> Result<(), DomainError> {
|
|
||||||
let owner = UserId::from_uuid(cmd.owner_id);
|
|
||||||
deps.social_command
|
|
||||||
.reject_follow(&owner, &cmd.requester)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/reject.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::RemoveFollowerCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
deps: &SocialCommandDeps,
|
|
||||||
cmd: RemoveFollowerCommand,
|
|
||||||
) -> Result<(), DomainError> {
|
|
||||||
let owner = UserId::from_uuid(cmd.owner_id);
|
|
||||||
deps.social_command
|
|
||||||
.remove_follower(&owner, &cmd.follower)
|
|
||||||
.await?;
|
|
||||||
deps.event_publisher
|
|
||||||
.publish(&DomainEvent::FollowerRemoved {
|
|
||||||
owner,
|
|
||||||
follower: cmd.follower,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/remove_follower.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
events::DomainEvent,
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
accept,
|
|
||||||
commands::{AcceptFollowCommand, FollowCommand},
|
|
||||||
deps::SocialCommandDeps,
|
|
||||||
follow,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn accept_follow_emits_follow_accepted_event() {
|
|
||||||
let (_social, events, deps) = make_deps();
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let owner_id = Uuid::new_v4();
|
|
||||||
let requester = SocialIdentity::Local(UserId::from_uuid(follower_id));
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
accept::execute(
|
|
||||||
&deps,
|
|
||||||
AcceptFollowCommand {
|
|
||||||
owner_id,
|
|
||||||
requester,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let published = events.published();
|
|
||||||
assert!(
|
|
||||||
published
|
|
||||||
.iter()
|
|
||||||
.any(|e| matches!(e, DomainEvent::FollowAccepted { .. }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
events::DomainEvent,
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{block, commands::BlockCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn block_emits_actor_blocked_event() {
|
|
||||||
let (_social, events, deps) = make_deps();
|
|
||||||
|
|
||||||
block::execute(
|
|
||||||
&deps,
|
|
||||||
BlockCommand {
|
|
||||||
blocker_id: Uuid::new_v4(),
|
|
||||||
target: SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4())),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let published = events.published();
|
|
||||||
assert!(
|
|
||||||
published
|
|
||||||
.iter()
|
|
||||||
.any(|e| matches!(e, DomainEvent::ActorBlocked { .. }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
449
crates/application/src/social/tests/execute.rs
Normal file
449
crates/application/src/social/tests/execute.rs
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use domain::{
|
||||||
|
events::DomainEvent,
|
||||||
|
testing::{InMemorySocialRepository, NoopEventPublisher},
|
||||||
|
value_objects::{FollowTarget, SocialIdentity, UserId},
|
||||||
|
};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::social::{
|
||||||
|
commands::SocialCmd,
|
||||||
|
deps::{SocialCommandDeps, SocialQueryDeps},
|
||||||
|
execute::{execute_command, execute_query},
|
||||||
|
queries::SocialQry,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn make_cmd_deps() -> (
|
||||||
|
Arc<InMemorySocialRepository>,
|
||||||
|
Arc<NoopEventPublisher>,
|
||||||
|
SocialCommandDeps,
|
||||||
|
) {
|
||||||
|
let social = InMemorySocialRepository::new();
|
||||||
|
let events = NoopEventPublisher::new();
|
||||||
|
let deps = SocialCommandDeps {
|
||||||
|
social_command: Arc::clone(&social) as _,
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
event_publisher: Arc::clone(&events) as _,
|
||||||
|
};
|
||||||
|
(social, events, deps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Follow ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn follow_emits_follow_requested_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id: Uuid::new_v4(),
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(
|
||||||
|
Uuid::new_v4(),
|
||||||
|
))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::FollowRequested { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn cannot_follow_yourself() {
|
||||||
|
let (_social, _events, deps) = make_cmd_deps();
|
||||||
|
let user_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
let result = execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id: user_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(user_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn cannot_follow_same_target_twice() {
|
||||||
|
let (_social, _events, deps) = make_cmd_deps();
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let target = FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4())));
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: target.clone(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result = execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Unfollow ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn unfollow_emits_unfollowed_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let target = SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()));
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(target.clone()),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Unfollow {
|
||||||
|
follower_id,
|
||||||
|
target,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::Unfollowed { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Accept ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn accept_follow_emits_follow_accepted_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let owner_id = Uuid::new_v4();
|
||||||
|
let requester = SocialIdentity::Local(UserId::from_uuid(follower_id));
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::AcceptFollow {
|
||||||
|
owner_id,
|
||||||
|
requester,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::FollowAccepted { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Reject ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn reject_follow_emits_follow_rejected_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let owner_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::RejectFollow {
|
||||||
|
owner_id,
|
||||||
|
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::FollowRejected { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Remove follower ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn remove_follower_emits_follower_removed_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let owner_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::AcceptFollow {
|
||||||
|
owner_id,
|
||||||
|
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::RemoveFollower {
|
||||||
|
owner_id,
|
||||||
|
follower: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::FollowerRemoved { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Block ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn block_emits_actor_blocked_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Block {
|
||||||
|
blocker_id: Uuid::new_v4(),
|
||||||
|
target: SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4())),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::ActorBlocked { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Unblock ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn unblock_emits_actor_unblocked_event() {
|
||||||
|
let (_social, events, deps) = make_cmd_deps();
|
||||||
|
let target = SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()));
|
||||||
|
let blocker_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&deps,
|
||||||
|
SocialCmd::Block {
|
||||||
|
blocker_id,
|
||||||
|
target: target.clone(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(&deps, SocialCmd::Unblock { blocker_id, target })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let published = events.published();
|
||||||
|
assert!(
|
||||||
|
published
|
||||||
|
.iter()
|
||||||
|
.any(|e| matches!(e, DomainEvent::ActorUnblocked { .. }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Get following ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn returns_accepted_follows() {
|
||||||
|
let social = InMemorySocialRepository::new();
|
||||||
|
let events = NoopEventPublisher::new();
|
||||||
|
let cmd_deps = SocialCommandDeps {
|
||||||
|
social_command: Arc::clone(&social) as _,
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
event_publisher: Arc::clone(&events) as _,
|
||||||
|
};
|
||||||
|
let query_deps = SocialQueryDeps {
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
};
|
||||||
|
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let target_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&cmd_deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(target_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Pending follow should not appear
|
||||||
|
let following = execute_query(
|
||||||
|
&query_deps,
|
||||||
|
SocialQry::GetFollowing {
|
||||||
|
user_id: follower_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(following.is_empty());
|
||||||
|
|
||||||
|
// Accept, then it should appear
|
||||||
|
execute_command(
|
||||||
|
&cmd_deps,
|
||||||
|
SocialCmd::AcceptFollow {
|
||||||
|
owner_id: target_id,
|
||||||
|
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let following = execute_query(
|
||||||
|
&query_deps,
|
||||||
|
SocialQry::GetFollowing {
|
||||||
|
user_id: follower_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(following.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Get followers ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn returns_accepted_followers() {
|
||||||
|
let social = InMemorySocialRepository::new();
|
||||||
|
let events = NoopEventPublisher::new();
|
||||||
|
let cmd_deps = SocialCommandDeps {
|
||||||
|
social_command: Arc::clone(&social) as _,
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
event_publisher: Arc::clone(&events) as _,
|
||||||
|
};
|
||||||
|
let query_deps = SocialQueryDeps {
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
};
|
||||||
|
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let owner_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&cmd_deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&cmd_deps,
|
||||||
|
SocialCmd::AcceptFollow {
|
||||||
|
owner_id,
|
||||||
|
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let followers = execute_query(&query_deps, SocialQry::GetFollowers { user_id: owner_id })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(followers.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Get pending ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn returns_only_pending_followers() {
|
||||||
|
let social = InMemorySocialRepository::new();
|
||||||
|
let events = NoopEventPublisher::new();
|
||||||
|
let cmd_deps = SocialCommandDeps {
|
||||||
|
social_command: Arc::clone(&social) as _,
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
event_publisher: Arc::clone(&events) as _,
|
||||||
|
};
|
||||||
|
let query_deps = SocialQueryDeps {
|
||||||
|
social_query: Arc::clone(&social) as _,
|
||||||
|
};
|
||||||
|
|
||||||
|
let follower_id = Uuid::new_v4();
|
||||||
|
let owner_id = Uuid::new_v4();
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
&cmd_deps,
|
||||||
|
SocialCmd::Follow {
|
||||||
|
follower_id,
|
||||||
|
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let pending = execute_query(&query_deps, SocialQry::GetPending { user_id: owner_id })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(pending.len(), 1);
|
||||||
|
}
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
events::DomainEvent,
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{commands::FollowCommand, deps::SocialCommandDeps, follow};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn follow_emits_follow_requested_event() {
|
|
||||||
let (_social, events, deps) = make_deps();
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id: Uuid::new_v4(),
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let published = events.published();
|
|
||||||
assert!(
|
|
||||||
published
|
|
||||||
.iter()
|
|
||||||
.any(|e| matches!(e, DomainEvent::FollowRequested { .. }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn cannot_follow_yourself() {
|
|
||||||
let (_social, _events, deps) = make_deps();
|
|
||||||
let user_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
let result = follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id: user_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(user_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(result.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn cannot_follow_same_target_twice() {
|
|
||||||
let (_social, _events, deps) = make_deps();
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let target = FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4())));
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: target.clone(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let result = follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(result.is_err());
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
accept,
|
|
||||||
commands::{AcceptFollowCommand, FollowCommand},
|
|
||||||
deps::{SocialCommandDeps, SocialQueryDeps},
|
|
||||||
follow, get_followers,
|
|
||||||
queries::GetFollowersQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn returns_accepted_followers() {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let cmd_deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
let query_deps = SocialQueryDeps {
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
};
|
|
||||||
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let owner_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&cmd_deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
accept::execute(
|
|
||||||
&cmd_deps,
|
|
||||||
AcceptFollowCommand {
|
|
||||||
owner_id,
|
|
||||||
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let followers = get_followers::execute(&query_deps, GetFollowersQuery { user_id: owner_id })
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(followers.len(), 1);
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
accept,
|
|
||||||
commands::{AcceptFollowCommand, FollowCommand},
|
|
||||||
deps::{SocialCommandDeps, SocialQueryDeps},
|
|
||||||
follow, get_following,
|
|
||||||
queries::GetFollowingQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn returns_accepted_follows() {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let cmd_deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
let query_deps = SocialQueryDeps {
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
};
|
|
||||||
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let target_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&cmd_deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(target_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Pending follow should not appear
|
|
||||||
let following = get_following::execute(
|
|
||||||
&query_deps,
|
|
||||||
GetFollowingQuery {
|
|
||||||
user_id: follower_id,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert!(following.is_empty());
|
|
||||||
|
|
||||||
// Accept, then it should appear
|
|
||||||
accept::execute(
|
|
||||||
&cmd_deps,
|
|
||||||
AcceptFollowCommand {
|
|
||||||
owner_id: target_id,
|
|
||||||
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let following = get_following::execute(
|
|
||||||
&query_deps,
|
|
||||||
GetFollowingQuery {
|
|
||||||
user_id: follower_id,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(following.len(), 1);
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
commands::FollowCommand,
|
|
||||||
deps::{SocialCommandDeps, SocialQueryDeps},
|
|
||||||
follow, get_pending,
|
|
||||||
queries::GetPendingFollowersQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn returns_only_pending_followers() {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let cmd_deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
let query_deps = SocialQueryDeps {
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
};
|
|
||||||
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let owner_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&cmd_deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let pending = get_pending::execute(&query_deps, GetPendingFollowersQuery { user_id: owner_id })
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(pending.len(), 1);
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
commands::{FollowCommand, RejectFollowCommand},
|
|
||||||
deps::SocialCommandDeps,
|
|
||||||
follow, reject,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn reject_follow_completes_without_error() {
|
|
||||||
let (_social, _events, deps) = make_deps();
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let owner_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
reject::execute(
|
|
||||||
&deps,
|
|
||||||
RejectFollowCommand {
|
|
||||||
owner_id,
|
|
||||||
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
events::DomainEvent,
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
accept,
|
|
||||||
commands::{AcceptFollowCommand, FollowCommand, RemoveFollowerCommand},
|
|
||||||
deps::SocialCommandDeps,
|
|
||||||
follow, remove_follower,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn remove_follower_emits_follower_removed_event() {
|
|
||||||
let (_social, events, deps) = make_deps();
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let owner_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
accept::execute(
|
|
||||||
&deps,
|
|
||||||
AcceptFollowCommand {
|
|
||||||
owner_id,
|
|
||||||
requester: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
remove_follower::execute(
|
|
||||||
&deps,
|
|
||||||
RemoveFollowerCommand {
|
|
||||||
owner_id,
|
|
||||||
follower: SocialIdentity::Local(UserId::from_uuid(follower_id)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let published = events.published();
|
|
||||||
assert!(
|
|
||||||
published
|
|
||||||
.iter()
|
|
||||||
.any(|e| matches!(e, DomainEvent::FollowerRemoved { .. }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
events::DomainEvent,
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
block,
|
|
||||||
commands::{BlockCommand, UnblockCommand},
|
|
||||||
deps::SocialCommandDeps,
|
|
||||||
unblock,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn unblock_emits_actor_unblocked_event() {
|
|
||||||
let (_social, events, deps) = make_deps();
|
|
||||||
let target = SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()));
|
|
||||||
let blocker_id = Uuid::new_v4();
|
|
||||||
|
|
||||||
block::execute(
|
|
||||||
&deps,
|
|
||||||
BlockCommand {
|
|
||||||
blocker_id,
|
|
||||||
target: target.clone(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
unblock::execute(&deps, UnblockCommand { blocker_id, target })
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let published = events.published();
|
|
||||||
assert!(
|
|
||||||
published
|
|
||||||
.iter()
|
|
||||||
.any(|e| matches!(e, DomainEvent::ActorUnblocked { .. }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use domain::{
|
|
||||||
events::DomainEvent,
|
|
||||||
testing::{InMemorySocialRepository, NoopEventPublisher},
|
|
||||||
value_objects::{FollowTarget, SocialIdentity, UserId},
|
|
||||||
};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::social::{
|
|
||||||
commands::{FollowCommand, UnfollowCommand},
|
|
||||||
deps::SocialCommandDeps,
|
|
||||||
follow, unfollow,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn make_deps() -> (
|
|
||||||
Arc<InMemorySocialRepository>,
|
|
||||||
Arc<NoopEventPublisher>,
|
|
||||||
SocialCommandDeps,
|
|
||||||
) {
|
|
||||||
let social = InMemorySocialRepository::new();
|
|
||||||
let events = NoopEventPublisher::new();
|
|
||||||
let deps = SocialCommandDeps {
|
|
||||||
social_command: Arc::clone(&social) as _,
|
|
||||||
social_query: Arc::clone(&social) as _,
|
|
||||||
event_publisher: Arc::clone(&events) as _,
|
|
||||||
};
|
|
||||||
(social, events, deps)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn unfollow_emits_unfollowed_event() {
|
|
||||||
let (_social, events, deps) = make_deps();
|
|
||||||
let follower_id = Uuid::new_v4();
|
|
||||||
let target = SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()));
|
|
||||||
|
|
||||||
follow::execute(
|
|
||||||
&deps,
|
|
||||||
FollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target: FollowTarget::Identity(target.clone()),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
unfollow::execute(
|
|
||||||
&deps,
|
|
||||||
UnfollowCommand {
|
|
||||||
follower_id,
|
|
||||||
target,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let published = events.published();
|
|
||||||
assert!(
|
|
||||||
published
|
|
||||||
.iter()
|
|
||||||
.any(|e| matches!(e, DomainEvent::Unfollowed { .. }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::UnblockCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(deps: &SocialCommandDeps, cmd: UnblockCommand) -> Result<(), DomainError> {
|
|
||||||
let blocker = UserId::from_uuid(cmd.blocker_id);
|
|
||||||
deps.social_command.unblock(&blocker, &cmd.target).await?;
|
|
||||||
deps.event_publisher
|
|
||||||
.publish(&DomainEvent::ActorUnblocked {
|
|
||||||
blocker,
|
|
||||||
target: cmd.target,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/unblock.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
|
||||||
|
|
||||||
use super::{commands::UnfollowCommand, deps::SocialCommandDeps};
|
|
||||||
|
|
||||||
pub async fn execute(deps: &SocialCommandDeps, cmd: UnfollowCommand) -> Result<(), DomainError> {
|
|
||||||
let follower = UserId::from_uuid(cmd.follower_id);
|
|
||||||
deps.social_command.unfollow(&follower, &cmd.target).await?;
|
|
||||||
deps.event_publisher
|
|
||||||
.publish(&DomainEvent::Unfollowed {
|
|
||||||
follower,
|
|
||||||
target: cmd.target,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[path = "tests/unfollow.rs"]
|
|
||||||
mod tests;
|
|
||||||
@@ -74,6 +74,7 @@ impl EventHandler for RecordingHandler {
|
|||||||
}
|
}
|
||||||
DomainEvent::FollowRequested { .. } => "follow_requested",
|
DomainEvent::FollowRequested { .. } => "follow_requested",
|
||||||
DomainEvent::FollowAccepted { .. } => "follow_accepted",
|
DomainEvent::FollowAccepted { .. } => "follow_accepted",
|
||||||
|
DomainEvent::FollowRejected { .. } => "follow_rejected",
|
||||||
DomainEvent::Unfollowed { .. } => "unfollowed",
|
DomainEvent::Unfollowed { .. } => "unfollowed",
|
||||||
DomainEvent::FollowerRemoved { .. } => "follower_removed",
|
DomainEvent::FollowerRemoved { .. } => "follower_removed",
|
||||||
DomainEvent::ActorBlocked { .. } => "actor_blocked",
|
DomainEvent::ActorBlocked { .. } => "actor_blocked",
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ pub enum DomainEvent {
|
|||||||
owner: UserId,
|
owner: UserId,
|
||||||
requester: crate::value_objects::SocialIdentity,
|
requester: crate::value_objects::SocialIdentity,
|
||||||
},
|
},
|
||||||
|
FollowRejected {
|
||||||
|
owner: UserId,
|
||||||
|
requester: crate::value_objects::SocialIdentity,
|
||||||
|
},
|
||||||
Unfollowed {
|
Unfollowed {
|
||||||
follower: UserId,
|
follower: UserId,
|
||||||
target: crate::value_objects::SocialIdentity,
|
target: crate::value_objects::SocialIdentity,
|
||||||
|
|||||||
@@ -171,9 +171,9 @@ pub async fn block_actor_api(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::block::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::BlockCommand {
|
application::social::commands::SocialCmd::Block {
|
||||||
blocker_id: user.0.value(),
|
blocker_id: user.0.value(),
|
||||||
target: SocialIdentity::Remote {
|
target: SocialIdentity::Remote {
|
||||||
actor_url: body.actor_url,
|
actor_url: body.actor_url,
|
||||||
@@ -203,9 +203,9 @@ pub async fn unblock_actor_api(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::unblock::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::UnblockCommand {
|
application::social::commands::SocialCmd::Unblock {
|
||||||
blocker_id: user.0.value(),
|
blocker_id: user.0.value(),
|
||||||
target: SocialIdentity::Remote {
|
target: SocialIdentity::Remote {
|
||||||
actor_url: body.actor_url,
|
actor_url: body.actor_url,
|
||||||
@@ -231,9 +231,9 @@ pub async fn get_blocked_actors_api(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
let identities = application::social::get_blocked::execute(
|
let identities = application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetBlockedQuery {
|
application::social::queries::SocialQry::GetBlocked {
|
||||||
user_id: user.0.value(),
|
user_id: user.0.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -261,9 +261,9 @@ pub async fn get_following(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
let identities = application::social::get_following::execute(
|
let identities = application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetFollowingQuery {
|
application::social::queries::SocialQry::GetFollowing {
|
||||||
user_id: user.0.value(),
|
user_id: user.0.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -288,9 +288,9 @@ pub async fn get_followers(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
let identities = application::social::get_followers::execute(
|
let identities = application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetFollowersQuery {
|
application::social::queries::SocialQry::GetFollowers {
|
||||||
user_id: user.0.value(),
|
user_id: user.0.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -308,9 +308,9 @@ pub async fn get_user_following(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
let identities = application::social::get_following::execute(
|
let identities = application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetFollowingQuery { user_id },
|
application::social::queries::SocialQry::GetFollowing { user_id },
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Json(ActorListResponse {
|
Ok(Json(ActorListResponse {
|
||||||
@@ -326,9 +326,9 @@ pub async fn get_user_followers(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
let identities = application::social::get_followers::execute(
|
let identities = application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetFollowersQuery { user_id },
|
application::social::queries::SocialQry::GetFollowers { user_id },
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Json(ActorListResponse {
|
Ok(Json(ActorListResponse {
|
||||||
@@ -355,9 +355,9 @@ pub async fn follow(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::follow::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::FollowCommand {
|
application::social::commands::SocialCmd::Follow {
|
||||||
follower_id: user.0.value(),
|
follower_id: user.0.value(),
|
||||||
target: FollowTarget::Handle(body.handle),
|
target: FollowTarget::Handle(body.handle),
|
||||||
},
|
},
|
||||||
@@ -385,9 +385,9 @@ pub async fn unfollow(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::unfollow::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::UnfollowCommand {
|
application::social::commands::SocialCmd::Unfollow {
|
||||||
follower_id: user.0.value(),
|
follower_id: user.0.value(),
|
||||||
target: SocialIdentity::Remote {
|
target: SocialIdentity::Remote {
|
||||||
actor_url: body.actor_url,
|
actor_url: body.actor_url,
|
||||||
@@ -417,9 +417,9 @@ pub async fn accept_follower(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::accept::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::AcceptFollowCommand {
|
application::social::commands::SocialCmd::AcceptFollow {
|
||||||
owner_id: user.0.value(),
|
owner_id: user.0.value(),
|
||||||
requester: SocialIdentity::Remote {
|
requester: SocialIdentity::Remote {
|
||||||
actor_url: body.actor_url,
|
actor_url: body.actor_url,
|
||||||
@@ -449,9 +449,9 @@ pub async fn reject_follower(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::reject::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::RejectFollowCommand {
|
application::social::commands::SocialCmd::RejectFollow {
|
||||||
owner_id: user.0.value(),
|
owner_id: user.0.value(),
|
||||||
requester: SocialIdentity::Remote {
|
requester: SocialIdentity::Remote {
|
||||||
actor_url: body.actor_url,
|
actor_url: body.actor_url,
|
||||||
@@ -481,9 +481,9 @@ pub async fn remove_follower(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
application::social::remove_follower::execute(
|
application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::RemoveFollowerCommand {
|
application::social::commands::SocialCmd::RemoveFollower {
|
||||||
owner_id: user.0.value(),
|
owner_id: user.0.value(),
|
||||||
follower: SocialIdentity::Remote {
|
follower: SocialIdentity::Remote {
|
||||||
actor_url: body.actor_url,
|
actor_url: body.actor_url,
|
||||||
@@ -509,9 +509,9 @@ pub async fn get_pending_followers(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
let identities = application::social::get_pending::execute(
|
let identities = application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetPendingFollowersQuery {
|
application::social::queries::SocialQry::GetPending {
|
||||||
user_id: user.0.value(),
|
user_id: user.0.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -548,9 +548,9 @@ pub async fn follow_remote_user(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::follow::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::FollowCommand {
|
application::social::commands::SocialCmd::Follow {
|
||||||
follower_id: user_id.value(),
|
follower_id: user_id.value(),
|
||||||
target: FollowTarget::Handle(form.handle),
|
target: FollowTarget::Handle(form.handle),
|
||||||
},
|
},
|
||||||
@@ -589,9 +589,9 @@ pub async fn unfollow_remote_user(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::unfollow::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::UnfollowCommand {
|
application::social::commands::SocialCmd::Unfollow {
|
||||||
follower_id: user_id.value(),
|
follower_id: user_id.value(),
|
||||||
target: SocialIdentity::Remote {
|
target: SocialIdentity::Remote {
|
||||||
actor_url: form.actor_url,
|
actor_url: form.actor_url,
|
||||||
@@ -632,9 +632,9 @@ pub async fn accept_follower_html(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::accept::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::AcceptFollowCommand {
|
application::social::commands::SocialCmd::AcceptFollow {
|
||||||
owner_id: user_id.value(),
|
owner_id: user_id.value(),
|
||||||
requester: SocialIdentity::Remote {
|
requester: SocialIdentity::Remote {
|
||||||
actor_url: form.actor_url,
|
actor_url: form.actor_url,
|
||||||
@@ -669,9 +669,9 @@ pub async fn reject_follower_html(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::reject::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::RejectFollowCommand {
|
application::social::commands::SocialCmd::RejectFollow {
|
||||||
owner_id: user_id.value(),
|
owner_id: user_id.value(),
|
||||||
requester: SocialIdentity::Remote {
|
requester: SocialIdentity::Remote {
|
||||||
actor_url: form.actor_url,
|
actor_url: form.actor_url,
|
||||||
@@ -773,9 +773,9 @@ pub async fn get_following_page(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
match application::social::get_following::execute(
|
match application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetFollowingQuery {
|
application::social::queries::SocialQry::GetFollowing {
|
||||||
user_id: user_id.value(),
|
user_id: user_id.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -824,9 +824,9 @@ pub async fn get_followers_page(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
match application::social::get_followers::execute(
|
match application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetFollowersQuery {
|
application::social::queries::SocialQry::GetFollowers {
|
||||||
user_id: user_id.value(),
|
user_id: user_id.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -874,9 +874,9 @@ pub async fn remove_follower_html(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::remove_follower::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::RemoveFollowerCommand {
|
application::social::commands::SocialCmd::RemoveFollower {
|
||||||
owner_id: user_id.value(),
|
owner_id: user_id.value(),
|
||||||
follower: SocialIdentity::Remote {
|
follower: SocialIdentity::Remote {
|
||||||
actor_url: form.actor_url,
|
actor_url: form.actor_url,
|
||||||
@@ -1000,9 +1000,9 @@ pub async fn get_blocked_actors_page(
|
|||||||
let deps = SocialQueryDeps {
|
let deps = SocialQueryDeps {
|
||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
};
|
};
|
||||||
match application::social::get_blocked::execute(
|
match application::social::execute::execute_query(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::queries::GetBlockedQuery {
|
application::social::queries::SocialQry::GetBlocked {
|
||||||
user_id: user_id.value(),
|
user_id: user_id.value(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -1049,9 +1049,9 @@ pub async fn post_block_actor_html(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::block::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::BlockCommand {
|
application::social::commands::SocialCmd::Block {
|
||||||
blocker_id: user_id.value(),
|
blocker_id: user_id.value(),
|
||||||
target: SocialIdentity::Remote {
|
target: SocialIdentity::Remote {
|
||||||
actor_url: form.actor_url,
|
actor_url: form.actor_url,
|
||||||
@@ -1082,9 +1082,9 @@ pub async fn post_unblock_actor(
|
|||||||
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
social_query: state.app_ctx.repos.social_query_unified.clone(),
|
||||||
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
};
|
};
|
||||||
match application::social::unblock::execute(
|
match application::social::execute::execute_command(
|
||||||
&deps,
|
&deps,
|
||||||
application::social::commands::UnblockCommand {
|
application::social::commands::SocialCmd::Unblock {
|
||||||
blocker_id: user_id.value(),
|
blocker_id: user_id.value(),
|
||||||
target: SocialIdentity::Remote {
|
target: SocialIdentity::Remote {
|
||||||
actor_url: form.actor_url,
|
actor_url: form.actor_url,
|
||||||
|
|||||||
Reference in New Issue
Block a user