fix: FollowTarget enum — actor_url no longer lies about holding a handle

FollowCommand.target is now FollowTarget (Identity|Handle) instead of
SocialIdentity. actor_url field always holds a URL; handles go through
FollowTarget::Handle. Adapter resolves handles explicitly. Type system
prevents misuse in future commands.
This commit is contained in:
2026-07-10 16:18:57 +02:00
parent 2484f1e603
commit d60c47199c
18 changed files with 95 additions and 45 deletions

View File

@@ -1,9 +1,9 @@
use domain::value_objects::SocialIdentity;
use domain::value_objects::{FollowTarget, SocialIdentity};
use uuid::Uuid;
pub struct FollowCommand {
pub follower_id: Uuid,
pub target: SocialIdentity,
pub target: FollowTarget,
}
pub struct UnfollowCommand {

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::{
events::DomainEvent,
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -40,7 +40,7 @@ async fn accept_follow_emits_follow_accepted_event() {
&deps,
FollowCommand {
follower_id,
target: SocialIdentity::Local(UserId::from_uuid(owner_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
},
)
.await

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::{
events::DomainEvent,
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -32,7 +32,7 @@ async fn follow_emits_follow_requested_event() {
&deps,
FollowCommand {
follower_id: Uuid::new_v4(),
target: SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4())),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()))),
},
)
.await
@@ -55,7 +55,7 @@ async fn cannot_follow_yourself() {
&deps,
FollowCommand {
follower_id: user_id,
target: SocialIdentity::Local(UserId::from_uuid(user_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(user_id))),
},
)
.await;
@@ -67,7 +67,7 @@ async fn cannot_follow_yourself() {
async fn cannot_follow_same_target_twice() {
let (_social, _events, deps) = make_deps();
let follower_id = Uuid::new_v4();
let target = SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4()));
let target = FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(Uuid::new_v4())));
follow::execute(
&deps,

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::{
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -34,7 +34,7 @@ async fn returns_accepted_followers() {
&cmd_deps,
FollowCommand {
follower_id,
target: SocialIdentity::Local(UserId::from_uuid(owner_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
},
)
.await

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::{
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -34,7 +34,7 @@ async fn returns_accepted_follows() {
&cmd_deps,
FollowCommand {
follower_id,
target: SocialIdentity::Local(UserId::from_uuid(target_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(target_id))),
},
)
.await

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::{
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -33,7 +33,7 @@ async fn returns_only_pending_followers() {
&cmd_deps,
FollowCommand {
follower_id,
target: SocialIdentity::Local(UserId::from_uuid(owner_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
},
)
.await

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::{
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -37,7 +37,7 @@ async fn reject_follow_completes_without_error() {
&deps,
FollowCommand {
follower_id,
target: SocialIdentity::Local(UserId::from_uuid(owner_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
},
)
.await

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::{
events::DomainEvent,
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -39,7 +39,7 @@ async fn remove_follower_emits_follower_removed_event() {
&deps,
FollowCommand {
follower_id,
target: SocialIdentity::Local(UserId::from_uuid(owner_id)),
target: FollowTarget::Identity(SocialIdentity::Local(UserId::from_uuid(owner_id))),
},
)
.await

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::{
events::DomainEvent,
testing::{InMemorySocialRepository, NoopEventPublisher},
value_objects::{SocialIdentity, UserId},
value_objects::{FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -38,7 +38,7 @@ async fn unfollow_emits_unfollowed_event() {
&deps,
FollowCommand {
follower_id,
target: target.clone(),
target: FollowTarget::Identity(target.clone()),
},
)
.await