From 2ebb0b165d1f00f0885e32c06f0817666447cbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Thu, 4 Apr 2024 19:05:51 +0300 Subject: [PATCH] test: :white_check_mark: search_id, search_id_non feat: :sparkles: routing feat: :sparkles: search id --- .gitignore | 1 + Cargo.toml | 2 +- src/db/db_operations.rs | 33 +++++----- src/db/db_utils.rs | 38 +++++------ src/lib.rs | 20 +++++- src/main.rs | 22 ++++--- src/routing.rs | 143 ++++++++++++++++++++++++++++++++++++++-- src/tests/db_tests.rs | 79 +++++++++++++++------- src/utils.rs | 35 ++++++++++ 9 files changed, 296 insertions(+), 77 deletions(-) create mode 100644 src/utils.rs diff --git a/.gitignore b/.gitignore index 0e1ea6d..0020430 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ debug/ target/ .vscode/ certificates/ +configs/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html diff --git a/Cargo.toml b/Cargo.toml index 8a56ab0..4b93e9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -axum = "0.7.5" +axum = { version = "0.7.5", features = ["macros"] } axum-server = { version = "0.6.0", features = ["tls-rustls"] } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" diff --git a/src/db/db_operations.rs b/src/db/db_operations.rs index ccfe7d6..cdd4098 100644 --- a/src/db/db_operations.rs +++ b/src/db/db_operations.rs @@ -1,11 +1,18 @@ use surrealdb::{engine::remote::ws::Client, Surreal}; -use crate::Channel; +use crate::{Channel, DataBaseConfig}; use super::db_utils::*; -pub async fn connect() -> Option> { - establish_connection().await +pub async fn connect(database_config: &DataBaseConfig) -> Option> { + establish_connection( + &database_config.address, + &database_config.username, + &database_config.password, + &database_config.namespace, + &database_config.database, + ) + .await } pub async fn create(username: &String, db: &Surreal) -> Option { @@ -15,13 +22,15 @@ pub async fn create(username: &String, db: &Surreal) -> Option } } -pub async fn search(username: &String, db: &Surreal) -> Option { +pub async fn search_username(username: &String, db: &Surreal) -> Option { search_channel_by_username(username, db).await } +pub async fn search_id(id: &String, db: &Surreal) -> Option { + search_channel_by_id(&id.into(), db).await +} + pub async fn delete(username: &String, db: &Surreal) -> Option { - // delete channel should be last for mind sake - // first artifacts match search_channel_by_username(username, db).await { Some(channel) => match remove_all_followers(channel.clone(), db).await { Some(_) => match remove_all_followed(channel.clone(), db).await { @@ -41,18 +50,6 @@ pub async fn delete(username: &String, db: &Surreal) -> Option None } } - // match delete_channel(username, db).await { - // Some(deleted_channel) => { - // match remove_follower_artifacts(deleted_channel.clone(), db).await { - // Some(_) => match remove_banned_artifacts(deleted_channel.clone(), db).await { - // Some(_) => Some(deleted_channel), - // None => None, - // }, - // None => None, - // } - // } - // None => None, - // } } pub async fn change_username( diff --git a/src/db/db_utils.rs b/src/db/db_utils.rs index ce7fe73..f9917c4 100644 --- a/src/db/db_utils.rs +++ b/src/db/db_utils.rs @@ -7,29 +7,27 @@ use surrealdb::{ }; use super::db_operations::{unban, unfollow}; -pub async fn establish_connection() -> Option> { - match Surreal::new::("127.0.0.1:8000").await { - Ok(db) => { - match db - .signin(Root { - username: "root", - password: "root", - }) - .await - { - Ok(_) => match db.use_ns("test").use_db("test").await { - Ok(_) => Some(db), - Err(err_val) => { - eprintln!("Error: DB Use | {}", err_val); - None - } - }, +pub async fn establish_connection( + address: &String, + username: &String, + password: &String, + namespace: &String, + database: &String, +) -> Option> { + match Surreal::new::(address).await { + Ok(db) => match db.signin(Root { username, password }).await { + Ok(_) => match db.use_ns(namespace).use_db(database).await { + Ok(_) => Some(db), Err(err_val) => { - eprintln!("Error: DB Login | {}", err_val); + eprintln!("Error: DB Use | {}", err_val); None } + }, + Err(err_val) => { + eprintln!("Error: DB Login | {}", err_val); + None } - } + }, Err(err_val) => { eprintln!("Error: DB Connection | {}", err_val); None @@ -37,7 +35,7 @@ pub async fn establish_connection() -> Option> { } } -async fn search_channel_by_id(id: &Id, db: &Surreal) -> Option { +pub async fn search_channel_by_id(id: &Id, db: &Surreal) -> Option { let searced: Option = db.select(("channel", id.clone())).await.unwrap(); searced } diff --git a/src/lib.rs b/src/lib.rs index 9e67b58..969873a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,28 @@ use serde::{Deserialize, Serialize}; -use surrealdb::sql::{Id, Thing}; +use surrealdb::{ + engine::remote::ws::Client, + sql::{Id, Thing}, + Surreal, +}; pub mod db; pub mod routing; pub mod tests; +pub mod utils; #[derive(Debug, Clone)] -pub struct AppState {} +pub struct DataBaseConfig { + pub address: String, + pub username: String, + pub password: String, + pub namespace: String, + pub database: String, +} + +#[derive(Debug, Clone)] +pub struct AppState { + pub db: Surreal, +} #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Channel { diff --git a/src/main.rs b/src/main.rs index d8f012e..3b849b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,9 @@ -use acapair_follow_ban_api::{routing, AppState}; -use axum_server::tls_rustls::RustlsConfig; +use acapair_follow_ban_api::{ + db::db_operations::connect, + routing, + utils::{database_config, tls_config}, + AppState, +}; use std::{env, net::SocketAddr}; fn take_args() -> String { @@ -14,17 +18,19 @@ fn take_args() -> String { #[tokio::main] async fn main() { println!("Hello, world!"); - let config = - RustlsConfig::from_pem_file("certificates/fullchain.pem", "certificates/privkey.pem") - .await - .unwrap(); + let tls_config = tls_config().await; + let database_config = database_config().await; - let state = AppState {}; + println!("{:#?}", database_config); + + let state = AppState { + db: connect(&database_config).await.unwrap(), + }; let app = routing::routing(axum::extract::State(state)).await; let addr = SocketAddr::from(take_args().parse::().unwrap()); - axum_server::bind_rustls(addr, config) + axum_server::bind_rustls(addr, tls_config) .serve(app.into_make_service()) .await .unwrap(); diff --git a/src/routing.rs b/src/routing.rs index 0a24bf1..00ed022 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -1,17 +1,35 @@ -use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; +use axum::{ + extract::{Path, State}, + http::StatusCode, + response::IntoResponse, + routing::get, + Json, Router, +}; use tower_http::cors::CorsLayer; -use crate::{db::db_operations, AppState}; +use crate::{db::db_operations, utils::database_config, AppState}; pub async fn routing(State(state): State) -> Router { Router::new() .route("/", get(alive)) + .route("/create/:username", get(create)) + .route("/delete/:username", get(delete)) + .route("/search-username/:username", get(search_username)) + .route("/search-id/:id", get(search_id)) + .route( + "/change-username/:username/:updated_username", + get(change_username), + ) + .route("/follow/:follower/:followed", get(follow)) + .route("/unfollow/:follower/:followed", get(unfollow)) + .route("/ban/:victim/:judge", get(ban)) + .route("/unban/:victim/:judge", get(unban)) .layer(CorsLayer::permissive()) .with_state(state.clone()) } async fn alive() -> impl IntoResponse { - let ping = match db_operations::connect().await { + let ping = match db_operations::connect(&database_config().await).await { Some(_) => "Alive", None => "Dead", }; @@ -19,6 +37,123 @@ async fn alive() -> impl IntoResponse { "server_status":"Alive", "database_status":ping, }); - println!("{}", alive_json); (StatusCode::OK, Json(alive_json)) } + +async fn create(Path(username): Path, State(state): State) -> impl IntoResponse { + match db_operations::create(&username, &state.db).await { + Some(channel) => { + let create = serde_json::json!({ + "channel":channel, + }); + (StatusCode::CREATED, Json(create)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn delete(Path(username): Path, State(state): State) -> impl IntoResponse { + match db_operations::delete(&username, &state.db).await { + Some(channel) => { + let delete = serde_json::json!({ + "channel":channel, + }); + (StatusCode::NO_CONTENT, Json(delete)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn search_username( + Path(username): Path, + State(state): State, +) -> impl IntoResponse { + match db_operations::search_username(&username, &state.db).await { + Some(channel) => { + let search_username = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(search_username)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn search_id(Path(id): Path, State(state): State) -> impl IntoResponse { + match db_operations::search_id(&id, &state.db).await { + Some(channel) => { + let search_id = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(search_id)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn change_username( + Path((username, updated_username)): Path<(String, String)>, + State(state): State, +) -> impl IntoResponse { + match db_operations::change_username(&updated_username, &username, &state.db).await { + Some(channel) => { + let change_username = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(change_username)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn follow( + Path((follower, followed)): Path<(String, String)>, + State(state): State, +) -> impl IntoResponse { + match db_operations::follow(&follower, &followed, &state.db).await { + Some(channel) => { + let follow = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(follow)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn unfollow( + Path((follower, followed)): Path<(String, String)>, + State(state): State, +) -> impl IntoResponse { + match db_operations::unfollow(&follower, &followed, &state.db).await { + Some(channel) => { + let unfollow = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(unfollow)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn ban( + Path((victim, judge)): Path<(String, String)>, + State(state): State, +) -> impl IntoResponse { + match db_operations::ban(&victim, &judge, &state.db).await { + Some(channel) => { + let ban = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(ban)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} +async fn unban( + Path((victim, judge)): Path<(String, String)>, + State(state): State, +) -> impl IntoResponse { + match db_operations::unban(&victim, &judge, &state.db).await { + Some(channel) => { + let unban = serde_json::json!({ + "channel":channel, + }); + (StatusCode::OK, Json(unban)) + } + None => (StatusCode::NOT_ACCEPTABLE, Json(serde_json::json!(""))), + } +} diff --git a/src/tests/db_tests.rs b/src/tests/db_tests.rs index 99b09d4..f133c47 100644 --- a/src/tests/db_tests.rs +++ b/src/tests/db_tests.rs @@ -22,7 +22,14 @@ async fn create_connection_for_tests( #[test] async fn test_connect() { - assert_eq!(connect().await.is_some(), true); + assert_eq!( + create_connection_for_tests("test_connect") + .await + .health() + .await + .is_ok(), + true + ); } #[test] async fn test_create() { @@ -37,12 +44,26 @@ async fn test_create() { } #[test] -async fn test_search() { - let connection = create_connection_for_tests("test_search").await; +async fn test_search_username() { + let connection = create_connection_for_tests("test_search_username").await; + let name = &"Ahmet".to_string(); + + let created = create(name, &connection).await; + let searched = search_username(name, &connection).await; + + assert_eq!(created, searched); + + let _cleaning = connection.query("DELETE channel;").await; +} + +#[test] +async fn test_search_id() { + let connection = create_connection_for_tests("test_search_username").await; let name = &"Ahmet".to_string(); let created = create(name, &connection).await; - let searched = search(name, &connection).await; + let id = &created.clone().unwrap().id.unwrap().id.to_string(); + let searched = search_id(id, &connection).await; assert_eq!(created, searched); @@ -58,7 +79,7 @@ async fn test_delete() { let deleted = delete(name, &connection).await; assert_eq!(created, deleted); - assert_eq!(search(name, &connection).await.is_none(), true); + assert_eq!(search_username(name, &connection).await.is_none(), true); let _cleaning = connection.query("DELETE channel;").await; } @@ -91,7 +112,7 @@ async fn test_follow() { let mut follower = follow(name_follower, name_followed, &connection) .await .unwrap(); - let mut followed = search(name_followed, &connection).await.unwrap(); + let mut followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!( followed.follower_list.pop().unwrap(), @@ -117,7 +138,7 @@ async fn test_unfollow() { let mut follower = follow(name_follower, name_followed, &connection) .await .unwrap(); - let mut followed = search(name_followed, &connection).await.unwrap(); + let mut followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!( followed.follower_list.pop().unwrap(), @@ -131,7 +152,7 @@ async fn test_unfollow() { follower = unfollow(name_follower, name_followed, &connection) .await .unwrap(); - followed = search(name_followed, &connection).await.unwrap(); + followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!(followed.follower_list.pop().is_none(), true); assert_eq!(follower.followed_list.pop().is_none(), true); @@ -149,7 +170,7 @@ async fn test_ban() { let _judge = create(name_judge, &connection).await.unwrap(); let mut victim = ban(name_victim, name_judge, &connection).await.unwrap(); - let mut judge = search(name_judge, &connection).await.unwrap(); + let mut judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(victim.banned_from_list.pop().unwrap(), judge.id.unwrap().id); assert_eq!(judge.banned_list.pop().unwrap(), victim.id.unwrap().id); @@ -167,13 +188,13 @@ async fn test_unban() { let _judge = create(name_judge, &connection).await.unwrap(); let mut victim = ban(name_victim, name_judge, &connection).await.unwrap(); - let mut judge = search(name_judge, &connection).await.unwrap(); + let mut judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(victim.banned_from_list.pop().unwrap(), judge.id.unwrap().id); assert_eq!(judge.banned_list.pop().unwrap(), victim.id.unwrap().id); victim = unban(name_victim, name_judge, &connection).await.unwrap(); - judge = search(name_judge, &connection).await.unwrap(); + judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(victim.banned_from_list.pop().is_none(), true); assert_eq!(judge.banned_list.pop().is_none(), true); @@ -193,7 +214,7 @@ async fn test_delete_follower() { let mut follower = follow(name_follower, name_followed, &connection) .await .unwrap(); - let mut followed = search(name_followed, &connection).await.unwrap(); + let mut followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!( followed.follower_list.pop().unwrap(), @@ -205,7 +226,7 @@ async fn test_delete_follower() { ); follower = delete(name_follower, &connection).await.unwrap(); - followed = search(name_followed, &connection).await.unwrap(); + followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!(followed.follower_list.pop().is_none(), true); assert_eq!(follower.followed_list.pop().is_none(), true); @@ -225,7 +246,7 @@ async fn test_delete_followed() { let mut follower = follow(name_follower, name_followed, &connection) .await .unwrap(); - let mut followed = search(name_followed, &connection).await.unwrap(); + let mut followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!( followed.follower_list.pop().unwrap(), @@ -237,7 +258,7 @@ async fn test_delete_followed() { ); followed = delete(name_followed, &connection).await.unwrap(); - follower = search(name_follower, &connection).await.unwrap(); + follower = search_username(name_follower, &connection).await.unwrap(); assert_eq!(followed.follower_list.pop().is_none(), true); assert_eq!(follower.followed_list.pop().is_none(), true); @@ -255,13 +276,13 @@ async fn test_delete_victim() { let _judge = create(name_judge, &connection).await.unwrap(); let mut victim = ban(name_victim, name_judge, &connection).await.unwrap(); - let mut judge = search(name_judge, &connection).await.unwrap(); + let mut judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(judge.banned_list.pop().unwrap(), victim.id.unwrap().id); assert_eq!(victim.banned_from_list.pop().unwrap(), judge.id.unwrap().id); victim = delete(name_victim, &connection).await.unwrap(); - judge = search(name_judge, &connection).await.unwrap(); + judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(judge.banned_list.pop().is_none(), true); assert_eq!(victim.banned_from_list.pop().is_none(), true); @@ -279,13 +300,13 @@ async fn test_delete_judge() { let _judge = create(name_judge, &connection).await.unwrap(); let mut victim = ban(name_victim, name_judge, &connection).await.unwrap(); - let mut judge = search(name_judge, &connection).await.unwrap(); + let mut judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(judge.banned_list.pop().unwrap(), victim.id.unwrap().id); assert_eq!(victim.banned_from_list.pop().unwrap(), judge.id.unwrap().id); judge = delete(name_judge, &connection).await.unwrap(); - victim = search(name_victim, &connection).await.unwrap(); + victim = search_username(name_victim, &connection).await.unwrap(); assert_eq!(judge.banned_list.pop().is_none(), true); assert_eq!(victim.banned_from_list.pop().is_none(), true); @@ -305,7 +326,7 @@ async fn test_follow_already_follower() { let mut follower = follow(name_follower, name_followed, &connection) .await .unwrap(); - let mut followed = search(name_followed, &connection).await.unwrap(); + let mut followed = search_username(name_followed, &connection).await.unwrap(); assert_eq!( followed.follower_list.pop().unwrap(), @@ -352,7 +373,7 @@ async fn test_ban_already_banned() { let _judge = create(name_judge, &connection).await.unwrap(); let mut victim = ban(name_victim, name_judge, &connection).await.unwrap(); - let mut judge = search(name_judge, &connection).await.unwrap(); + let mut judge = search_username(name_judge, &connection).await.unwrap(); assert_eq!(victim.banned_from_list.pop().unwrap(), judge.id.unwrap().id); assert_eq!(judge.banned_list.pop().unwrap(), victim.id.unwrap().id); @@ -405,11 +426,21 @@ async fn test_create_already_created() { } #[test] -async fn test_search_noncreated() { - let connection = create_connection_for_tests("test_search_noncreated").await; +async fn test_search_username_noncreated() { + let connection = create_connection_for_tests("test_search_username_noncreated").await; + let name = &"Ahmet".to_string(); + + assert_eq!(search_username(name, &connection).await.is_none(), true); + + let _cleaning = connection.query("DELETE channel;").await; +} + +#[test] +async fn test_search_id_noncreated() { + let connection = create_connection_for_tests("test_search_id_noncreated").await; let name = &"Ahmet".to_string(); - assert_eq!(search(name, &connection).await.is_none(), true); + assert_eq!(search_id(name, &connection).await.is_none(), true); let _cleaning = connection.query("DELETE channel;").await; } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..a05e0c4 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,35 @@ +use axum_server::tls_rustls::RustlsConfig; +use tokio::{fs::File, io::AsyncReadExt}; + +use crate::DataBaseConfig; + +pub async fn tls_config() -> RustlsConfig { + RustlsConfig::from_pem_file("certificates/fullchain.pem", "certificates/privkey.pem") + .await + .unwrap() +} + +pub async fn database_config() -> DataBaseConfig { + let mut config_file = File::open("configs/databaseconfig").await.unwrap(); + let mut config_unparsed = String::new(); + config_file + .read_to_string(&mut config_unparsed) + .await + .unwrap(); + + let configs_parsed: Vec<&str> = config_unparsed.split_terminator("\n").collect(); + let mut configs_cleaned: Vec<&str> = vec![]; + + for element in configs_parsed { + let dirty: Vec<&str> = element.split(": ").collect(); + configs_cleaned.push(dirty[1]); + } + + DataBaseConfig { + address: configs_cleaned[0].to_string(), + username: configs_cleaned[1].to_string(), + password: configs_cleaned[2].to_string(), + namespace: configs_cleaned[3].to_string(), + database: configs_cleaned[4].to_string(), + } +}