refactor: 5 architectural improvements (Tasks 2-5 + Task 6 fix)
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 5m2s
test / unit (pull_request) Successful in 16m19s
test / integration (pull_request) Failing after 17m15s
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 5m2s
test / unit (pull_request) Successful in 16m19s
test / integration (pull_request) Failing after 17m15s
- feat(domain): Hashtag value object with canonical extract() — unifies two divergent private implementations; fields pre-compute raw/normalized/url_slug/ap_name - feat(presentation): Deps<S: FromAppState> extractor — each handler now declares its exact dependency surface; AppState unchanged; handlers become unit-testable without mocking all 20 deps - refactor(feed): replace 5 flat FeedRepository methods with FeedQuery/FeedScope — single query() method; SQL shared logic lives once; adding feed types no longer requires 5 edits - refactor(activitypub): ActivityPubRepository + OutboundFederationPort moved out of domain::ports into activitypub-base::ap_ports — domain crate no longer knows about AP IDs, inboxes, or actor URLs - fix(outbox): OutboxRelay now opens a per-row transaction so FOR UPDATE SKIP LOCKED actually holds the lock during publish + mark_delivered
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use activitypub_base::{ActivityPubRepository, OutboundFederationPort};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
events::DomainEvent,
|
||||
models::thought::Visibility,
|
||||
ports::{ActivityPubRepository, OutboundFederationPort, ThoughtRepository, UserReader},
|
||||
ports::{ThoughtRepository, UserReader},
|
||||
value_objects::ThoughtId,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
@@ -212,13 +213,14 @@ impl FederationEventService {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use activitypub_base::{ActorApUrls, OutboundFederationPort};
|
||||
use async_trait::async_trait;
|
||||
use crate::testing::TestApRepo;
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
events::DomainEvent,
|
||||
models::thought::{Thought, Visibility},
|
||||
models::user::User,
|
||||
ports::{ActivityPubRepository, OutboundFederationPort},
|
||||
testing::TestStore,
|
||||
value_objects::*,
|
||||
};
|
||||
@@ -325,12 +327,23 @@ mod tests {
|
||||
}
|
||||
|
||||
fn svc(store: &TestStore, spy: Arc<SpyPort>) -> FederationEventService {
|
||||
let ap_repo = TestApRepo::new(store.clone());
|
||||
FederationEventService {
|
||||
thoughts: Arc::new(store.clone()),
|
||||
users: Arc::new(store.clone()),
|
||||
ap: spy,
|
||||
base_url: "https://example.com".to_string(),
|
||||
ap_repo: Arc::new(store.clone()),
|
||||
ap_repo: Arc::new(ap_repo),
|
||||
}
|
||||
}
|
||||
|
||||
fn svc_with_ap(store: &TestStore, ap_repo: TestApRepo, spy: Arc<SpyPort>) -> FederationEventService {
|
||||
FederationEventService {
|
||||
thoughts: Arc::new(store.clone()),
|
||||
users: Arc::new(store.clone()),
|
||||
ap: spy,
|
||||
base_url: "https://example.com".to_string(),
|
||||
ap_repo: Arc::new(ap_repo),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +465,8 @@ mod tests {
|
||||
let alice = alice();
|
||||
let mut thought = local_thought(alice.id.clone());
|
||||
thought.local = false;
|
||||
store.thought_ap_ids.lock().unwrap().insert(
|
||||
let ap_repo = TestApRepo::new(store.clone());
|
||||
ap_repo.inner.thought_ap_ids.lock().unwrap().insert(
|
||||
thought.id.clone(),
|
||||
"https://mastodon.social/users/bob/statuses/123".into(),
|
||||
);
|
||||
@@ -460,7 +474,7 @@ mod tests {
|
||||
store.thoughts.lock().unwrap().push(thought.clone());
|
||||
|
||||
let spy = Arc::new(SpyPort::default());
|
||||
svc(&store, spy.clone())
|
||||
svc_with_ap(&store, ap_repo, spy.clone())
|
||||
.process(&DomainEvent::BoostAdded {
|
||||
boost_id: BoostId::new(),
|
||||
user_id: alice.id.clone(),
|
||||
@@ -604,14 +618,15 @@ mod tests {
|
||||
let alice = alice();
|
||||
let mut thought = local_thought(alice.id.clone());
|
||||
thought.local = false;
|
||||
store.thought_ap_ids.lock().unwrap().insert(
|
||||
let ap_repo = TestApRepo::new(store.clone());
|
||||
ap_repo.inner.thought_ap_ids.lock().unwrap().insert(
|
||||
thought.id.clone(),
|
||||
"https://mastodon.social/users/bob/statuses/456".into(),
|
||||
);
|
||||
store.thoughts.lock().unwrap().push(thought.clone());
|
||||
|
||||
let spy = Arc::new(SpyPort::default());
|
||||
svc(&store, spy.clone())
|
||||
svc_with_ap(&store, ap_repo, spy.clone())
|
||||
.process(&DomainEvent::BoostRemoved {
|
||||
user_id: alice.id.clone(),
|
||||
thought_id: thought.id.clone(),
|
||||
@@ -673,28 +688,28 @@ mod tests {
|
||||
PasswordHash("h".into()),
|
||||
);
|
||||
author.local = false;
|
||||
store.actor_ap_urls.lock().unwrap().insert(
|
||||
author.id.clone(),
|
||||
domain::ports::ActorApUrls {
|
||||
ap_id: "https://mastodon.social/users/author".into(),
|
||||
inbox_url: "https://mastodon.social/users/author/inbox".into(),
|
||||
},
|
||||
);
|
||||
|
||||
let thought = local_thought(author.id.clone());
|
||||
store.thought_ap_ids.lock().unwrap().insert(
|
||||
thought.id.clone(),
|
||||
"https://mastodon.social/posts/123".into(),
|
||||
);
|
||||
|
||||
let liker = alice();
|
||||
|
||||
store.users.lock().unwrap().push(author.clone());
|
||||
store.users.lock().unwrap().push(liker.clone());
|
||||
store.thoughts.lock().unwrap().push(thought.clone());
|
||||
|
||||
let ap_repo = TestApRepo::new(store.clone());
|
||||
ap_repo.actor_ap_urls.lock().unwrap().insert(
|
||||
author.id.clone(),
|
||||
ActorApUrls {
|
||||
ap_id: "https://mastodon.social/users/author".into(),
|
||||
inbox_url: "https://mastodon.social/users/author/inbox".into(),
|
||||
},
|
||||
);
|
||||
ap_repo.inner.thought_ap_ids.lock().unwrap().insert(
|
||||
thought.id.clone(),
|
||||
"https://mastodon.social/posts/123".into(),
|
||||
);
|
||||
|
||||
let spy = Arc::new(SpyPort::default());
|
||||
svc(&store, spy.clone())
|
||||
svc_with_ap(&store, ap_repo, spy.clone())
|
||||
.process(&DomainEvent::LikeAdded {
|
||||
like_id: LikeId::new(),
|
||||
user_id: liker.id,
|
||||
|
||||
Reference in New Issue
Block a user