refactor: replace long arg lists with input/config structs and builder
- Thought::new_local → NewThought struct (7 args → 1) - UserWriter::update_profile → UpdateProfileInput struct (6 args → 2) - update_profile use case → UpdateProfileInput (8 args → 3) - ActivityPubService::new → builder pattern (9 args → 5 required + 4 optional setters) - accept_note → AcceptNoteInput struct (8 args → 1) - ThoughtNote::new_public → ThoughtNoteInput struct (8 args → 1) Remove all #[allow(clippy::too_many_arguments)] annotations.
This commit is contained in:
@@ -6,7 +6,7 @@ const THOUGHTS_PATH_PREFIX: &str = "/thoughts/";
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use activitypub_base::{ActivityPubRepository, ActorApUrls, OutboxEntry};
|
||||
use activitypub_base::{AcceptNoteInput, ActivityPubRepository, ActorApUrls, OutboxEntry};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
models::thought::{Thought, Visibility},
|
||||
@@ -210,17 +210,17 @@ impl ActivityPubRepository for PgActivityPubRepository {
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn accept_note(
|
||||
&self,
|
||||
ap_id: &str,
|
||||
author_id: &UserId,
|
||||
content: &str,
|
||||
published: DateTime<Utc>,
|
||||
sensitive: bool,
|
||||
content_warning: Option<String>,
|
||||
visibility: &str,
|
||||
in_reply_to: Option<&str>,
|
||||
) -> Result<ThoughtId, DomainError> {
|
||||
async fn accept_note(&self, input: AcceptNoteInput<'_>) -> Result<ThoughtId, DomainError> {
|
||||
let AcceptNoteInput {
|
||||
ap_id,
|
||||
author_id,
|
||||
content,
|
||||
published,
|
||||
sensitive,
|
||||
content_warning,
|
||||
visibility,
|
||||
in_reply_to,
|
||||
} = input;
|
||||
let capped: String = content.chars().take(MAX_REMOTE_CONTENT_CHARS).collect();
|
||||
let (in_reply_to_id, in_reply_to_url) = match in_reply_to {
|
||||
Some(url) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use activitypub_base::ActivityPubRepository;
|
||||
use activitypub_base::{AcceptNoteInput, ActivityPubRepository};
|
||||
|
||||
#[sqlx::test(migrations = "./migrations")]
|
||||
async fn intern_remote_actor_is_idempotent(pool: sqlx::PgPool) {
|
||||
@@ -16,16 +16,16 @@ async fn accept_and_retract_note(pool: sqlx::PgPool) {
|
||||
let actor_url = "https://remote.example/users/bob";
|
||||
let ap_id = "https://remote.example/notes/1";
|
||||
let author = repo.intern_remote_actor(actor_url).await.unwrap();
|
||||
repo.accept_note(
|
||||
repo.accept_note(AcceptNoteInput {
|
||||
ap_id,
|
||||
&author,
|
||||
"hello from remote",
|
||||
chrono::Utc::now(),
|
||||
false,
|
||||
None,
|
||||
"public",
|
||||
None,
|
||||
)
|
||||
author_id: &author,
|
||||
content: "hello from remote",
|
||||
published: chrono::Utc::now(),
|
||||
sensitive: false,
|
||||
content_warning: None,
|
||||
visibility: "public",
|
||||
in_reply_to: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
repo.retract_note(ap_id).await.unwrap();
|
||||
@@ -46,16 +46,16 @@ async fn accept_note_returns_thought_id(pool: sqlx::PgPool) {
|
||||
.unwrap();
|
||||
|
||||
let thought_id = repo
|
||||
.accept_note(
|
||||
"https://remote.example/notes/1",
|
||||
&actor_user_id,
|
||||
"Hello #rust world",
|
||||
chrono::Utc::now(),
|
||||
false,
|
||||
None,
|
||||
"public",
|
||||
None,
|
||||
)
|
||||
.accept_note(AcceptNoteInput {
|
||||
ap_id: "https://remote.example/notes/1",
|
||||
author_id: &actor_user_id,
|
||||
content: "Hello #rust world",
|
||||
published: chrono::Utc::now(),
|
||||
sensitive: false,
|
||||
content_warning: None,
|
||||
visibility: "public",
|
||||
in_reply_to: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{thought::PgThoughtRepository, user::PgUserRepository};
|
||||
use domain::{
|
||||
models::{
|
||||
feed::PageParams,
|
||||
thought::{Thought, Visibility},
|
||||
thought::{NewThought, Thought, Visibility},
|
||||
user::User,
|
||||
},
|
||||
ports::{FeedQuery, ThoughtRepository, UserWriter},
|
||||
@@ -20,15 +20,15 @@ async fn seed(pool: &sqlx::PgPool, username: &str, content: &str) -> (User, Thou
|
||||
PasswordHash("h".into()),
|
||||
);
|
||||
urepo.save(&u).await.unwrap();
|
||||
let t = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
u.id.clone(),
|
||||
Content::new_local(content).unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let t = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: u.id.clone(),
|
||||
content: Content::new_local(content).unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
trepo.save(&t).await.unwrap();
|
||||
(u, t)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{thought::PgThoughtRepository, user::PgUserRepository};
|
||||
use domain::ports::{ThoughtRepository, UserWriter};
|
||||
use domain::{
|
||||
models::{
|
||||
thought::{Thought, Visibility},
|
||||
thought::{NewThought, Thought, Visibility},
|
||||
user::User,
|
||||
},
|
||||
value_objects::*,
|
||||
@@ -29,15 +29,15 @@ async fn attach_and_list(pool: sqlx::PgPool) {
|
||||
PasswordHash("h".into()),
|
||||
);
|
||||
urepo.save(&u).await.unwrap();
|
||||
let t = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
u.id.clone(),
|
||||
Content::new_local("hi").unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let t = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: u.id.clone(),
|
||||
content: Content::new_local("hi").unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
trepo.save(&t).await.unwrap();
|
||||
let repo = PgTagRepository::new(pool);
|
||||
let tag = repo.find_or_create("greetings").await.unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{thought::PgThoughtRepository, user::PgUserRepository};
|
||||
use domain::{
|
||||
models::{
|
||||
thought::{Thought, Visibility},
|
||||
thought::{NewThought, Thought, Visibility},
|
||||
user::User,
|
||||
},
|
||||
ports::{ThoughtRepository, UserWriter},
|
||||
@@ -23,15 +23,15 @@ pub async fn seed_user(pool: &sqlx::PgPool, username: &str, email: &str) -> User
|
||||
pub async fn seed_user_and_thought(pool: &sqlx::PgPool) -> (User, Thought) {
|
||||
let user = seed_user(pool, "alice", "alice@ex.com").await;
|
||||
let trepo = PgThoughtRepository::new(pool.clone());
|
||||
let t = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
user.id.clone(),
|
||||
Content::new_local("hi").unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let t = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: user.id.clone(),
|
||||
content: Content::new_local("hi").unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
trepo.save(&t).await.unwrap();
|
||||
(user, t)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use crate::test_helpers::seed_user;
|
||||
use domain::{
|
||||
models::thought::{Thought, Visibility},
|
||||
models::thought::{NewThought, Thought, Visibility},
|
||||
value_objects::*,
|
||||
};
|
||||
|
||||
@@ -9,15 +9,15 @@ use domain::{
|
||||
async fn save_and_find_thought(pool: sqlx::PgPool) {
|
||||
let user = seed_user(&pool, "alice", "alice@ex.com").await;
|
||||
let repo = PgThoughtRepository::new(pool);
|
||||
let t = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
user.id.clone(),
|
||||
Content::new_local("hello world").unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let t = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: user.id.clone(),
|
||||
content: Content::new_local("hello world").unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
repo.save(&t).await.unwrap();
|
||||
let found = repo.find_by_id(&t.id).await.unwrap().unwrap();
|
||||
assert_eq!(found.content.as_str(), "hello world");
|
||||
@@ -28,15 +28,15 @@ async fn save_and_find_thought(pool: sqlx::PgPool) {
|
||||
async fn delete_thought(pool: sqlx::PgPool) {
|
||||
let user = seed_user(&pool, "bob", "bob@ex.com").await;
|
||||
let repo = PgThoughtRepository::new(pool);
|
||||
let t = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
user.id.clone(),
|
||||
Content::new_local("bye").unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let t = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: user.id.clone(),
|
||||
content: Content::new_local("bye").unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
repo.save(&t).await.unwrap();
|
||||
repo.delete(&t.id, &user.id).await.unwrap();
|
||||
assert!(repo.find_by_id(&t.id).await.unwrap().is_none());
|
||||
@@ -47,15 +47,15 @@ async fn delete_wrong_owner_returns_not_found(pool: sqlx::PgPool) {
|
||||
let alice = seed_user(&pool, "alice", "alice@ex.com").await;
|
||||
let bob = seed_user(&pool, "bob", "bob@ex.com").await;
|
||||
let repo = PgThoughtRepository::new(pool);
|
||||
let t = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
alice.id.clone(),
|
||||
Content::new_local("secret").unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let t = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: alice.id.clone(),
|
||||
content: Content::new_local("secret").unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
repo.save(&t).await.unwrap();
|
||||
let err = repo.delete(&t.id, &bob.id).await.unwrap_err();
|
||||
assert!(matches!(err, DomainError::NotFound));
|
||||
@@ -65,24 +65,24 @@ async fn delete_wrong_owner_returns_not_found(pool: sqlx::PgPool) {
|
||||
async fn get_thread_returns_root_and_replies(pool: sqlx::PgPool) {
|
||||
let user = seed_user(&pool, "charlie", "charlie@ex.com").await;
|
||||
let repo = PgThoughtRepository::new(pool);
|
||||
let root = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
user.id.clone(),
|
||||
Content::new_local("root").unwrap(),
|
||||
None,
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let reply = Thought::new_local(
|
||||
ThoughtId::new(),
|
||||
user.id.clone(),
|
||||
Content::new_local("reply").unwrap(),
|
||||
Some(root.id.clone()),
|
||||
Visibility::Public,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let root = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: user.id.clone(),
|
||||
content: Content::new_local("root").unwrap(),
|
||||
in_reply_to_id: None,
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
let reply = Thought::new_local(NewThought {
|
||||
id: ThoughtId::new(),
|
||||
user_id: user.id.clone(),
|
||||
content: Content::new_local("reply").unwrap(),
|
||||
in_reply_to_id: Some(root.id.clone()),
|
||||
visibility: Visibility::Public,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
});
|
||||
repo.save(&root).await.unwrap();
|
||||
repo.save(&reply).await.unwrap();
|
||||
let thread = repo.get_thread(&root.id).await.unwrap();
|
||||
|
||||
@@ -4,7 +4,7 @@ use chrono::{DateTime, Utc};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
models::feed::{PageParams, Paginated, UserSummary},
|
||||
models::user::User,
|
||||
models::user::{UpdateProfileInput, User},
|
||||
ports::{UserReader, UserWriter},
|
||||
value_objects::{Email, PasswordHash, UserId, Username},
|
||||
};
|
||||
@@ -265,21 +265,17 @@ impl UserWriter for PgUserRepository {
|
||||
async fn update_profile(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
display_name: Option<String>,
|
||||
bio: Option<String>,
|
||||
avatar_url: Option<String>,
|
||||
header_url: Option<String>,
|
||||
custom_css: Option<String>,
|
||||
input: UpdateProfileInput,
|
||||
) -> Result<(), DomainError> {
|
||||
sqlx::query(
|
||||
"UPDATE users SET display_name=$2,bio=$3,avatar_url=$4,header_url=$5,custom_css=$6,updated_at=NOW() WHERE id=$1"
|
||||
)
|
||||
.bind(user_id.as_uuid())
|
||||
.bind(display_name)
|
||||
.bind(bio)
|
||||
.bind(avatar_url)
|
||||
.bind(header_url)
|
||||
.bind(custom_css)
|
||||
.bind(input.display_name)
|
||||
.bind(input.bio)
|
||||
.bind(input.avatar_url)
|
||||
.bind(input.header_url)
|
||||
.bind(input.custom_css)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.into_domain()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use super::*;
|
||||
use domain::{models::user::User, value_objects::*};
|
||||
use domain::{
|
||||
models::user::{UpdateProfileInput, User},
|
||||
value_objects::*,
|
||||
};
|
||||
|
||||
#[sqlx::test(migrations = "./migrations")]
|
||||
async fn save_and_find_by_id(pool: sqlx::PgPool) {
|
||||
@@ -55,11 +58,11 @@ async fn update_profile_changes_fields(pool: sqlx::PgPool) {
|
||||
repo.save(&user).await.unwrap();
|
||||
repo.update_profile(
|
||||
&user.id,
|
||||
Some("Charlie".into()),
|
||||
Some("bio".into()),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
UpdateProfileInput {
|
||||
display_name: Some("Charlie".into()),
|
||||
bio: Some("bio".into()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user