this repo has no description
1use crate::state::AppState;
2use axum::{
3 Json,
4 extract::{Query, State},
5 http::StatusCode,
6 response::{IntoResponse, Response},
7};
8use serde::Deserialize;
9use serde_json::json;
10
11#[derive(Deserialize)]
12pub struct DescribeRepoInput {
13 pub repo: String,
14}
15
16pub async fn describe_repo(
17 State(state): State<AppState>,
18 Query(input): Query<DescribeRepoInput>,
19) -> Response {
20 let hostname = std::env::var("PDS_HOSTNAME").unwrap_or_else(|_| "localhost".to_string());
21
22 let user_row = if input.repo.starts_with("did:") {
23 sqlx::query!("SELECT id, handle, did FROM users WHERE did = $1", input.repo)
24 .fetch_optional(&state.db)
25 .await
26 .map(|opt| opt.map(|r| (r.id, r.handle, r.did)))
27 } else {
28 let suffix = format!(".{}", hostname);
29 let short_handle = if input.repo.ends_with(&suffix) {
30 input.repo.strip_suffix(&suffix).unwrap_or(&input.repo)
31 } else {
32 &input.repo
33 };
34 sqlx::query!("SELECT id, handle, did FROM users WHERE handle = $1", short_handle)
35 .fetch_optional(&state.db)
36 .await
37 .map(|opt| opt.map(|r| (r.id, r.handle, r.did)))
38 };
39
40 let (user_id, handle, did) = match user_row {
41 Ok(Some((id, handle, did))) => (id, handle, did),
42 _ => {
43 return (
44 StatusCode::NOT_FOUND,
45 Json(json!({"error": "NotFound", "message": "Repo not found"})),
46 )
47 .into_response();
48 }
49 };
50
51 let collections_query =
52 sqlx::query!("SELECT DISTINCT collection FROM records WHERE repo_id = $1", user_id)
53 .fetch_all(&state.db)
54 .await;
55
56 let collections: Vec<String> = match collections_query {
57 Ok(rows) => rows.iter().map(|r| r.collection.clone()).collect(),
58 Err(_) => Vec::new(),
59 };
60
61 let full_handle = format!("{}.{}", handle, hostname);
62 let did_doc = json!({
63 "id": did,
64 "alsoKnownAs": [format!("at://{}", full_handle)]
65 });
66
67 Json(json!({
68 "handle": full_handle,
69 "did": did,
70 "didDoc": did_doc,
71 "collections": collections,
72 "handleIsCorrect": true
73 }))
74 .into_response()
75}