refactor: eliminate User/UserResponse struct literals, add AP user tests

- Feed/search adapters use #[sqlx(flatten)] UserRow instead of
  inline User construction — single point of change when User
  gains fields
- User::new_remote constructor replaces struct literal in testing
- to_summary_response replaces inline UserResponse in get_users
- 5 integration tests for PgApUserRepository (find, count,
  profile_fields→attachment)
This commit is contained in:
2026-05-29 14:17:41 +02:00
parent 020a79704f
commit 6d0b1a3121
10 changed files with 160 additions and 107 deletions

View File

@@ -5,6 +5,7 @@ use api_types::{
};
use application::use_cases::auth::{login, register, LoginInput, RegisterInput};
use axum::{http::StatusCode, response::IntoResponse, Json};
use domain::models::feed::UserSummary;
use domain::ports::{AuthService, EventPublisher, PasswordHasher, UserRepository};
deps_struct!(AuthDeps {
@@ -37,6 +38,22 @@ pub fn to_user_response(u: &domain::models::user::User) -> UserResponse {
}
}
pub fn to_summary_response(u: &UserSummary) -> UserResponse {
UserResponse {
id: u.id.as_uuid(),
username: u.username.clone(),
display_name: u.display_name.clone(),
bio: u.bio.clone(),
avatar_url: u.avatar_url.clone(),
header_url: None,
custom_css: None,
profile_fields: vec![],
local: true,
is_followed_by_viewer: false,
created_at: chrono::Utc::now(),
}
}
#[utoipa::path(
post, path = "/auth/register",
request_body = RegisterRequest,

View File

@@ -1,7 +1,7 @@
use crate::{
errors::ApiError,
extractors::{AuthUser, Deps, FromAppState, OptionalAuthUser},
handlers::auth::to_user_response,
handlers::auth::{to_summary_response, to_user_response},
state::AppState,
};
use api_types::{
@@ -200,23 +200,7 @@ pub async fn get_users(
}
let result = list_users(&*d.users, page_params).await?;
let items: Vec<UserResponse> = result
.items
.iter()
.map(|u| UserResponse {
id: u.id.as_uuid(),
username: u.username.clone(),
display_name: u.display_name.clone(),
bio: u.bio.clone(),
avatar_url: u.avatar_url.clone(),
header_url: None,
custom_css: None,
profile_fields: vec![],
local: true,
is_followed_by_viewer: false,
created_at: chrono::Utc::now(),
})
.collect();
let items: Vec<UserResponse> = result.items.iter().map(to_summary_response).collect();
Ok(Json(PagedResponse {
items,
total: result.total,