fix(presentation): hydrate feed responses with full ThoughtResponse — remove UUID-only stubs

This commit is contained in:
2026-05-14 15:31:44 +02:00
parent cf94b0ba6c
commit 6eba91e699

View File

@@ -1,10 +1,30 @@
use axum::{extract::{Path, Query, State}, Json}; use axum::{extract::{Path, Query, State}, Json};
use api_types::requests::{PaginationQuery, SearchQuery}; use api_types::requests::{PaginationQuery, SearchQuery};
use api_types::responses::ThoughtResponse;
use application::use_cases::feed::{get_home_feed, get_public_feed, get_followers, get_following, get_user_feed, get_by_tag}; use application::use_cases::feed::{get_home_feed, get_public_feed, get_followers, get_following, get_user_feed, get_by_tag};
use domain::models::feed::PageParams; use domain::models::feed::PageParams;
use crate::{errors::ApiError, extractors::{AuthUser, OptionalAuthUser}, handlers::auth::to_user_response, state::AppState}; use crate::{errors::ApiError, extractors::{AuthUser, OptionalAuthUser}, handlers::auth::to_user_response, state::AppState};
use application::use_cases::profile::get_user_by_username; use application::use_cases::profile::get_user_by_username;
fn to_thought_response(e: &domain::models::feed::FeedEntry) -> ThoughtResponse {
ThoughtResponse {
id: e.thought.id.as_uuid(),
content: e.thought.content.as_str().to_string(),
author: to_user_response(&e.author),
in_reply_to_id: e.thought.in_reply_to_id.as_ref().map(|id| id.as_uuid()),
visibility: e.thought.visibility.as_str().to_string(),
content_warning: e.thought.content_warning.clone(),
sensitive: e.thought.sensitive,
like_count: e.like_count,
boost_count: e.boost_count,
reply_count: e.reply_count,
liked_by_viewer: e.liked_by_viewer,
boosted_by_viewer: e.boosted_by_viewer,
created_at: e.thought.created_at,
updated_at: e.thought.updated_at,
}
}
#[utoipa::path( #[utoipa::path(
get, path = "/feed", get, path = "/feed",
params(PaginationQuery), params(PaginationQuery),
@@ -14,7 +34,12 @@ use application::use_cases::profile::get_user_by_username;
pub async fn home_feed(State(s): State<AppState>, AuthUser(uid): AuthUser, Query(q): Query<PaginationQuery>) -> Result<Json<serde_json::Value>, ApiError> { pub async fn home_feed(State(s): State<AppState>, AuthUser(uid): AuthUser, Query(q): Query<PaginationQuery>) -> Result<Json<serde_json::Value>, ApiError> {
let page = PageParams { page: q.page(), per_page: q.per_page() }; let page = PageParams { page: q.page(), per_page: q.per_page() };
let result = get_home_feed(&*s.feed, &*s.follows, &uid, page).await?; let result = get_home_feed(&*s.feed, &*s.follows, &uid, page).await?;
Ok(Json(serde_json::json!({ "items": result.items.iter().map(|e| e.thought.id.as_uuid()).collect::<Vec<_>>(), "total": result.total, "page": result.page }))) Ok(Json(serde_json::json!({
"items": result.items.iter().map(to_thought_response).collect::<Vec<_>>(),
"total": result.total,
"page": result.page,
"per_page": result.per_page,
})))
} }
#[utoipa::path( #[utoipa::path(
@@ -25,7 +50,12 @@ pub async fn home_feed(State(s): State<AppState>, AuthUser(uid): AuthUser, Query
pub async fn public_feed(State(s): State<AppState>, OptionalAuthUser(viewer): OptionalAuthUser, Query(q): Query<PaginationQuery>) -> Result<Json<serde_json::Value>, ApiError> { pub async fn public_feed(State(s): State<AppState>, OptionalAuthUser(viewer): OptionalAuthUser, Query(q): Query<PaginationQuery>) -> Result<Json<serde_json::Value>, ApiError> {
let page = PageParams { page: q.page(), per_page: q.per_page() }; let page = PageParams { page: q.page(), per_page: q.per_page() };
let result = get_public_feed(&*s.feed, viewer.as_ref(), page).await?; let result = get_public_feed(&*s.feed, viewer.as_ref(), page).await?;
Ok(Json(serde_json::json!({ "items": result.items.iter().map(|e| e.thought.id.as_uuid()).collect::<Vec<_>>(), "total": result.total, "page": result.page }))) Ok(Json(serde_json::json!({
"items": result.items.iter().map(to_thought_response).collect::<Vec<_>>(),
"total": result.total,
"page": result.page,
"per_page": result.per_page,
})))
} }
#[utoipa::path( #[utoipa::path(
@@ -99,16 +129,7 @@ pub async fn user_thoughts_handler(
"total": result.total, "total": result.total,
"page": result.page, "page": result.page,
"per_page": result.per_page, "per_page": result.per_page,
"items": result.items.iter().map(|e| serde_json::json!({ "items": result.items.iter().map(to_thought_response).collect::<Vec<_>>()
"id": e.thought.id.as_uuid(),
"content": e.thought.content.as_str(),
"visibility": e.thought.visibility.as_str(),
"like_count": e.like_count,
"boost_count": e.boost_count,
"reply_count": e.reply_count,
"created_at": e.thought.created_at,
"updated_at": e.thought.updated_at,
})).collect::<Vec<_>>()
}))) })))
} }
@@ -135,8 +156,12 @@ pub async fn tag_thoughts_handler(
"items": result.items.iter().map(|t| serde_json::json!({ "items": result.items.iter().map(|t| serde_json::json!({
"id": t.id.as_uuid(), "id": t.id.as_uuid(),
"content": t.content.as_str(), "content": t.content.as_str(),
"in_reply_to_id": t.in_reply_to_id.as_ref().map(|id| id.as_uuid()),
"visibility": t.visibility.as_str(), "visibility": t.visibility.as_str(),
"content_warning": t.content_warning,
"sensitive": t.sensitive,
"created_at": t.created_at, "created_at": t.created_at,
"updated_at": t.updated_at,
})).collect::<Vec<_>>() })).collect::<Vec<_>>()
}))) })))
} }