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, Serialize}; 9use serde_json::json; 10use tracing::error; 11 12#[derive(Deserialize)] 13pub struct GetLatestCommitParams { 14 pub did: String, 15} 16 17#[derive(Serialize)] 18pub struct GetLatestCommitOutput { 19 pub cid: String, 20 pub rev: String, 21} 22 23pub async fn get_latest_commit( 24 State(state): State<AppState>, 25 Query(params): Query<GetLatestCommitParams>, 26) -> Response { 27 let did = params.did.trim(); 28 29 if did.is_empty() { 30 return ( 31 StatusCode::BAD_REQUEST, 32 Json(json!({"error": "InvalidRequest", "message": "did is required"})), 33 ) 34 .into_response(); 35 } 36 37 let result = sqlx::query!( 38 r#" 39 SELECT r.repo_root_cid 40 FROM repos r 41 JOIN users u ON r.user_id = u.id 42 WHERE u.did = $1 43 "#, 44 did 45 ) 46 .fetch_optional(&state.db) 47 .await; 48 49 match result { 50 Ok(Some(row)) => { 51 ( 52 StatusCode::OK, 53 Json(GetLatestCommitOutput { 54 cid: row.repo_root_cid, 55 rev: chrono::Utc::now().timestamp_millis().to_string(), 56 }), 57 ) 58 .into_response() 59 } 60 Ok(None) => ( 61 StatusCode::NOT_FOUND, 62 Json(json!({"error": "RepoNotFound", "message": "Could not find repo for DID"})), 63 ) 64 .into_response(), 65 Err(e) => { 66 error!("DB error in get_latest_commit: {:?}", e); 67 ( 68 StatusCode::INTERNAL_SERVER_ERROR, 69 Json(json!({"error": "InternalError"})), 70 ) 71 .into_response() 72 } 73 } 74} 75 76#[derive(Deserialize)] 77pub struct ListReposParams { 78 pub limit: Option<i64>, 79 pub cursor: Option<String>, 80} 81 82#[derive(Serialize)] 83#[serde(rename_all = "camelCase")] 84pub struct RepoInfo { 85 pub did: String, 86 pub head: String, 87 pub rev: String, 88 pub active: bool, 89} 90 91#[derive(Serialize)] 92pub struct ListReposOutput { 93 pub cursor: Option<String>, 94 pub repos: Vec<RepoInfo>, 95} 96 97pub async fn list_repos( 98 State(state): State<AppState>, 99 Query(params): Query<ListReposParams>, 100) -> Response { 101 let limit = params.limit.unwrap_or(50).min(1000); 102 let cursor_did = params.cursor.as_deref().unwrap_or(""); 103 104 let result = sqlx::query!( 105 r#" 106 SELECT u.did, r.repo_root_cid 107 FROM repos r 108 JOIN users u ON r.user_id = u.id 109 WHERE u.did > $1 110 ORDER BY u.did ASC 111 LIMIT $2 112 "#, 113 cursor_did, 114 limit + 1 115 ) 116 .fetch_all(&state.db) 117 .await; 118 119 match result { 120 Ok(rows) => { 121 let has_more = rows.len() as i64 > limit; 122 let repos: Vec<RepoInfo> = rows 123 .iter() 124 .take(limit as usize) 125 .map(|row| { 126 RepoInfo { 127 did: row.did.clone(), 128 head: row.repo_root_cid.clone(), 129 rev: chrono::Utc::now().timestamp_millis().to_string(), 130 active: true, 131 } 132 }) 133 .collect(); 134 135 let next_cursor = if has_more { 136 repos.last().map(|r| r.did.clone()) 137 } else { 138 None 139 }; 140 141 ( 142 StatusCode::OK, 143 Json(ListReposOutput { 144 cursor: next_cursor, 145 repos, 146 }), 147 ) 148 .into_response() 149 } 150 Err(e) => { 151 error!("DB error in list_repos: {:?}", e); 152 ( 153 StatusCode::INTERNAL_SERVER_ERROR, 154 Json(json!({"error": "InternalError"})), 155 ) 156 .into_response() 157 } 158 } 159} 160 161#[derive(Deserialize)] 162pub struct GetRepoStatusParams { 163 pub did: String, 164} 165 166#[derive(Serialize)] 167pub struct GetRepoStatusOutput { 168 pub did: String, 169 pub active: bool, 170 pub rev: Option<String>, 171} 172 173pub async fn get_repo_status( 174 State(state): State<AppState>, 175 Query(params): Query<GetRepoStatusParams>, 176) -> Response { 177 let did = params.did.trim(); 178 179 if did.is_empty() { 180 return ( 181 StatusCode::BAD_REQUEST, 182 Json(json!({"error": "InvalidRequest", "message": "did is required"})), 183 ) 184 .into_response(); 185 } 186 187 let result = sqlx::query!( 188 r#" 189 SELECT u.did, r.repo_root_cid 190 FROM users u 191 LEFT JOIN repos r ON u.id = r.user_id 192 WHERE u.did = $1 193 "#, 194 did 195 ) 196 .fetch_optional(&state.db) 197 .await; 198 199 match result { 200 Ok(Some(row)) => { 201 let rev = Some(chrono::Utc::now().timestamp_millis().to_string()); 202 203 ( 204 StatusCode::OK, 205 Json(GetRepoStatusOutput { 206 did: row.did, 207 active: true, 208 rev, 209 }), 210 ) 211 .into_response() 212 } 213 Ok(None) => ( 214 StatusCode::NOT_FOUND, 215 Json(json!({"error": "RepoNotFound", "message": "Could not find repo for DID"})), 216 ) 217 .into_response(), 218 Err(e) => { 219 error!("DB error in get_repo_status: {:?}", e); 220 ( 221 StatusCode::INTERNAL_SERVER_ERROR, 222 Json(json!({"error": "InternalError"})), 223 ) 224 .into_response() 225 } 226 } 227}