systemprompt_api/routes/oauth/client/
list.rs1use axum::extract::{Extension, Query};
7use axum::http::StatusCode;
8use axum::response::{IntoResponse, Json, Response};
9use serde::Deserialize;
10use tracing::instrument;
11use validator::Validate;
12
13use super::super::OAuthHttpError;
14use super::super::extractors::OAuthRepo;
15use systemprompt_models::api::PaginationParams;
16use systemprompt_models::{PaginationInfo, RequestContext};
17
18#[derive(Debug, Deserialize, Validate)]
19pub struct ListClientsQuery {
20 #[serde(flatten)]
21 pub pagination: PaginationParams,
22
23 #[validate(length(min = 1, max = 50))]
24 pub status: Option<String>,
25}
26
27fn paginated_response<T: serde::Serialize>(items: &[T], pagination: &PaginationInfo) -> Response {
28 (
29 StatusCode::OK,
30 Json(serde_json::json!({
31 "data": items,
32 "meta": {
33 "pagination": pagination
34 }
35 })),
36 )
37 .into_response()
38}
39
40#[instrument(skip(repository, req_ctx, query))]
41pub async fn list_clients(
42 Extension(req_ctx): Extension<RequestContext>,
43 OAuthRepo(repository): OAuthRepo,
44 Query(query): Query<ListClientsQuery>,
45) -> Result<Response, OAuthHttpError> {
46 query
47 .validate()
48 .map_err(|e| OAuthHttpError::invalid_request(format!("Invalid query parameters: {e}")))?;
49
50 let page = query.pagination.page;
51 let per_page = query.pagination.per_page;
52 let offset = query.pagination.offset();
53 let limit = query.pagination.limit();
54
55 let clients = repository.list_clients_paginated(limit, offset).await?;
56 let total = repository.count_clients().await?;
57
58 tracing::info!(
59 count = clients.len(),
60 total = total,
61 page = page,
62 per_page = per_page,
63 requested_by = %req_ctx.auth.actor.user_id,
64 "OAuth clients listed"
65 );
66 let pagination = PaginationInfo::new(total, page, per_page);
67 let items: Vec<systemprompt_oauth::clients::api::OAuthClientResponse> =
68 clients.into_iter().map(Into::into).collect();
69 Ok(paginated_response(&items, &pagination))
70}