From 3c29c26e791a03b6074b1aaf048c4199d1ec65dc Mon Sep 17 00:00:00 2001 From: Reinaldy Rafli Date: Fri, 12 Apr 2024 19:59:41 +0700 Subject: [PATCH] feat(registration_rust): conform with auth_rust changes --- registration_rust/Cargo.lock | 79 +----- registration_rust/Cargo.toml | 1 - registration_rust/src/main.rs | 467 ++++++++++++++++++++++++---------- 3 files changed, 333 insertions(+), 214 deletions(-) diff --git a/registration_rust/Cargo.lock b/registration_rust/Cargo.lock index 4bd86a3..1a73f54 100644 --- a/registration_rust/Cargo.lock +++ b/registration_rust/Cargo.lock @@ -26,21 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "async-compression" version = "0.4.8" @@ -56,9 +41,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", @@ -189,20 +174,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.4", -] - [[package]] name = "combine" version = "4.6.7" @@ -639,29 +610,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "idna" version = "0.5.0" @@ -815,15 +763,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - [[package]] name = "num_cpus" version = "1.16.0" @@ -1101,7 +1040,6 @@ name = "registration_rust" version = "0.1.0" dependencies = [ "axum", - "chrono", "rand", "redis", "reqwest 0.12.3", @@ -1605,9 +1543,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.35" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef89ece63debf11bc32d1ed8d078ac870cbeb44da02afb02a9ff135ae7ca0582" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -1985,15 +1923,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.4", -] - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/registration_rust/Cargo.toml b/registration_rust/Cargo.toml index 9a12baa..8f44c99 100644 --- a/registration_rust/Cargo.toml +++ b/registration_rust/Cargo.toml @@ -15,7 +15,6 @@ redis = { version = "0.25.3", features = ["tokio-comp", "aio"] } serde_json = "1.0.115" serde = { version = "1.0.197", features = ["derive"] } reqwest = { version = "0.12.3", features = ["json", "gzip"] } -chrono = "0.4.37" sentry = { version = "0.32.2", features = ["tracing", "UNSTABLE_metrics"] } tracing = { version = "0.1.40" } tracing-subscriber = { version = "0.3.18", features = ["std", "registry", "tracing"] } diff --git a/registration_rust/src/main.rs b/registration_rust/src/main.rs index cea2992..fcedcd0 100644 --- a/registration_rust/src/main.rs +++ b/registration_rust/src/main.rs @@ -1,15 +1,15 @@ -use std::{env, fmt}; -use std::error::Error; -use std::fmt::{Debug, Display, Formatter}; -use axum::{Json, Router, routing::get}; use axum::extract::{FromRef, State}; use axum::http::{header, StatusCode}; use axum::response::IntoResponse; use axum::routing::{post, put}; +use axum::{routing::get, Json, Router}; use rand::distributions::Alphanumeric; use rand::Rng; -use redis::{Client, RedisError, AsyncCommands, RedisResult}; +use redis::{AsyncCommands, Client, RedisError, RedisResult}; use serde::{Deserialize, Serialize}; +use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; +use std::{env, fmt}; use tokio::net::TcpListener; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; @@ -32,7 +32,6 @@ impl Display for PestoError { } } - #[derive(Clone)] struct ApplicationState { waiting_list_service: WaitingListService, @@ -57,9 +56,13 @@ struct HumanUser { #[derive(Debug, Deserialize, Serialize, Clone)] struct TokenValue { + #[serde(skip)] pub token: Option, + #[serde(rename = "UserEmail")] pub user_email: String, + #[serde(rename = "MonthlyLimit")] pub monthly_limit: i64, + #[serde(rename = "Revoked")] pub revoked: bool, } @@ -69,10 +72,16 @@ struct PestoToken { } #[derive(Clone)] -struct WaitingListService where Command: Clone { +struct WaitingListService +where + Command: Clone, +{ pub redis_client: Command, } -impl FromRef> for WaitingListService { + +impl FromRef> + for WaitingListService +{ fn from_ref(input: &ApplicationState) -> Self { input.waiting_list_service.clone() } @@ -80,7 +89,7 @@ impl FromRef> for Wait impl Debug for WaitingListService { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "WaitingListService") + write!(f, "WaitingListService") } } @@ -97,21 +106,28 @@ impl WaitingListService { }; // Check if the user's email already exists on the waiting list - let email_exists = users.iter().any(|waiting_list_user| waiting_list_user.email == human_user.email); + let email_exists = users + .iter() + .any(|waiting_list_user| waiting_list_user.email == human_user.email); if email_exists { return Err(PestoError::EmailAlreadyExists); } // Email not exists, let's serialize human_user struct and insert it into Redis - let serialized_user = serde_json::to_string(&human_user).map_err(|_| PestoError::ParseError)?; - self.redis_client.rpush("waiting-list", serialized_user).await.map_err(|e| PestoError::RedisError(e))?; + let serialized_user = + serde_json::to_string(&human_user).map_err(|_| PestoError::ParseError)?; + self.redis_client + .rpush("waiting-list", serialized_user) + .await + .map_err(|e| PestoError::RedisError(e))?; Ok(()) } #[tracing::instrument] async fn get_users(&mut self) -> Result, PestoError> { - let waiting_list_result: RedisResult>> = self.redis_client.lrange("waiting-list", 0, -1).await; + let waiting_list_result: RedisResult>> = + self.redis_client.lrange("waiting-list", 0, -1).await; let waiting_list = match waiting_list_result { Ok(Some(users)) => users, @@ -121,7 +137,8 @@ impl WaitingListService { let mut users = Vec::new(); for value in waiting_list { - let user = serde_json::from_str::(&value).map_err(|_| PestoError::ParseError)?; + let user = + serde_json::from_str::(&value).map_err(|_| PestoError::ParseError)?; users.push(user); } @@ -133,16 +150,24 @@ impl WaitingListService { let users: Vec = self.get_users().await?; // Filter out user - let filtered_waiting_list_users = users.iter() + let filtered_waiting_list_users = users + .iter() .filter(|waiting_list_user| waiting_list_user.email != human_user.email); // Delete the key - self.redis_client.del("waiting-list").await.map_err(|e| PestoError::RedisError(e))?; + self.redis_client + .del("waiting-list") + .await + .map_err(|e| PestoError::RedisError(e))?; // Insert the remaining users for value in filtered_waiting_list_users { - let serialized_user = serde_json::to_string(value).map_err(|_| PestoError::ParseError)?; - self.redis_client.rpush("waiting-list", serialized_user).await.map_err(|e| PestoError::RedisError(e))?; + let serialized_user = + serde_json::to_string(value).map_err(|_| PestoError::ParseError)?; + self.redis_client + .rpush("waiting-list", serialized_user) + .await + .map_err(|e| PestoError::RedisError(e))?; } Ok(()) @@ -150,11 +175,16 @@ impl WaitingListService { } #[derive(Clone)] -struct ApprovalService where Command: Clone { +struct ApprovalService +where + Command: Clone, +{ pub redis_client: Command, } -impl FromRef> for ApprovalService { +impl FromRef> + for ApprovalService +{ fn from_ref(input: &ApplicationState) -> Self { input.approval_service.clone() } @@ -180,9 +210,13 @@ impl ApprovalService { revoked: false, }; - let serialized_user = serde_json::to_string(®istered_user).map_err(|_| PestoError::ParseError)?; + let serialized_user = + serde_json::to_string(®istered_user).map_err(|_| PestoError::ParseError)?; - self.redis_client.set(registered_user.token, serialized_user).await.map_err(|e| PestoError::RedisError(e))?; + self.redis_client + .set(registered_user.token, serialized_user) + .await + .map_err(|e| PestoError::RedisError(e))?; Ok(()) } @@ -196,9 +230,13 @@ impl ApprovalService { revoked: true, }; - let serialized_user = serde_json::to_string(®istered_user).map_err(|_| PestoError::ParseError)?; + let serialized_user = + serde_json::to_string(®istered_user).map_err(|_| PestoError::ParseError)?; - self.redis_client.set(registered_user.token, serialized_user).await.map_err(|e| PestoError::RedisError(e))?; + self.redis_client + .set(registered_user.token, serialized_user) + .await + .map_err(|e| PestoError::RedisError(e))?; Ok(()) } @@ -209,9 +247,10 @@ impl ApprovalService { match registered_user { Ok(Some(user)) => { - let token_value = serde_json::from_str::(&user).map_err(|_| PestoError::ParseError)?; + let token_value = serde_json::from_str::(&user) + .map_err(|_| PestoError::ParseError)?; Ok(token_value) - }, + } Ok(None) => Err(PestoError::UserNotFound), Err(e) => Err(PestoError::RedisError(e)), } @@ -219,7 +258,10 @@ impl ApprovalService { } #[derive(Clone)] -struct TrialService where Command: Clone { +struct TrialService +where + Command: Clone, +{ pub redis_client: Command, } @@ -243,7 +285,7 @@ impl TrialService { #[tracing::instrument] async fn create_token(&mut self) -> Result { let token = format!("TRIAL-{}", self.random_string(64 - 6)); - let user_email = format!("trial-{}@pesto.teknologiumum.com",self.random_string(20)); + let user_email = format!("trial-{}@pesto.teknologiumum.com", self.random_string(20)); let registered_user = TokenValue { token: Some(token.clone()), @@ -252,9 +294,13 @@ impl TrialService { revoked: false, }; - let serialized_user = serde_json::to_string(®istered_user).map_err(|_| PestoError::ParseError)?; + let serialized_user = + serde_json::to_string(®istered_user).map_err(|_| PestoError::ParseError)?; - self.redis_client.set_ex(token.clone(), serialized_user, 24 * 60 * 60).await.map_err(|e| PestoError::RedisError(e))?; + self.redis_client + .set_ex(token.clone(), serialized_user, 24 * 60 * 60) + .await + .map_err(|e| PestoError::RedisError(e))?; Ok(token) } @@ -342,58 +388,71 @@ impl Error for MailersendError {} impl MailersendClient { fn new(api_key: String) -> Self { - Self { api_key, client: reqwest::Client::new() } + Self { + api_key, + client: reqwest::Client::new(), + } } - async fn send_email(&self, destination: String, subject: String, text: String, html: String) -> Result<(), MailersendError> { + #[tracing::instrument] + async fn send_email( + &self, + destination: String, + subject: String, + text: String, + html: String, + ) -> Result<(), MailersendError> { let payload = MailersendEmailPayload { from: MailersendEmailFrom { email: String::from("pesto@teknologiumum.com"), name: String::from("Pesto from Teknologi Umum"), }, - to: vec![MailersendEmailTo { email: destination, name: String::new() }], + to: vec![MailersendEmailTo { + email: destination, + name: String::new(), + }], subject, text, html, }; - let client = self.client.post("https://api.mailersend.com/v1/email") + let client = self + .client + .post("https://api.mailersend.com/v1/email") .header("Content-Type", "application/json") .header("Authorization", format!("Bearer {}", self.api_key)) .json(&payload); match client.send().await { - Ok(response) => { - match response.status() { - StatusCode::OK => Ok(()), - StatusCode::BAD_REQUEST => { - let error = response.text().await.unwrap_or_default(); - Err(MailersendError::BadRequest(error)) - }, - StatusCode::UNAUTHORIZED => Err(MailersendError::Unauthorized), - StatusCode::FORBIDDEN => Err(MailersendError::Forbidden), - StatusCode::NOT_FOUND => Err(MailersendError::NotFound), - StatusCode::REQUEST_TIMEOUT => Err(MailersendError::RequestTimeout), - StatusCode::SERVICE_UNAVAILABLE => { - let error = response.text().await.unwrap_or_default(); - Err(MailersendError::UnderMaintenance(error)) - }, - StatusCode::UNPROCESSABLE_ENTITY => { - let error = response.text().await.unwrap_or_default(); - Err(MailersendError::UnprocessableEntity(error)) - }, - StatusCode::TOO_MANY_REQUESTS => { - let error = response.text().await.unwrap_or_default(); - Err(MailersendError::TooManyRequest(error)) - }, - StatusCode::INTERNAL_SERVER_ERROR => { - let error = response.text().await.unwrap_or_default(); - Err(MailersendError::InternalServerError(error)) - }, - _ => { - let error = response.text().await.unwrap_or_default(); - Err(MailersendError::NetworkError(error)) - } + Ok(response) => match response.status() { + StatusCode::OK => Ok(()), + StatusCode::BAD_REQUEST => { + let error = response.text().await.unwrap_or_default(); + Err(MailersendError::BadRequest(error)) + } + StatusCode::UNAUTHORIZED => Err(MailersendError::Unauthorized), + StatusCode::FORBIDDEN => Err(MailersendError::Forbidden), + StatusCode::NOT_FOUND => Err(MailersendError::NotFound), + StatusCode::REQUEST_TIMEOUT => Err(MailersendError::RequestTimeout), + StatusCode::SERVICE_UNAVAILABLE => { + let error = response.text().await.unwrap_or_default(); + Err(MailersendError::UnderMaintenance(error)) + } + StatusCode::UNPROCESSABLE_ENTITY => { + let error = response.text().await.unwrap_or_default(); + Err(MailersendError::UnprocessableEntity(error)) + } + StatusCode::TOO_MANY_REQUESTS => { + let error = response.text().await.unwrap_or_default(); + Err(MailersendError::TooManyRequest(error)) + } + StatusCode::INTERNAL_SERVER_ERROR => { + let error = response.text().await.unwrap_or_default(); + Err(MailersendError::InternalServerError(error)) + } + _ => { + let error = response.text().await.unwrap_or_default(); + Err(MailersendError::NetworkError(error)) } }, Err(e) => { @@ -404,12 +463,11 @@ impl MailersendClient { } } - async fn healthcheck() -> impl IntoResponse { (StatusCode::OK, "OK") } -#[tracing::instrument] +#[tracing::instrument(name = "POST /api/register", fields(op = "http.server", http.request.method = "POST"))] async fn register( State(mut waiting_list_service): State>, Json(body): Json, @@ -417,19 +475,35 @@ async fn register( let result = waiting_list_service.put_user_in_waiting_list(body).await; match result { - Ok(_) => (StatusCode::CREATED, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Created"}"#), - Err(PestoError::EmailAlreadyExists) => (StatusCode::ACCEPTED, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Accepted"}"#), + Ok(_) => ( + StatusCode::CREATED, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Created"}"#, + ), + Err(PestoError::EmailAlreadyExists) => ( + StatusCode::ACCEPTED, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Accepted"}"#, + ), Err(PestoError::RedisError(error)) => { sentry::capture_error(&error); - (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#) + ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ) } - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#) + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ), } } -#[tracing::instrument] +#[tracing::instrument(name = "GET /api/pending", fields(op = "http.server", http.request.method = "GET"))] async fn pending_users( - State(mut waiting_list_service): State> + State(mut waiting_list_service): State>, ) -> impl IntoResponse { let result = waiting_list_service.get_users().await; @@ -437,20 +511,38 @@ async fn pending_users( Ok(users) => { let serialized_users = match serde_json::to_string(&users) { Ok(serialized_users) => serialized_users, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#.to_string()) + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#.to_string(), + ) + } }; - (StatusCode::OK, [(header::CONTENT_TYPE, "application/json")], serialized_users) - }, + ( + StatusCode::OK, + [(header::CONTENT_TYPE, "application/json")], + serialized_users, + ) + } Err(PestoError::RedisError(error)) => { sentry::capture_error(&error); - (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#.to_string()) + ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#.to_string(), + ) } - Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#.to_string()) + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#.to_string(), + ), } } -#[tracing::instrument] +#[tracing::instrument(name = "PUT /api/approve", fields(op = "http.server", http.request.method = "PUT"))] async fn approve_user( State(mut waiting_list_service): State>, State(mut approval_service): State>, @@ -461,22 +553,37 @@ async fn approve_user( Ok(waiting_list) => waiting_list, Err(PestoError::RedisError(error)) => { sentry::capture_error(&error); - return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#); - }, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#), + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ); + } + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ) + } }; // Check if email exists on the waiting list - let user: Option<&HumanUser> = waiting_list.iter().find(|waiting_list_user| waiting_list_user.email == body.user_email); + let user: Option<&HumanUser> = waiting_list + .iter() + .find(|waiting_list_user| waiting_list_user.email == body.user_email); // XXX(reinaldy): we should refactor this hadouken pattern later match user { None => { - return (StatusCode::BAD_REQUEST, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Email does not exists"}"#); - }, - Some(user) => { - match approval_service.approve_user(body).await { - Ok(_) => { - let _ = mailersend_client.send_email( + return ( + StatusCode::BAD_REQUEST, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Email does not exists"}"#, + ); + } + Some(user) => match approval_service.approve_user(body).await { + Ok(_) => { + let _ = mailersend_client.send_email( user.email.clone(), "Your Pesto (the remote code execution engine) token!".to_string(), format!(r#"Hello, {}! 👋 @@ -496,71 +603,140 @@ Thank you! Have a great day."#, user.name.clone(), user.email.clone()), error }); - match waiting_list_service.remove_user(user.clone()).await { - Ok(_) => (StatusCode::OK, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"OK"}"#), - Err(PestoError::RedisError(error)) => { - sentry::capture_error(&error); - return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#); - }, - Err(_) => return (StatusCode::BAD_REQUEST, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"User seemed to be removed from waiting list already"}"#), + match waiting_list_service.remove_user(user.clone()).await { + Ok(_) => ( + StatusCode::OK, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"OK"}"#, + ), + Err(PestoError::RedisError(error)) => { + sentry::capture_error(&error); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ); + } + Err(_) => { + return ( + StatusCode::BAD_REQUEST, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"User seemed to be removed from waiting list already"}"#, + ) } - }, - Err(PestoError::RedisError(error)) => { - sentry::capture_error(&error); - return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#); - }, - Err(_) => { - return (StatusCode::BAD_REQUEST, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"User seemed to be approved already"}"#); } } - } + Err(PestoError::RedisError(error)) => { + sentry::capture_error(&error); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ); + } + Err(_) => { + return ( + StatusCode::BAD_REQUEST, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"User seemed to be approved already"}"#, + ); + } + }, } } -#[tracing::instrument] +#[tracing::instrument(name = "PUT /api/revoke", fields(op = "http.server", http.request.method = "PUT"))] async fn revoke_user( State(mut approval_service): State>, Json(pesto_token): Json, ) -> impl IntoResponse { - let registered_user: TokenValue = match approval_service.get_user_by_token(pesto_token.token).await { - Ok(registered_user) => registered_user, - Err(PestoError::UserNotFound) => return (StatusCode::BAD_REQUEST, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"User does not exists"}"#), - Err(PestoError::RedisError(error)) => { - sentry::capture_error(&error); - return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#); - }, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#), - }; + let registered_user: TokenValue = + match approval_service.get_user_by_token(pesto_token.token).await { + Ok(registered_user) => registered_user, + Err(PestoError::UserNotFound) => { + return ( + StatusCode::BAD_REQUEST, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"User does not exists"}"#, + ) + } + Err(PestoError::RedisError(error)) => { + sentry::capture_error(&error); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ); + } + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ) + } + }; match approval_service.revoke_user(registered_user).await { - Ok(_) => (StatusCode::OK, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"OK"}"#), + Ok(_) => ( + StatusCode::OK, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"OK"}"#, + ), Err(PestoError::RedisError(error)) => { sentry::capture_error(&error); - (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#) - }, - Err(_) => (StatusCode::BAD_REQUEST, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"User seemed to be revoked already"}"#), + ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#, + ) + } + Err(_) => ( + StatusCode::BAD_REQUEST, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"User seemed to be revoked already"}"#, + ), } } -#[tracing::instrument] +#[tracing::instrument(name = "POST /api/trial", fields(op = "http.server", http.request.method = "POST"))] async fn user_trial( - State(mut trial_service): State> + State(mut trial_service): State>, ) -> impl IntoResponse { match trial_service.create_token().await { Ok(token) => { let serialized_token = match serde_json::to_string(&PestoToken { token }) { Ok(out) => out, - Err(_) => return - (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#.to_string()) + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#.to_string(), + ) + } }; - (StatusCode::OK, [(header::CONTENT_TYPE, "application/json")], serialized_token) - }, + ( + StatusCode::OK, + [(header::CONTENT_TYPE, "application/json")], + serialized_token, + ) + } Err(PestoError::RedisError(error)) => { sentry::capture_error(&error); - return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#.to_string()); - }, - Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, [(header::CONTENT_TYPE, "application/json")], r#"{"message":"Internal Server Error"}"#.to_string()), + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#.to_string(), + ); + } + Err(_) => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + [(header::CONTENT_TYPE, "application/json")], + r#"{"message":"Internal Server Error"}"#.to_string(), + ) + } } } @@ -569,24 +745,34 @@ fn main() -> Result<(), Box> { .with(sentry::integrations::tracing::layer()) .init(); - let _guard = sentry::init((env::var("SENTRY_DSN").unwrap_or_default(), sentry::ClientOptions { - release: sentry::release_name!(), - sample_rate: 1.0, - traces_sample_rate: 0.5, - ..Default::default() - })); + let _guard = sentry::init(( + env::var("SENTRY_DSN").unwrap_or_default(), + sentry::ClientOptions { + release: sentry::release_name!(), + sample_rate: 1.0, + traces_sample_rate: 0.5, + ..Default::default() + }, + )); tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .unwrap() .block_on(async { - let redis_client = Client::open(env::var("REDIS_URL").unwrap_or("redis://@localhost:6379".to_string())).unwrap(); - let redis_async_connection = redis_client.get_multiplexed_async_connection().await.unwrap(); + let redis_client = Client::open( + env::var("REDIS_URL").unwrap_or("redis://@localhost:6379".to_string()), + ) + .unwrap(); + let redis_async_connection = redis_client + .get_multiplexed_async_connection() + .await + .unwrap(); let approval_service = ApprovalService::new(redis_async_connection.clone()); let trial_service = TrialService::new(redis_async_connection.clone()); let waiting_list_service = WaitingListService::new(redis_async_connection); - let mailersend_client = MailersendClient::new(env::var("MAILERSEND_API_KEY").unwrap_or_default()); + let mailersend_client = + MailersendClient::new(env::var("MAILERSEND_API_KEY").unwrap_or_default()); let application_state = ApplicationState { waiting_list_service, @@ -604,9 +790,14 @@ fn main() -> Result<(), Box> { .route("/api/trial", post(user_trial)) .with_state(application_state); - let listener = TcpListener::bind(format!("0.0.0.0:{}", env::var("PORT").unwrap_or("3000".to_string()))).await.unwrap(); + let listener = TcpListener::bind(format!( + "0.0.0.0:{}", + env::var("PORT").unwrap_or("3000".to_string()) + )) + .await + .unwrap(); axum::serve(listener, app).await.unwrap(); }); Ok(()) -} \ No newline at end of file +}