learn and share notes on atproto (wip) 馃 malfestio.stormlightlabs.org/
readability solid axum atproto srs
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 103 lines 4.6 kB view raw
1use crate::state::SharedState; 2 3use axum::{ 4 Json, 5 extract::{Path, State}, 6 http::StatusCode, 7 response::IntoResponse, 8}; 9use serde_json::json; 10 11/// GET /api/users/:did/profile 12/// Get aggregated profile information for a user 13pub async fn get_profile(State(state): State<SharedState>, Path(did): Path<String>) -> impl IntoResponse { 14 match state.social_repo.get_user_profile(&did).await { 15 Ok(profile) => Json(profile).into_response(), 16 Err(e) => { 17 tracing::error!("Failed to get user profile: {:?}", e); 18 ( 19 StatusCode::INTERNAL_SERVER_ERROR, 20 Json(json!({"error": "Failed to get user profile"})), 21 ) 22 .into_response() 23 } 24 } 25} 26 27#[cfg(test)] 28mod tests { 29 use super::*; 30 use crate::repository::card::mock::MockCardRepository; 31 use crate::repository::deck::mock::MockDeckRepository; 32 use crate::repository::note::mock::MockNoteRepository; 33 use crate::repository::oauth::mock::MockOAuthRepository; 34 use crate::repository::preferences::mock::MockPreferencesRepository; 35 use crate::repository::review::mock::MockReviewRepository; 36 use crate::repository::search::mock::MockSearchRepository; 37 use crate::repository::social::mock::MockSocialRepository; 38 use crate::repository::social::{SocialRepository, UserProfile}; 39 use crate::state::AppState; 40 use std::sync::Arc; 41 42 fn create_test_state(social_repo: Arc<MockSocialRepository>) -> SharedState { 43 let pool = crate::db::create_mock_pool(); 44 Arc::new(AppState { 45 pool, 46 card_repo: Arc::new(MockCardRepository::new()) as Arc<dyn crate::repository::card::CardRepository>, 47 note_repo: Arc::new(MockNoteRepository::new()) as Arc<dyn crate::repository::note::NoteRepository>, 48 oauth_repo: Arc::new(MockOAuthRepository::new()) as Arc<dyn crate::repository::oauth::OAuthRepository>, 49 prefs_repo: Arc::new(MockPreferencesRepository::new()) 50 as Arc<dyn crate::repository::preferences::PreferencesRepository>, 51 review_repo: Arc::new(MockReviewRepository::new()) as Arc<dyn crate::repository::review::ReviewRepository>, 52 social_repo: social_repo.clone() as Arc<dyn SocialRepository>, 53 deck_repo: Arc::new(MockDeckRepository::new()) as Arc<dyn crate::repository::deck::DeckRepository>, 54 search_repo: Arc::new(MockSearchRepository::new()) as Arc<dyn crate::repository::search::SearchRepository>, 55 sync_repo: Arc::new(crate::repository::sync::mock::MockSyncRepository::new()) 56 as Arc<dyn crate::repository::sync::SyncRepository>, 57 config: crate::state::AppConfig { pds_url: "https://bsky.social".to_string() }, 58 auth_cache: Arc::new(tokio::sync::RwLock::new(std::collections::HashMap::new())), 59 dpop_nonces: Arc::new(tokio::sync::RwLock::new(std::collections::HashMap::new())), 60 identity_resolver: crate::oauth::resolver::IdentityResolver::new(), 61 }) 62 } 63 64 #[tokio::test] 65 async fn test_get_profile_returns_counts() { 66 let social_repo = Arc::new(MockSocialRepository::new()); 67 social_repo.follow("did:follower1", "did:user").await.unwrap(); 68 social_repo.follow("did:follower2", "did:user").await.unwrap(); 69 social_repo.follow("did:user", "did:following").await.unwrap(); 70 71 let state = create_test_state(social_repo); 72 let response = get_profile(State(state), Path("did:user".to_string())) 73 .await 74 .into_response(); 75 76 assert_eq!(response.status(), StatusCode::OK); 77 78 let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap(); 79 let profile: UserProfile = serde_json::from_slice(&body).unwrap(); 80 81 assert_eq!(profile.did, "did:user"); 82 assert_eq!(profile.follower_count, 2); 83 assert_eq!(profile.following_count, 1); 84 } 85 86 #[tokio::test] 87 async fn test_get_profile_unknown_user_returns_zero() { 88 let social_repo = Arc::new(MockSocialRepository::new()); 89 let state = create_test_state(social_repo); 90 91 let response = get_profile(State(state), Path("did:unknown".to_string())) 92 .await 93 .into_response(); 94 95 assert_eq!(response.status(), StatusCode::OK); 96 97 let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap(); 98 let profile: UserProfile = serde_json::from_slice(&body).unwrap(); 99 100 assert_eq!(profile.follower_count, 0); 101 assert_eq!(profile.following_count, 0); 102 } 103}