use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE}; use reqwest::Client as HTTPClient; use serde_json::json; use std::collections::HashMap; use std::env; use std::error::Error; use crate::SSEMessageData; async fn get_author_id(user: &str) -> Result> { let api_base = env::var("API_BASE")?; let query_name = "get_author"; let operation = "GetAuthor"; let mut headers = HeaderMap::new(); // headers.insert(AUTHORIZATION, HeaderValue::from_str(token)?); headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); let mut variables = HashMap::::new(); variables.insert("user".to_string(), user.to_string()); let gql = json!({ "query": format!("query {}($slug: String, $user: String, $author_id: Int) {{ {}(slug: $slug, user: $user, author_id: $author_id){{ id }} }}", operation, query_name), "operationName": operation, "variables": variables }); println!("[get_author_id] GraphQL: {}", gql); let client = HTTPClient::new(); let response = client .post(&api_base) .headers(headers) .json(&gql) .send() .await?; if response.status().is_success() { let r: HashMap = response.json().await?; let author_id = r .get("data") .and_then(|data| data.get(query_name)) .and_then(|claims| claims.get("id")) .and_then(|id| id.as_i64()); match author_id { Some(id) => { println!("Author ID retrieved: {}", id); Ok(id as i32) } None => { Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, "No author ID found in the response", ))) } } } else { Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, format!("Request failed with status: {}", response.status()), ))) } } pub async fn get_id_by_token(token: &str) -> Result> { let auth_api_base = env::var("AUTH_URL")?; let query_name = "validate_jwt_token"; let operation = "ValidateToken"; let mut headers = HeaderMap::new(); // headers.insert(AUTHORIZATION, HeaderValue::from_str(token)?); headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); let mut variables = HashMap::>::new(); let mut params = HashMap::::new(); params.insert("token".to_string(), token.to_string()); params.insert("token_type".to_string(), "access_token".to_string()); variables.insert("params".to_string(), params); let gql = json!({ "query": format!("query {}($params: ValidateJWTTokenInput!) {{ {}(params: $params) {{ is_valid claims }} }}", operation, query_name), "operationName": operation, "variables": variables }); // println!("GraphQL Query: {}", gql); let client = HTTPClient::new(); let response = client .post(&auth_api_base) .headers(headers) .json(&gql) .send() .await?; if response.status().is_success() { let r: HashMap = response.json().await?; let user_id = r .get("data") .and_then(|data| data.get(query_name)) .and_then(|query| query.get("claims")) .and_then(|claims| claims.get("sub")) .and_then(|id| id.as_str()); match user_id { Some(id) => { println!("User ID retrieved: {}", id); let author_id = get_author_id(id).await?; Ok(author_id as i32) } None => { println!("No user ID found in the response"); Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, "No user ID found in the response", ))) } } } else { Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, format!("Request failed with status: {}", response.status()), ))) } } async fn get_shout_followers(shout_id: &str) -> Result, Box> { let api_base = env::var("API_BASE")?; let query = r#"query GetShoutFollowers($slug: String, shout_id: Int) { get_shout_followers(slug: $slug, shout_id: $shout_id) { id } } "#; let shout_id = shout_id.parse::()?; let variables = json!({ "shout": shout_id }); let body = json!({ "query": query, "operationName": "GetShoutFollowers", "variables": variables }); let client = reqwest::Client::new(); let response = client.post(&api_base).json(&body).send().await?; if response.status().is_success() { let response_body: serde_json::Value = response.json().await?; let ids: Vec = response_body["data"]["get_shout_followers"] .as_array() .ok_or("Failed to parse follower array")? .iter() .filter_map(|f| f["id"].as_i64().map(|id| id as i32)) .collect(); Ok(ids) } else { println!("Request failed with status: {}", response.status()); Err(Box::new(std::io::Error::new( std::io::ErrorKind::Other, format!("Request failed with status: {}", response.status()), ))) } } pub async fn is_fitting( listener_id: i32, message_data: SSEMessageData, ) -> Result { if message_data.entity == "reaction" { // payload is Reaction let shout_id = message_data.payload.get("shout").unwrap().as_str().unwrap(); let recipients = get_shout_followers(shout_id).await.unwrap(); Ok(recipients.contains(&listener_id)) } else if message_data.entity == "shout" { // payload is Shout // TODO: check all community subscribers if no then // TODO: check all topics subscribers if no then // TODO: check all authors subscribers Ok(true) } else if message_data.entity == "chat" { // payload is Chat Ok(true) } else if message_data.entity == "message" { // payload is Message Ok(true) } else if message_data.entity == "follower" { // payload is Author Ok(true) }else { eprintln!("[data] unknown entity"); eprintln!("{:?}", message_data); Ok(false) } }