diff --git a/src/main.rs b/src/main.rs index 1c9c70d..3a8796d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +// This is a program which creates a server where you can access imaginary financial services. Enjoy! + +// Imports use axum::{ Router, extract::Json, http::StatusCode, response::IntoResponse, routing::get, routing::post, }; @@ -8,6 +11,7 @@ use std::error::Error; use std::fmt; use std::path::Path; +// Error structure #[derive(Debug)] enum AccError { WrongPassword, @@ -40,6 +44,7 @@ impl From for AccError { } } +// Structures for requests #[derive(Debug, Serialize, Deserialize)] struct NewPerson { name: String, @@ -51,11 +56,24 @@ struct GetID { name: String, } +#[derive(Debug, Serialize, Deserialize)] +struct Id { + id: i32, +} + #[derive(Debug, Serialize, Deserialize)] struct GetName { id: i32, } +#[derive(Debug, Serialize, Deserialize)] +struct Transaction { + trid: i64, + sender: i32, + reciever: i32, + message: String, +} + #[derive(Debug, Serialize, Deserialize)] struct SendMoney { sender: i32, @@ -85,6 +103,16 @@ fn init_database() -> Result<()> { )", (), )?; + conn.execute( + "CREATE TABLE transactions ( + trid INTEGER PRIMARY KEY, + sender INTEGER NOT NULL, + reciever INTEGER NOT NULL, + amount INTEGER NOT NULL, + message TEXT + )", + (), + )?; Ok(()) } @@ -116,6 +144,17 @@ fn send_money_to_id(request: &SendMoney) -> Result<(), AccError> { "UPDATE persons SET money = money + ?1 WHERE id = ?2", params![request.amount, request.reciever], )?; + + // Add the transaction into the history + conn.execute( + "INSERT INTO transactions (sender, reciever, amount, message) VALUES (?1, ?2, ?3, ?4)", + params![ + &request.sender, + &request.reciever, + &request.amount, + &request.message + ], + )?; } Err(RusqliteError::QueryReturnedNoRows) => { let result2 = conn.query_row( @@ -194,6 +233,86 @@ async fn get_id_request(Json(payload): Json) -> impl IntoResponse { } } +fn get_money_by_id(name: &Id) -> Result { + let conn = Connection::open("financials.db")?; + println!("Getting money"); + let id = conn.query_row( + "SELECT money FROM persons WHERE id = ?1", + params![name.id], + |row| row.get(0), + )?; + Ok(id) +} + +async fn get_money_request(Json(payload): Json) -> impl IntoResponse { + let id = get_money_by_id(&payload); + match id { + Ok(_) => (StatusCode::OK, id.unwrap().to_string()), + Err(e) => (StatusCode::NOT_FOUND, format!("Error: {}", e)), + } +} + +fn get_transactions_by_id(id: &Id) -> Result, AccError> { + let conn = Connection::open("financials.db")?; + println!("Getting transactions by ID"); + let statement = format!( + "SELECT trid, sender, reciever, message FROM transactions WHERE sender = {} OR reciever = {}", + id.id.to_string(), + id.id.to_string() + ); + let mut tstate = conn.prepare(&statement)?; + let rows = tstate.query_map([], |row| { + Ok(Transaction { + trid: row.get(0)?, + sender: row.get(1)?, + reciever: row.get(2)?, + message: row.get(3)?, + }) + })?; + let mut transactions = Vec::new(); + for transaction_result in rows { + transactions.push(transaction_result?); + } + Ok(transactions) +} + +async fn get_transactions_request(Json(payload): Json) -> impl IntoResponse { + let transactions = get_transactions_by_id(&payload); + let mut tjson: String = "{".to_string(); + let mut is_first = true; + match transactions { + Ok(_) => { + for t in transactions.unwrap() { + tjson += &format!( + "{} + \"trid-{}\": {{ + \"trid\": {}, + \"sender\": {}, + \"reciever\": {}, + \"message\": \"{}\" + }}", + { + if is_first { + is_first = false; + "".to_string() + } else { + ",".to_string() + } + }, + t.trid.to_string(), + t.trid.to_string(), + t.sender.to_string(), + t.reciever.to_string(), + t.message + ); + } + tjson += "\n}"; + (StatusCode::OK, tjson) + } + Err(e) => (StatusCode::NOT_FOUND, format!("Error: {}", e)), + } +} + #[tokio::main] async fn main() { println!("Server starting up..."); @@ -208,7 +327,9 @@ async fn main() { .route("/", get(process_request)) .route("/api/createperson", post(create_person_request)) .route("/api/sendmoneytoid", post(send_money_request)) - .route("/api/getidfromname", post(get_id_request)); + .route("/api/getidfromname", post(get_id_request)) + .route("/api/getmoneyfromid", post(get_money_request)) + .route("/api/gettransactionsfromid", post(get_transactions_request)); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); }