diff --git a/src/http_server/router.rs b/src/http_server/router.rs index 13a1229..1f52a31 100644 --- a/src/http_server/router.rs +++ b/src/http_server/router.rs @@ -38,8 +38,9 @@ where "/recommendations/:pubkey", get(get_recommendations_handler::), ) // Make handler generic + .route("/maybe_spammer/:pubkey", get(maybe_spammer::)) // Make handler generic .layer(tracing_layer) - .layer(TimeoutLayer::new(Duration::from_secs(1))) + .layer(TimeoutLayer::new(Duration::from_secs(5))) .with_state(state)) // Attach state to the router } @@ -67,6 +68,19 @@ where Ok(Json(recommendations)) } +async fn maybe_spammer( + State(state): State>>, // Extract shared state with generic RepoTrait + axum::extract::Path(pubkey): axum::extract::Path, // Extract pubkey from the path +) -> Result, ApiError> +where + T: RepoTrait, +{ + let public_key = PublicKey::from_hex(&pubkey).map_err(|_| ApiError::InvalidPublicKey)?; + let pagerank = state.repo.get_pagerank(&public_key).await?; + + Ok(Json(pagerank < 0.2)) +} + async fn serve_root_page(_headers: HeaderMap) -> impl IntoResponse { let body = r#" diff --git a/src/repo.rs b/src/repo.rs index fef9e02..956bd1d 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -101,6 +101,13 @@ pub trait RepoTrait: Sync + Send { { async { panic!("Not implemented") } } + + fn get_pagerank( + &self, + _public_key: &PublicKey, + ) -> impl std::future::Future> + std::marker::Send { + async { panic!("Not implemented") } + } } impl RepoTrait for Repo { @@ -511,6 +518,34 @@ impl RepoTrait for Repo { Ok(recommendations) } + + async fn get_pagerank(&self, public_key: &PublicKey) -> Result { + let statement = r#" + MATCH (user:User {pubkey: $pubkey_val}) + RETURN user.pagerank AS pagerank + "#; + + let query = query(statement).param("pubkey_val", public_key.to_hex()); + + let mut records = self + .graph + .execute(query) + .await + .map_err(RepoError::GetPageRank)?; + + match records.next().await { + Ok(Some(row)) => { + let pagerank = row.get::("pagerank").map_err(|e| { + RepoError::deserialization_with_context(e, "deserializing 'pagerank' field") + })?; + Ok(pagerank) + } + Ok(None) => Err(RepoError::General(neo4rs::Error::DeserializationError( + neo4rs::DeError::PropertyMissingButRequired, + ))), + Err(e) => Err(RepoError::General(e)), + } + } } /// A function to read as DateTime a value stored either as LocalDatetime or DateTime @@ -577,6 +612,9 @@ pub enum RepoError { #[error("Failed to get recommendations pubkey: {0}")] GetRecommendationsPubkey(nostr_sdk::key::Error), + + #[error("Failed to get pagerank: {0}")] + GetPageRank(neo4rs::Error), } impl RepoError {