fmt
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
pub mod composite_handler;
|
||||
pub mod social_adapter;
|
||||
pub mod event_handler;
|
||||
pub mod federation_event_bridge;
|
||||
pub mod goal_handler;
|
||||
@@ -7,6 +6,7 @@ pub mod objects;
|
||||
pub mod port;
|
||||
pub mod remote_review_repository;
|
||||
pub mod review_handler;
|
||||
pub mod social_adapter;
|
||||
pub(crate) mod urls;
|
||||
pub mod user_adapter;
|
||||
pub mod watchlist_handler;
|
||||
|
||||
@@ -87,11 +87,7 @@ fn ap_err(e: anyhow::Error) -> DomainError {
|
||||
|
||||
#[async_trait]
|
||||
impl SocialCommand for CompositeSocialAdapter {
|
||||
async fn follow(
|
||||
&self,
|
||||
follower: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError> {
|
||||
async fn follow(&self, follower: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
|
||||
if let SocialIdentity::Local(target_id) = target
|
||||
&& follower == target_id
|
||||
{
|
||||
@@ -154,11 +150,7 @@ impl SocialCommand for CompositeSocialAdapter {
|
||||
.map_err(ap_err)
|
||||
}
|
||||
|
||||
async fn block(
|
||||
&self,
|
||||
blocker: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError> {
|
||||
async fn block(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
|
||||
let actor_url = self.actor_url_from_identity(target);
|
||||
self.ap_service
|
||||
.block_actor(blocker.value(), &actor_url)
|
||||
@@ -166,11 +158,7 @@ impl SocialCommand for CompositeSocialAdapter {
|
||||
.map_err(ap_err)
|
||||
}
|
||||
|
||||
async fn unblock(
|
||||
&self,
|
||||
blocker: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError> {
|
||||
async fn unblock(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
|
||||
let actor_url = self.actor_url_from_identity(target);
|
||||
self.ap_service
|
||||
.unblock_actor(blocker.value(), &actor_url)
|
||||
@@ -181,10 +169,7 @@ impl SocialCommand for CompositeSocialAdapter {
|
||||
|
||||
#[async_trait]
|
||||
impl SocialQuery for CompositeSocialAdapter {
|
||||
async fn get_following(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_following(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let actors = self
|
||||
.ap_service
|
||||
.get_following(user.value())
|
||||
@@ -196,10 +181,7 @@ impl SocialQuery for CompositeSocialAdapter {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn get_followers(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let actors = self
|
||||
.ap_service
|
||||
.get_accepted_followers(user.value())
|
||||
@@ -211,10 +193,7 @@ impl SocialQuery for CompositeSocialAdapter {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_pending_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let actors = self
|
||||
.ap_service
|
||||
.get_pending_followers(user.value())
|
||||
@@ -240,10 +219,7 @@ impl SocialQuery for CompositeSocialAdapter {
|
||||
.map_err(ap_err)
|
||||
}
|
||||
|
||||
async fn get_blocked(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_blocked(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let actors = self
|
||||
.ap_service
|
||||
.get_blocked_actors(user.value())
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
models::RemoteActorInfo,
|
||||
ports::FederationAdminQuery,
|
||||
};
|
||||
use domain::{errors::DomainError, models::RemoteActorInfo, ports::FederationAdminQuery};
|
||||
|
||||
use super::PostgresFederationRepository;
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
models::RemoteActorInfo,
|
||||
ports::FederationAdminQuery,
|
||||
};
|
||||
use domain::{errors::DomainError, models::RemoteActorInfo, ports::FederationAdminQuery};
|
||||
|
||||
use super::SqliteFederationRepository;
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use domain::{errors::DomainError, value_objects::{SocialActor, UserId}};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
value_objects::{SocialActor, UserId},
|
||||
};
|
||||
|
||||
use super::{deps::SocialQueryDeps, queries::GetBlockedQuery};
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use domain::{errors::DomainError, value_objects::{SocialActor, UserId}};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
value_objects::{SocialActor, UserId},
|
||||
};
|
||||
|
||||
use super::{deps::SocialQueryDeps, queries::GetFollowersQuery};
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use domain::{errors::DomainError, value_objects::{SocialActor, UserId}};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
value_objects::{SocialActor, UserId},
|
||||
};
|
||||
|
||||
use super::{deps::SocialQueryDeps, queries::GetFollowingQuery};
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use domain::{errors::DomainError, value_objects::{SocialActor, UserId}};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
value_objects::{SocialActor, UserId},
|
||||
};
|
||||
|
||||
use super::{deps::SocialQueryDeps, queries::GetPendingFollowersQuery};
|
||||
|
||||
|
||||
@@ -14,7 +14,11 @@ use crate::social::{
|
||||
follow,
|
||||
};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
@@ -53,7 +57,9 @@ async fn accept_follow_emits_follow_accepted_event() {
|
||||
.unwrap();
|
||||
|
||||
let published = events.published();
|
||||
assert!(published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::FollowAccepted { .. })));
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::FollowAccepted { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ use uuid::Uuid;
|
||||
|
||||
use crate::social::{block, commands::BlockCommand, deps::SocialCommandDeps};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
@@ -35,7 +39,9 @@ async fn block_emits_actor_blocked_event() {
|
||||
.unwrap();
|
||||
|
||||
let published = events.published();
|
||||
assert!(published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::ActorBlocked { .. })));
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::ActorBlocked { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ use uuid::Uuid;
|
||||
|
||||
use crate::social::{commands::FollowCommand, deps::SocialCommandDeps, follow};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
@@ -35,9 +39,11 @@ async fn follow_emits_follow_requested_event() {
|
||||
.unwrap();
|
||||
|
||||
let published = events.published();
|
||||
assert!(published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::FollowRequested { .. })));
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::FollowRequested { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -50,13 +50,8 @@ async fn returns_accepted_followers() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let followers = get_followers::execute(
|
||||
&query_deps,
|
||||
GetFollowersQuery {
|
||||
user_id: owner_id,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let followers = get_followers::execute(&query_deps, GetFollowersQuery { user_id: owner_id })
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(followers.len(), 1);
|
||||
}
|
||||
|
||||
@@ -39,13 +39,8 @@ async fn returns_only_pending_followers() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let pending = get_pending::execute(
|
||||
&query_deps,
|
||||
GetPendingFollowersQuery {
|
||||
user_id: owner_id,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let pending = get_pending::execute(&query_deps, GetPendingFollowersQuery { user_id: owner_id })
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(pending.len(), 1);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,11 @@ use crate::social::{
|
||||
follow, reject,
|
||||
};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
|
||||
@@ -14,7 +14,11 @@ use crate::social::{
|
||||
follow, remove_follower,
|
||||
};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
@@ -62,7 +66,9 @@ async fn remove_follower_emits_follower_removed_event() {
|
||||
.unwrap();
|
||||
|
||||
let published = events.published();
|
||||
assert!(published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::FollowerRemoved { .. })));
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::FollowerRemoved { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,17 @@ use domain::{
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::social::{
|
||||
block,
|
||||
commands::{BlockCommand, UnblockCommand},
|
||||
deps::SocialCommandDeps,
|
||||
block, unblock,
|
||||
unblock,
|
||||
};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
@@ -40,18 +45,14 @@ async fn unblock_emits_actor_unblocked_event() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
unblock::execute(
|
||||
&deps,
|
||||
UnblockCommand {
|
||||
blocker_id,
|
||||
target,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
unblock::execute(&deps, UnblockCommand { blocker_id, target })
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let published = events.published();
|
||||
assert!(published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::ActorUnblocked { .. })));
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::ActorUnblocked { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,11 @@ use crate::social::{
|
||||
follow, unfollow,
|
||||
};
|
||||
|
||||
fn make_deps() -> (Arc<InMemorySocialRepository>, Arc<NoopEventPublisher>, SocialCommandDeps) {
|
||||
fn make_deps() -> (
|
||||
Arc<InMemorySocialRepository>,
|
||||
Arc<NoopEventPublisher>,
|
||||
SocialCommandDeps,
|
||||
) {
|
||||
let social = InMemorySocialRepository::new();
|
||||
let events = NoopEventPublisher::new();
|
||||
let deps = SocialCommandDeps {
|
||||
@@ -51,7 +55,9 @@ async fn unfollow_emits_unfollowed_event() {
|
||||
.unwrap();
|
||||
|
||||
let published = events.published();
|
||||
assert!(published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::Unfollowed { .. })));
|
||||
assert!(
|
||||
published
|
||||
.iter()
|
||||
.any(|e| matches!(e, DomainEvent::Unfollowed { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ 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.social_command.unfollow(&follower, &cmd.target).await?;
|
||||
deps.event_publisher
|
||||
.publish(&DomainEvent::Unfollowed {
|
||||
follower,
|
||||
|
||||
@@ -4,8 +4,8 @@ use chrono::NaiveDateTime;
|
||||
use crate::{
|
||||
errors::DomainError,
|
||||
models::{
|
||||
DiaryEntry, FederationFlags, RemoteActorInfo, RemoteGoalEntry,
|
||||
RemoteWatchlistEntry, WatchlistWithMovie,
|
||||
DiaryEntry, FederationFlags, RemoteActorInfo, RemoteGoalEntry, RemoteWatchlistEntry,
|
||||
WatchlistWithMovie,
|
||||
},
|
||||
value_objects::{MovieId, SocialActor, SocialIdentity, UserId},
|
||||
};
|
||||
@@ -14,17 +14,10 @@ use crate::{
|
||||
|
||||
#[async_trait]
|
||||
pub trait SocialCommand: Send + Sync {
|
||||
async fn follow(
|
||||
&self,
|
||||
follower: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError>;
|
||||
async fn follow(&self, follower: &UserId, target: &SocialIdentity) -> Result<(), DomainError>;
|
||||
|
||||
async fn unfollow(
|
||||
&self,
|
||||
follower: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError>;
|
||||
async fn unfollow(&self, follower: &UserId, target: &SocialIdentity)
|
||||
-> Result<(), DomainError>;
|
||||
|
||||
async fn accept_follow(
|
||||
&self,
|
||||
@@ -44,44 +37,24 @@ pub trait SocialCommand: Send + Sync {
|
||||
follower: &SocialIdentity,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
async fn block(
|
||||
&self,
|
||||
blocker: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError>;
|
||||
async fn block(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError>;
|
||||
|
||||
async fn unblock(
|
||||
&self,
|
||||
blocker: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError>;
|
||||
async fn unblock(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait SocialQuery: Send + Sync {
|
||||
async fn get_following(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
async fn get_following(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn get_followers(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
async fn get_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
async fn get_pending_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn count_following(&self, user: &UserId) -> Result<usize, DomainError>;
|
||||
|
||||
async fn count_followers(&self, user: &UserId) -> Result<usize, DomainError>;
|
||||
|
||||
async fn get_blocked(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError>;
|
||||
async fn get_blocked(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError>;
|
||||
|
||||
async fn is_following(
|
||||
&self,
|
||||
@@ -93,7 +66,6 @@ pub trait SocialQuery: Send + Sync {
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<Vec<String>, DomainError>;
|
||||
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -893,11 +893,7 @@ impl InMemorySocialRepository {
|
||||
|
||||
#[async_trait]
|
||||
impl SocialCommand for InMemorySocialRepository {
|
||||
async fn follow(
|
||||
&self,
|
||||
follower: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError> {
|
||||
async fn follow(&self, follower: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
|
||||
if let SocialIdentity::Local(target_id) = target {
|
||||
if follower == target_id {
|
||||
return Err(DomainError::ValidationError(
|
||||
@@ -925,7 +921,9 @@ impl SocialCommand for InMemorySocialRepository {
|
||||
let before = store.len();
|
||||
store.retain(|(f, t, _)| !(*f == follower.value() && t == target));
|
||||
if store.len() == before {
|
||||
return Err(DomainError::NotFound("Follow relationship not found".into()));
|
||||
return Err(DomainError::NotFound(
|
||||
"Follow relationship not found".into(),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1008,11 +1006,7 @@ impl SocialCommand for InMemorySocialRepository {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn block(
|
||||
&self,
|
||||
blocker: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError> {
|
||||
async fn block(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
|
||||
let mut store = self.blocked.lock().unwrap();
|
||||
store.push((blocker.value(), target.clone()));
|
||||
// Also remove any existing follow relationships
|
||||
@@ -1021,11 +1015,7 @@ impl SocialCommand for InMemorySocialRepository {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn unblock(
|
||||
&self,
|
||||
blocker: &UserId,
|
||||
target: &SocialIdentity,
|
||||
) -> Result<(), DomainError> {
|
||||
async fn unblock(&self, blocker: &UserId, target: &SocialIdentity) -> Result<(), DomainError> {
|
||||
let mut store = self.blocked.lock().unwrap();
|
||||
store.retain(|(b, t)| !(*b == blocker.value() && t == target));
|
||||
Ok(())
|
||||
@@ -1034,10 +1024,7 @@ impl SocialCommand for InMemorySocialRepository {
|
||||
|
||||
#[async_trait]
|
||||
impl SocialQuery for InMemorySocialRepository {
|
||||
async fn get_following(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_following(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let store = self.follows.lock().unwrap();
|
||||
Ok(store
|
||||
.iter()
|
||||
@@ -1046,10 +1033,7 @@ impl SocialQuery for InMemorySocialRepository {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn get_followers(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let store = self.follows.lock().unwrap();
|
||||
let target = SocialIdentity::Local(user.clone());
|
||||
Ok(store
|
||||
@@ -1062,10 +1046,7 @@ impl SocialQuery for InMemorySocialRepository {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn get_pending_followers(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_pending_followers(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let store = self.follows.lock().unwrap();
|
||||
let target = SocialIdentity::Local(user.clone());
|
||||
Ok(store
|
||||
@@ -1095,10 +1076,7 @@ impl SocialQuery for InMemorySocialRepository {
|
||||
.count())
|
||||
}
|
||||
|
||||
async fn get_blocked(
|
||||
&self,
|
||||
user: &UserId,
|
||||
) -> Result<Vec<SocialActor>, DomainError> {
|
||||
async fn get_blocked(&self, user: &UserId) -> Result<Vec<SocialActor>, DomainError> {
|
||||
let store = self.blocked.lock().unwrap();
|
||||
Ok(store
|
||||
.iter()
|
||||
@@ -1113,9 +1091,9 @@ impl SocialQuery for InMemorySocialRepository {
|
||||
target: &SocialIdentity,
|
||||
) -> Result<bool, DomainError> {
|
||||
let store = self.follows.lock().unwrap();
|
||||
Ok(store
|
||||
.iter()
|
||||
.any(|(f, t, state)| *f == follower.value() && t == target && *state == FollowState::Accepted))
|
||||
Ok(store.iter().any(|(f, t, state)| {
|
||||
*f == follower.value() && t == target && *state == FollowState::Accepted
|
||||
}))
|
||||
}
|
||||
|
||||
async fn get_accepted_following_urls(
|
||||
|
||||
@@ -64,8 +64,8 @@ impl ObjectStorage for NoopObjectStorage {
|
||||
|
||||
// Re-export production noop types so test code that imports from
|
||||
// `domain::testing` keeps compiling without changes.
|
||||
pub use crate::ports::noop::NoopRemoteWatchlistRepository;
|
||||
pub use crate::ports::noop::NoopFederationAdminQuery;
|
||||
pub use crate::ports::noop::NoopRemoteWatchlistRepository;
|
||||
|
||||
// ── NoopGoalCommand ───────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::{
|
||||
AnnotatedRow, DiaryEntry, DiaryFilter, EntityType, ExportFormat, ExternalPersonId,
|
||||
FeedEntry, FeedSortBy, FieldMapping, FileFormat, FollowingFilter, ImportError,
|
||||
ImportProfile, ImportSession, IndexableDocument, MovieProfile, MovieStats, ParsedFile,
|
||||
Person, PersonCredits, PersonEnrichmentData, PersonId, RefreshSession,
|
||||
RemoteActorInfo, ReviewHistory, SearchQuery, SearchResults, UserStats, UserTrends,
|
||||
Person, PersonCredits, PersonEnrichmentData, PersonId, RefreshSession, RemoteActorInfo,
|
||||
ReviewHistory, SearchQuery, SearchResults, UserStats, UserTrends,
|
||||
collections::{PageParams, Paginated},
|
||||
},
|
||||
ports::{
|
||||
|
||||
@@ -2,13 +2,14 @@ use std::sync::Arc;
|
||||
|
||||
use domain::ports::{
|
||||
AuthService, DiaryExporter, DiaryQuery, DocumentParser, EventPublisher, FederatedProfileQuery,
|
||||
GoalCommand, GoalQuery, ImportProfileRepository, ImportSessionRepository, MetadataClient,
|
||||
MovieCommand, MovieProfileRepository, MovieQuery, ObjectStorage, PasswordHasher, PersonCommand,
|
||||
PersonEnrichmentClient, PersonQuery, PosterFetcherClient, RefreshSessionRepository,
|
||||
RemoteGoalRepository, RemoteWatchlistRepository, ReviewRepository, SearchCommand, SearchPort,
|
||||
FederationAdminQuery, SocialCommand, SocialQuery, StatsRepository, UserProfileFieldsRepository,
|
||||
UserRepository, UserSettingsRepository, WatchEventCommand, WatchEventQuery,
|
||||
WatchlistRepository, WebhookTokenRepository, WrapUpRepository, WrapUpStatsQuery,
|
||||
FederationAdminQuery, GoalCommand, GoalQuery, ImportProfileRepository, ImportSessionRepository,
|
||||
MetadataClient, MovieCommand, MovieProfileRepository, MovieQuery, ObjectStorage,
|
||||
PasswordHasher, PersonCommand, PersonEnrichmentClient, PersonQuery, PosterFetcherClient,
|
||||
RefreshSessionRepository, RemoteGoalRepository, RemoteWatchlistRepository, ReviewRepository,
|
||||
SearchCommand, SearchPort, SocialCommand, SocialQuery, StatsRepository,
|
||||
UserProfileFieldsRepository, UserRepository, UserSettingsRepository, WatchEventCommand,
|
||||
WatchEventQuery, WatchlistRepository, WebhookTokenRepository, WrapUpRepository,
|
||||
WrapUpStatsQuery,
|
||||
};
|
||||
|
||||
use application::config::AppConfig;
|
||||
|
||||
@@ -84,7 +84,9 @@ pub async fn get_blocked_domains_admin(
|
||||
_admin: AdminApiUser,
|
||||
) -> Result<Json<Vec<BlockedDomainResponse>>, ApiError> {
|
||||
let domains = state
|
||||
.app_ctx.services.ap_service
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.get_blocked_domains()
|
||||
.await
|
||||
.map_err(ap_to_domain)?;
|
||||
@@ -116,7 +118,9 @@ pub async fn add_blocked_domain_admin(
|
||||
axum::Json(body): axum::Json<AddBlockedDomainRequest>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
state
|
||||
.app_ctx.services.ap_service
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.add_blocked_domain(&body.domain, body.reason.as_deref())
|
||||
.await
|
||||
.map_err(ap_to_domain)?;
|
||||
@@ -139,7 +143,9 @@ pub async fn remove_blocked_domain_admin(
|
||||
axum::extract::Path(domain): axum::extract::Path<String>,
|
||||
) -> Result<impl IntoResponse, ApiError> {
|
||||
state
|
||||
.app_ctx.services.ap_service
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.remove_blocked_domain(&domain)
|
||||
.await
|
||||
.map_err(ap_to_domain)?;
|
||||
@@ -263,10 +269,7 @@ pub async fn get_following(
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(ActorListResponse {
|
||||
actors: identities
|
||||
.into_iter()
|
||||
.map(social_actor_to_dto)
|
||||
.collect(),
|
||||
actors: identities.into_iter().map(social_actor_to_dto).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -293,10 +296,7 @@ pub async fn get_followers(
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(ActorListResponse {
|
||||
actors: identities
|
||||
.into_iter()
|
||||
.map(social_actor_to_dto)
|
||||
.collect(),
|
||||
actors: identities.into_iter().map(social_actor_to_dto).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -314,10 +314,7 @@ pub async fn get_user_following(
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(ActorListResponse {
|
||||
actors: identities
|
||||
.into_iter()
|
||||
.map(social_actor_to_dto)
|
||||
.collect(),
|
||||
actors: identities.into_iter().map(social_actor_to_dto).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -335,10 +332,7 @@ pub async fn get_user_followers(
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(ActorListResponse {
|
||||
actors: identities
|
||||
.into_iter()
|
||||
.map(social_actor_to_dto)
|
||||
.collect(),
|
||||
actors: identities.into_iter().map(social_actor_to_dto).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -525,10 +519,7 @@ pub async fn get_pending_followers(
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(ActorListResponse {
|
||||
actors: identities
|
||||
.into_iter()
|
||||
.map(social_actor_to_dto)
|
||||
.collect(),
|
||||
actors: identities.into_iter().map(social_actor_to_dto).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -563,7 +554,9 @@ pub async fn follow_remote_user(
|
||||
&deps,
|
||||
application::social::commands::FollowCommand {
|
||||
follower_id: user_id.value(),
|
||||
target: SocialIdentity::Remote { actor_url: form.handle },
|
||||
target: SocialIdentity::Remote {
|
||||
actor_url: form.handle,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -604,7 +597,9 @@ pub async fn unfollow_remote_user(
|
||||
&deps,
|
||||
application::social::commands::UnfollowCommand {
|
||||
follower_id: user_id.value(),
|
||||
target: SocialIdentity::Remote { actor_url: form.actor_url },
|
||||
target: SocialIdentity::Remote {
|
||||
actor_url: form.actor_url,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -645,7 +640,9 @@ pub async fn accept_follower_html(
|
||||
&deps,
|
||||
application::social::commands::AcceptFollowCommand {
|
||||
owner_id: user_id.value(),
|
||||
requester: SocialIdentity::Remote { actor_url: form.actor_url },
|
||||
requester: SocialIdentity::Remote {
|
||||
actor_url: form.actor_url,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -680,7 +677,9 @@ pub async fn reject_follower_html(
|
||||
&deps,
|
||||
application::social::commands::RejectFollowCommand {
|
||||
owner_id: user_id.value(),
|
||||
requester: SocialIdentity::Remote { actor_url: form.actor_url },
|
||||
requester: SocialIdentity::Remote {
|
||||
actor_url: form.actor_url,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -706,7 +705,9 @@ pub async fn get_followers_collection(
|
||||
if accept.contains("application/activity+json") || accept.contains("application/ld+json") {
|
||||
let page = params.get("page").and_then(|p| p.parse::<u32>().ok());
|
||||
return match state
|
||||
.app_ctx.services.ap_service
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.followers_collection_json(user_id, page)
|
||||
.await
|
||||
{
|
||||
@@ -737,7 +738,9 @@ pub async fn get_following_collection(
|
||||
if accept.contains("application/activity+json") || accept.contains("application/ld+json") {
|
||||
let page = params.get("page").and_then(|p| p.parse::<u32>().ok());
|
||||
return match state
|
||||
.app_ctx.services.ap_service
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.following_collection_json(user_id, page)
|
||||
.await
|
||||
{
|
||||
@@ -776,7 +779,9 @@ pub async fn get_following_page(
|
||||
};
|
||||
match application::social::get_following::execute(
|
||||
&deps,
|
||||
application::social::queries::GetFollowingQuery { user_id: user_id.value() },
|
||||
application::social::queries::GetFollowingQuery {
|
||||
user_id: user_id.value(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -825,7 +830,9 @@ pub async fn get_followers_page(
|
||||
};
|
||||
match application::social::get_followers::execute(
|
||||
&deps,
|
||||
application::social::queries::GetFollowersQuery { user_id: user_id.value() },
|
||||
application::social::queries::GetFollowersQuery {
|
||||
user_id: user_id.value(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -875,7 +882,9 @@ pub async fn remove_follower_html(
|
||||
&deps,
|
||||
application::social::commands::RemoveFollowerCommand {
|
||||
owner_id: user_id.value(),
|
||||
follower: SocialIdentity::Remote { actor_url: form.actor_url },
|
||||
follower: SocialIdentity::Remote {
|
||||
actor_url: form.actor_url,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -902,7 +911,13 @@ pub async fn get_blocked_domains_page(
|
||||
let mut ctx = build_page_context(&state, Some(user_id), csrf.0).await;
|
||||
ctx.page_title = "Blocked Domains — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!("{}/admin/blocked-domains", state.app_ctx.config.base_url);
|
||||
match state.app_ctx.services.ap_service.get_blocked_domains().await {
|
||||
match state
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.get_blocked_domains()
|
||||
.await
|
||||
{
|
||||
Ok(domains) => {
|
||||
let entries: Vec<template_askama::BlockedDomainEntry> = domains
|
||||
.into_iter()
|
||||
@@ -940,7 +955,9 @@ pub async fn post_blocked_domain(
|
||||
}
|
||||
let reason = form.reason.as_deref().filter(|s| !s.trim().is_empty());
|
||||
match state
|
||||
.app_ctx.services.ap_service
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.add_blocked_domain(&form.domain, reason)
|
||||
.await
|
||||
{
|
||||
@@ -961,7 +978,13 @@ pub async fn post_remove_blocked_domain(
|
||||
if crate::csrf::mismatch(&csrf, &form.csrf_token) {
|
||||
return StatusCode::FORBIDDEN.into_response();
|
||||
}
|
||||
match state.app_ctx.services.ap_service.remove_blocked_domain(&form.domain).await {
|
||||
match state
|
||||
.app_ctx
|
||||
.services
|
||||
.ap_service
|
||||
.remove_blocked_domain(&form.domain)
|
||||
.await
|
||||
{
|
||||
Ok(()) => Redirect::to("/admin/blocked-domains").into_response(),
|
||||
Err(e) => {
|
||||
tracing::error!("remove_blocked_domain error: {:?}", e);
|
||||
@@ -983,7 +1006,9 @@ pub async fn get_blocked_actors_page(
|
||||
};
|
||||
match application::social::get_blocked::execute(
|
||||
&deps,
|
||||
application::social::queries::GetBlockedQuery { user_id: user_id.value() },
|
||||
application::social::queries::GetBlockedQuery {
|
||||
user_id: user_id.value(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -1032,7 +1057,9 @@ pub async fn post_block_actor_html(
|
||||
&deps,
|
||||
application::social::commands::BlockCommand {
|
||||
blocker_id: user_id.value(),
|
||||
target: SocialIdentity::Remote { actor_url: form.actor_url },
|
||||
target: SocialIdentity::Remote {
|
||||
actor_url: form.actor_url,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -1063,7 +1090,9 @@ pub async fn post_unblock_actor(
|
||||
&deps,
|
||||
application::social::commands::UnblockCommand {
|
||||
blocker_id: user_id.value(),
|
||||
target: SocialIdentity::Remote { actor_url: form.actor_url },
|
||||
target: SocialIdentity::Remote {
|
||||
actor_url: form.actor_url,
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -66,7 +66,15 @@ async fn wire_dependencies() -> anyhow::Result<(AppState, axum::Router)> {
|
||||
let event_bus = EventBusBackend::from_env()?;
|
||||
|
||||
#[cfg(feature = "federation")]
|
||||
let (event_publisher_arc, ap_router, ap_service, social_query, remote_watchlist_repo, social_command_arc, social_query_unified_arc) = {
|
||||
let (
|
||||
event_publisher_arc,
|
||||
ap_router,
|
||||
ap_service,
|
||||
social_query,
|
||||
remote_watchlist_repo,
|
||||
social_command_arc,
|
||||
social_query_unified_arc,
|
||||
) = {
|
||||
let (
|
||||
activity_repo,
|
||||
follow_repo,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use domain::{errors::DomainError, events::DomainEvent, ports::EventHandler, value_objects::SocialIdentity};
|
||||
use domain::{
|
||||
errors::DomainError, events::DomainEvent, ports::EventHandler, value_objects::SocialIdentity,
|
||||
};
|
||||
|
||||
pub struct FollowBackfillHandler {
|
||||
pub ap_service: Arc<dyn activitypub::ActivityPubPort>,
|
||||
|
||||
Reference in New Issue
Block a user