feat(presentation): add GET /users/me/friends handler and route

This commit is contained in:
2026-05-28 03:46:52 +02:00
parent d4da172398
commit 0e2b72b77a
4 changed files with 57 additions and 4 deletions

View File

@@ -4,11 +4,15 @@ use crate::{
errors::ApiError,
extractors::{AuthUser, Deps},
};
use api_types::requests::SetTopFriendsRequest;
use api_types::responses::TopFriendsResponse;
use api_types::requests::{PaginationQuery, SetTopFriendsRequest};
use api_types::responses::{PagedResponse, TopFriendsResponse, UserResponse};
use application::use_cases::profile::{get_top_friends, get_user_by_username, set_top_friends};
use application::use_cases::social::*;
use axum::{extract::Path, http::StatusCode, Json};
use axum::{
extract::{Path, Query},
http::StatusCode,
Json,
};
use domain::{
ports::{
BlockRepository, BoostRepository, EventPublisher, FederationActionPort, FollowRepository,
@@ -150,5 +154,33 @@ pub async fn get_top_friends_handler(
Ok(Json(TopFriendsResponse { top_friends }))
}
#[utoipa::path(
get, path = "/users/me/friends",
params(PaginationQuery),
responses(
(status = 200, description = "Local mutual follows (paginated)", body = inline(PagedResponse<UserResponse>)),
(status = 401, description = "Unauthorized"),
),
security(("bearer_auth" = []))
)]
pub async fn get_friends_handler(
Deps(d): Deps<SocialDeps>,
AuthUser(uid): AuthUser,
Query(q): Query<PaginationQuery>,
) -> Result<Json<PagedResponse<UserResponse>>, ApiError> {
use domain::models::feed::PageParams;
let page = PageParams {
page: q.page(),
per_page: q.per_page(),
};
let result = get_local_friends(&*d.follows, &uid, &page).await?;
Ok(Json(PagedResponse {
items: result.items.iter().map(to_user_response).collect(),
total: result.total,
page: result.page,
per_page: result.per_page,
}))
}
#[cfg(test)]
mod tests;

View File

@@ -1,9 +1,10 @@
use super::get_friends_handler;
use super::*;
use crate::testing::make_state;
use axum::{
body::Body,
http::Request,
routing::{delete, post},
routing::{delete, get, post},
Router,
};
use tower::ServiceExt;
@@ -32,6 +33,24 @@ async fn follow_without_auth_returns_401() {
assert_eq!(resp.status(), 401);
}
#[tokio::test]
async fn get_friends_without_auth_returns_401() {
let app = Router::new()
.route("/users/me/friends", get(get_friends_handler))
.with_state(make_state());
let resp = app
.oneshot(
Request::builder()
.method("GET")
.uri("/users/me/friends")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(resp.status(), 401);
}
#[tokio::test]
async fn unfollow_remote_without_auth_returns_401() {
let resp = app()

View File

@@ -14,6 +14,7 @@ use utoipa::OpenApi;
crate::handlers::social::delete_block,
crate::handlers::social::put_top_friends,
crate::handlers::social::get_top_friends_handler,
crate::handlers::social::get_friends_handler,
),
components(schemas(SetTopFriendsRequest))
)]

View File

@@ -26,6 +26,7 @@ pub fn router() -> Router<AppState> {
put(users::upload_banner).layer(DefaultBodyLimit::max(10 * 1024 * 1024)),
)
.route("/users/me/following", get(users::get_me_following))
.route("/users/me/friends", get(social::get_friends_handler))
.route("/users/me/top-friends", put(social::put_top_friends))
.route("/users/{username}", get(users::get_user))
.route(