From e32c1f9492b645016446e50922d0f278da219ce4 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Thu, 27 Apr 2023 23:59:14 -0400 Subject: [PATCH 01/35] beginnings of authentication --- Cargo.lock | 211 +++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 + src/api/mod.rs | 2 + src/api/user.rs | 133 ++++++++++++++++++++++++++++++ src/main.rs | 71 ++++++++-------- src/security.rs | 81 ------------------- 6 files changed, 384 insertions(+), 118 deletions(-) create mode 100644 src/api/mod.rs create mode 100644 src/api/user.rs delete mode 100644 src/security.rs diff --git a/Cargo.lock b/Cargo.lock index b400687..218619c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,21 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "actix-cors" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + [[package]] name = "actix-http" version = "3.3.1" @@ -30,7 +45,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.3", - "base64", + "base64 0.21.0", "bitflags", "brotli", "bytes", @@ -58,6 +73,22 @@ dependencies = [ "zstd", ] +[[package]] +name = "actix-identity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1224c9f9593dc27c9077b233ce04adedc1d7febcfc35ee9f53ea3c24df180bec" +dependencies = [ + "actix-service", + "actix-session", + "actix-utils", + "actix-web", + "anyhow", + "futures-core", + "serde", + "tracing", +] + [[package]] name = "actix-macros" version = "0.2.3" @@ -120,6 +151,23 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "actix-session" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da8b818ae1f11049a4d218975345fe8e56ce5a5f92c11f972abcff5ff80e87" +dependencies = [ + "actix-service", + "actix-utils", + "actix-web", + "anyhow", + "async-trait", + "derive_more", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "actix-utils" version = "3.0.1" @@ -193,6 +241,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" name = "adv_db" version = "0.1.0" dependencies = [ + "actix-cors", + "actix-identity", + "actix-session", "actix-web", "chrono", "env_logger", @@ -200,9 +251,45 @@ dependencies = [ "oracle", "rand", "serde", + "serde_json", "sha2", ] +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.7.6" @@ -259,12 +346,35 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" + [[package]] name = "base64" version = "0.21.0" @@ -358,6 +468,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -380,7 +500,14 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ + "aes-gcm", + "base64 0.20.0", + "hkdf", + "hmac", "percent-encoding", + "rand", + "sha2", + "subtle", "time 0.3.20", "version_check", ] @@ -416,9 +543,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "cxx" version = "1.0.94" @@ -519,6 +656,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -640,6 +778,16 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "h2" version = "0.3.18" @@ -680,6 +828,24 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.9" @@ -759,6 +925,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "io-lifetimes" version = "1.0.10" @@ -944,6 +1119,12 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "oracle" version = "0.5.7" @@ -1021,6 +1202,18 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "polyval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1253,6 +1446,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.109" @@ -1421,6 +1620,16 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "url" version = "2.3.1" diff --git a/Cargo.toml b/Cargo.toml index 445348c..b8e99d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +actix-cors = "0.6.4" +actix-identity = "0.5.2" +actix-session = { version = "0.7.2", features = ["cookie-session"] } actix-web = "4.3.1" chrono = "0.4.24" env_logger = "0.10.0" @@ -13,4 +16,5 @@ log = "0.4.17" oracle = "0.5.7" rand = "0.8.5" serde = { version = "1.0.160", features = ["derive"] } +serde_json = "1.0.96" sha2 = "0.10.6" diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 0000000..34b2ad4 --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod user; + diff --git a/src/api/user.rs b/src/api/user.rs new file mode 100644 index 0000000..9a7d291 --- /dev/null +++ b/src/api/user.rs @@ -0,0 +1,133 @@ +use sha2::{Sha256, Digest}; +use rand::{prelude::Rng, distributions::Alphanumeric }; +use oracle::{Connection, Error}; +use log::{info, warn, error}; +use actix_identity::Identity; +use actix_web::{web, Responder, HttpRequest, HttpMessage, HttpResponse}; +use serde::{Deserialize, Serialize}; + + +static SQL_USERNAME: &str = "group09_user"; +static SQL_PASSWORD: &str = "group09_user"; +static SALT_LEN: usize = 16; + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct Entry { + net_id: String, + password: String +} + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct User { + id: String, + first_name: String, + last_name: String +} + + +pub async fn login(request: HttpRequest, body: web::Json) -> impl Responder { + //TODO: finish login, for now will simply login for everyone + let net_id: &str = body.net_id.as_str(); + let password: &str = body.password.as_str(); + + //Identity::login(&request.extensions(), "User1".into()); + println!("{:?}", request); + println!("{:?}", body); + match authenticate(net_id, password) { + Some(user) => { + Identity::login(&request.extensions(), net_id.into()); + web::Json(user) + }, + None => web::Json(User::default()) + } +} + +pub async fn logout(user: Identity) -> impl Responder { + user.logout(); + HttpResponse::Ok() +} + +fn authenticate(username: &str, password: &str) -> Option { + + info!("Authenticating user: {}", username); + + let conn = match Connection::connect(SQL_USERNAME,SQL_PASSWORD, ""){ + Ok(c) => c, + Err(e) => { + error!("unable to open connection to server: {}", e); + return None; + } + }; + let mut stmt = match conn.statement("select * from student where net_id = :1").build(){ + Ok(s) => s, + Err(e) => { + error!("unable to build statement: {}", e); + return None; + } + }; + + let row = stmt.query_row_as::<(String, String, String, String, String)>(&[&username]).unwrap_or_default(); + + let true_pword = row.3; + let salt = row.4; + + let mut hasher = Sha256::new(); + hasher.update(password); + hasher.update(salt); + let hash = hasher.finalize(); + + let mut tmp: String = String::new(); + for value in hash{ + tmp += &format!("{:x}", value); + } + + conn.close().unwrap_or_default(); + + + if true_pword.eq(&tmp) { + info!("User {} successfully authenticated", username); + Some( User { id: row.0, first_name: row.1,last_name: row.2} ) + } + else{ + warn!("User {} failed authentication", username); + None + } + +} + + + + +fn create_user(username: &str, password: &str, first_name: &str, last_name: &str) -> Result<(), Error> { + + info!("Creating user: {}", username); + let conn = Connection::connect(SQL_USERNAME, SQL_PASSWORD, "")?; + let mut stmt = conn.statement("insert into student values(:net_id, :first_name, :last_name, :password, :salt)").build()?; + + let salt: String = rand::thread_rng().sample_iter(&Alphanumeric).take(SALT_LEN).map(char::from).collect(); + let mut hasher = Sha256::new(); + hasher.update(&password); + hasher.update(&salt); + let hash = hasher.finalize(); + + let mut hash_string = String::new(); + + for value in hash{ + hash_string += &format!("{:x}", value); + } + + match stmt.execute_named(&[("net_id", &username), ("first_name", &first_name), ("last_name", &last_name), ("password", &hash_string), ("salt", &salt)]) { + Ok(_) => { + info!("User {} successfully created", username); + conn.commit()?; + }, + Err(_) => { + warn!("Failed to create user {}", username); + conn.rollback()?; + } + }; + + conn.close()?; + Ok(()) + +} diff --git a/src/main.rs b/src/main.rs index 760cf94..be26b33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,14 @@ use log::{info, warn, error}; use env_logger::Env; -use actix_web::{web, get, post, web::Json, App, HttpResponse, HttpServer, Responder}; +use actix_web::{web, get, post, web::Json, App, HttpResponse, HttpServer, Responder, middleware, cookie::Key}; use serde::{Deserialize, Serialize}; -mod security; +use actix_cors::Cors; +use actix_identity::IdentityMiddleware; +use actix_session::{SessionMiddleware, storage::CookieSessionStore}; +mod api; -static PORT: u16 = 8009; +static PORT: u16 = 5000; +const ALLOWED_ORIGIN: &str = "http://localhost"; #[derive(Default, Debug, Serialize, Deserialize, Clone)] @@ -21,46 +25,41 @@ async fn main() -> std::io::Result<()> { let env = Env::default().filter_or("LOG_LEVEL", "info"); env_logger::init_from_env(env); - let _ = HttpServer::new( || { + let secret_key = Key::generate(); + + let _ = HttpServer::new(move || { App::new() - .service(index) - .service(login) - .service(homepage) - .service(plan_page) - }) - .bind(("0.0.0.0", PORT))? + .wrap(middleware::Logger::default()) + .wrap( + Cors::default() + .allowed_origin(ALLOWED_ORIGIN) + .allowed_methods(vec!["GET","POST","DELETE"]) + .supports_credentials() + ) + .wrap(IdentityMiddleware::default()) + .wrap(SessionMiddleware::new(CookieSessionStore::default(), secret_key.clone())) + .service( + web::scope("/api") + .service( + web::resource("/auth") + .route(web::post().to(api::user::login)) + .route(web::delete().to(api::user::logout)) + ) + .route("/", web::get().to(api_index)) + ) + .route("/", web::get().to(index)) + }) + .bind(("127.0.0.1", PORT))? .run() .await; - //Temporary for testing purposes, should write something to make a random salt - let username = "cmckechn"; - let password = "password"; - //proof of concept tests, create_user should fail in this instance because user was already - //created - security::authenticate(username, password).unwrap(); - security::create_user("test", "test_create", "test_first", "test_last").unwrap(); - security::authenticate("test", "test_create").unwrap(); Ok(()) } -#[get("/")] +async fn api_index() -> impl Responder { + HttpResponse::Ok().body("api") +} async fn index() -> impl Responder { - HttpResponse::Ok().body("Hello world!") + HttpResponse::Ok().body("/") } -#[get("/login")] -async fn login(json: Json) -> Result { - Ok(format!("{} {}", json.net_id, json.password)) -} - -#[get("/{net_id}/home")] -async fn homepage(path: web::Path) -> impl Responder { - let net_id = path.into_inner(); - HttpResponse::Ok().body(format!("You have reached the homepage of {} user", net_id) ) -} - -#[get("/{net_id}/plans")] -async fn plan_page(path: web::Path) -> impl Responder { - let net_id = path.into_inner(); - HttpResponse::Ok().body(format!("You have reached the plan page of {}", net_id)) -} diff --git a/src/security.rs b/src/security.rs deleted file mode 100644 index da8b1d7..0000000 --- a/src/security.rs +++ /dev/null @@ -1,81 +0,0 @@ -use sha2::{Sha256, Digest}; -use rand::{prelude::Rng, distributions::Alphanumeric }; -use oracle::{Connection, Error}; -use log::{info, warn}; - -static SQL_USERNAME: &str = "group09_user"; -static SQL_PASSWORD: &str = "group09_user"; -static SALT_LEN: usize = 16; - -pub fn authenticate(username: &str, password: &str) -> Result { - - info!("Authenticating user: {}", username); - - let conn = Connection::connect(SQL_USERNAME,SQL_PASSWORD, "")?; - let mut stmt = conn.statement("select password, salt from student where net_id = :1").build()?; - let row = stmt.query_row_as::<(String, String)>(&[&username])?; - - - let true_pword = row.0; - let salt = row.1; - - let mut hasher = Sha256::new(); - hasher.update(password); - hasher.update(salt); - let hash = hasher.finalize(); - - let mut tmp: String = String::new(); - for value in hash{ - tmp += &format!("{:x}", value); - } - - conn.close()?; - - - if true_pword.eq(&tmp) { - info!("User {} successfully authenticated", username); - Ok(true) - } - else{ - warn!("User {} failed authentication", username); - Ok(false) - } - -} - - - - -pub fn create_user(username: &str, password: &str, first_name: &str, last_name: &str) -> Result<(), Error> { - - info!("Creating user: {}", username); - let conn = Connection::connect(SQL_USERNAME, SQL_PASSWORD, "")?; - let mut stmt = conn.statement("insert into student values(:net_id, :first_name, :last_name, :password, :salt)").build()?; - - let salt: String = rand::thread_rng().sample_iter(&Alphanumeric).take(SALT_LEN).map(char::from).collect(); - let mut hasher = Sha256::new(); - hasher.update(&password); - hasher.update(&salt); - let hash = hasher.finalize(); - - let mut hash_string = String::new(); - - for value in hash{ - hash_string += &format!("{:x}", value); - } - - match stmt.execute_named(&[("net_id", &username), ("first_name", &first_name), ("last_name", &last_name), ("password", &hash_string), ("salt", &salt)]) { - Ok(_) => { - info!("User {} successfully created", username); - conn.commit()?; - }, - Err(_) => { - warn!("Failed to create user {}", username); - conn.rollback()?; - } - }; - - conn.close()?; - Ok(()) - -} From 2a47588eb170c9963c1ac8262b47b9897e35a0d2 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Fri, 28 Apr 2023 00:19:45 -0400 Subject: [PATCH 02/35] failed login results in 401 --- src/api/user.rs | 8 ++++++-- src/main.rs | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/api/user.rs b/src/api/user.rs index 9a7d291..2dbf123 100644 --- a/src/api/user.rs +++ b/src/api/user.rs @@ -36,9 +36,13 @@ pub async fn login(request: HttpRequest, body: web::Json) -> impl Respond match authenticate(net_id, password) { Some(user) => { Identity::login(&request.extensions(), net_id.into()); - web::Json(user) + web::Json(user); + HttpResponse::Ok() }, - None => web::Json(User::default()) + None => { + web::Json(User::default()); + HttpResponse::Unauthorized() + } } } diff --git a/src/main.rs b/src/main.rs index be26b33..d97575f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use actix_cors::Cors; use actix_identity::IdentityMiddleware; use actix_session::{SessionMiddleware, storage::CookieSessionStore}; + mod api; static PORT: u16 = 5000; From 7f1e4a0808759c5b1748a20f97aff49e8deb2bb6 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Fri, 28 Apr 2023 00:46:47 -0400 Subject: [PATCH 03/35] added signup api --- src/api/user.rs | 25 +++++++++++++++++++++++++ src/main.rs | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/src/api/user.rs b/src/api/user.rs index 2dbf123..c01e588 100644 --- a/src/api/user.rs +++ b/src/api/user.rs @@ -24,6 +24,14 @@ pub struct User { last_name: String } +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct NewUser { + netid: String, + password: String, + first_name: String, + last_name: String +} + pub async fn login(request: HttpRequest, body: web::Json) -> impl Responder { //TODO: finish login, for now will simply login for everyone @@ -51,6 +59,23 @@ pub async fn logout(user: Identity) -> impl Responder { HttpResponse::Ok() } +pub async fn signup(request: HttpRequest, body: web::Json) -> impl Responder { + let body = body.into_inner(); + + match create_user(body.netid.as_str(), body.password.as_str(), body.first_name.as_str(), body.last_name.as_str()) { + Ok(_) => { + Identity::login(&request.extensions(), body.netid.clone()); + web::Json(User { id: body.netid, first_name: body.first_name, last_name: body.last_name}); + HttpResponse::Ok() + } + Err(e) => { + error!("Error creating new user: {}", e); + HttpResponse::InternalServerError() + } + } + +} + fn authenticate(username: &str, password: &str) -> Option { info!("Authenticating user: {}", username); diff --git a/src/main.rs b/src/main.rs index d97575f..a03802f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,6 +46,10 @@ async fn main() -> std::io::Result<()> { .route(web::post().to(api::user::login)) .route(web::delete().to(api::user::logout)) ) + .service( + web::resource("/signup") + .route(web::post().to(api::user::signup)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From cc1c370e564d15ff4e251e0371daf3adc2e5300d Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Fri, 28 Apr 2023 01:10:08 -0400 Subject: [PATCH 04/35] moved backend into backend directory --- Cargo.lock => backend/Cargo.lock | 0 Cargo.toml => backend/Cargo.toml | 0 {src => backend/src}/api/mod.rs | 0 {src => backend/src}/api/user.rs | 0 {src => backend/src}/main.rs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename Cargo.lock => backend/Cargo.lock (100%) rename Cargo.toml => backend/Cargo.toml (100%) rename {src => backend/src}/api/mod.rs (100%) rename {src => backend/src}/api/user.rs (100%) rename {src => backend/src}/main.rs (100%) diff --git a/Cargo.lock b/backend/Cargo.lock similarity index 100% rename from Cargo.lock rename to backend/Cargo.lock diff --git a/Cargo.toml b/backend/Cargo.toml similarity index 100% rename from Cargo.toml rename to backend/Cargo.toml diff --git a/src/api/mod.rs b/backend/src/api/mod.rs similarity index 100% rename from src/api/mod.rs rename to backend/src/api/mod.rs diff --git a/src/api/user.rs b/backend/src/api/user.rs similarity index 100% rename from src/api/user.rs rename to backend/src/api/user.rs diff --git a/src/main.rs b/backend/src/main.rs similarity index 100% rename from src/main.rs rename to backend/src/main.rs From c76a63735adaa37815ec6550841032a00a27867d Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sat, 29 Apr 2023 22:10:54 -0400 Subject: [PATCH 05/35] added table creation --- backend/src/api/user.rs | 29 +++++++++++++++++++++-------- backend/src/main.rs | 8 ++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index c01e588..81d1057 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -3,7 +3,7 @@ use rand::{prelude::Rng, distributions::Alphanumeric }; use oracle::{Connection, Error}; use log::{info, warn, error}; use actix_identity::Identity; -use actix_web::{web, Responder, HttpRequest, HttpMessage, HttpResponse}; +use actix_web::{web, Responder, HttpRequest, HttpMessage, HttpResponse, cookie}; use serde::{Deserialize, Serialize}; @@ -26,7 +26,7 @@ pub struct User { #[derive(Deserialize, Serialize, Debug, Default)] pub struct NewUser { - netid: String, + net_id: String, password: String, first_name: String, last_name: String @@ -43,7 +43,7 @@ pub async fn login(request: HttpRequest, body: web::Json) -> impl Respond println!("{:?}", body); match authenticate(net_id, password) { Some(user) => { - Identity::login(&request.extensions(), net_id.into()); + let id = Identity::login(&request.extensions(), net_id.into()).unwrap(); web::Json(user); HttpResponse::Ok() }, @@ -62,10 +62,10 @@ pub async fn logout(user: Identity) -> impl Responder { pub async fn signup(request: HttpRequest, body: web::Json) -> impl Responder { let body = body.into_inner(); - match create_user(body.netid.as_str(), body.password.as_str(), body.first_name.as_str(), body.last_name.as_str()) { + match create_user(body.net_id.as_str(), body.password.as_str(), body.first_name.as_str(), body.last_name.as_str()) { Ok(_) => { - Identity::login(&request.extensions(), body.netid.clone()); - web::Json(User { id: body.netid, first_name: body.first_name, last_name: body.last_name}); + Identity::login(&request.extensions(), body.net_id.clone()).unwrap(); + web::Json(User { id: body.net_id, first_name: body.first_name, last_name: body.last_name}); HttpResponse::Ok() } Err(e) => { @@ -131,7 +131,7 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str info!("Creating user: {}", username); let conn = Connection::connect(SQL_USERNAME, SQL_PASSWORD, "")?; - let mut stmt = conn.statement("insert into student values(:net_id, :first_name, :last_name, :password, :salt)").build()?; + let mut stmt = conn.statement("insert into student values(:net_id, :first_name, :last_name, :pswd, :salt)").build()?; let salt: String = rand::thread_rng().sample_iter(&Alphanumeric).take(SALT_LEN).map(char::from).collect(); let mut hasher = Sha256::new(); @@ -145,7 +145,7 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str hash_string += &format!("{:x}", value); } - match stmt.execute_named(&[("net_id", &username), ("first_name", &first_name), ("last_name", &last_name), ("password", &hash_string), ("salt", &salt)]) { + match stmt.execute_named(&[("net_id", &username), ("first_name", &first_name), ("last_name", &last_name), ("pswd", &hash_string), ("salt", &salt)]) { Ok(_) => { info!("User {} successfully created", username); conn.commit()?; @@ -155,6 +155,19 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str conn.rollback()?; } }; + + let mut new_table = conn.statement("create table week_:netid ( item_id number(5), foreign key (item_id) references menu_item (id))").build()?; + + match new_table.execute_named(&[("net_id", &username)]) { + Ok(_) => { + info!("User {} week table created", username); + conn.commit()?; + }, + Err(_) => { + warn!("Failed to create week table for {}", username); + conn.rollback()?; + } + }; conn.close()?; Ok(()) diff --git a/backend/src/main.rs b/backend/src/main.rs index a03802f..ef0f741 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,6 +1,5 @@ -use log::{info, warn, error}; use env_logger::Env; -use actix_web::{web, get, post, web::Json, App, HttpResponse, HttpServer, Responder, middleware, cookie::Key}; +use actix_web::{web, App, HttpResponse, HttpServer, Responder, middleware, cookie::Key}; use serde::{Deserialize, Serialize}; use actix_cors::Cors; use actix_identity::IdentityMiddleware; @@ -8,8 +7,8 @@ use actix_session::{SessionMiddleware, storage::CookieSessionStore}; mod api; -static PORT: u16 = 5000; -const ALLOWED_ORIGIN: &str = "http://localhost"; +static PORT: u16 = 8000; +const ALLOWED_ORIGIN: &str = "http://localhost:8009"; #[derive(Default, Debug, Serialize, Deserialize, Clone)] @@ -36,6 +35,7 @@ async fn main() -> std::io::Result<()> { .allowed_origin(ALLOWED_ORIGIN) .allowed_methods(vec!["GET","POST","DELETE"]) .supports_credentials() + .allow_any_header() ) .wrap(IdentityMiddleware::default()) .wrap(SessionMiddleware::new(CookieSessionStore::default(), secret_key.clone())) From 82b4be1ba1b699658e79e1ca68c11933e7733a79 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 16:01:13 -0400 Subject: [PATCH 06/35] adding menu items --- backend/src/api/eatery.rs | 52 +++++++++++++++++++++++++++++++++++++++ backend/src/api/mod.rs | 1 + backend/src/api/user.rs | 2 +- backend/src/main.rs | 4 +++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 backend/src/api/eatery.rs diff --git a/backend/src/api/eatery.rs b/backend/src/api/eatery.rs new file mode 100644 index 0000000..4012fc0 --- /dev/null +++ b/backend/src/api/eatery.rs @@ -0,0 +1,52 @@ +use serde::{Serialize, Deserialize}; +use actix_web::{web::Path, Responder, HttpResponse}; +use oracle::{Connection, Error}; +use log::{error}; + +const ORACLE_USER: &str = "timmy"; +const ORACLE_PASS: &str = "timmy"; + +#[derive(Serialize, Deserialize, Debug, Default)] +struct food_item { + item_id: u32, + eatery_id: u32, + item_name: String, + serving_size: f32, + calories: f32, + fat: f32, + sat_fat: f32, + trans_fat: f32, + carbs: f32, + fiber: f32, + sugar: f32, + protein: f32, + sodium: f32, + potassium: f32, + cholesterol: f32 +} + + +pub fn menu(eatery: Path) -> impl Responder { + let eatery = eatery.into_inner(); + let conn = match Connection::connect(ORACLE_USER, ORACLE_PASS, "") { + Ok(c) => c, + Err(e) => { + error!("Unable to reach oracle server: {}", e); + return HttpResponse::InternalServerError(); + } + }; + + let mut stmt = match conn.statement("select * from menu_item natural join nutrition_info food where menu_item.eatery_id = :1").build() { + Ok(s) => s, + Err(e) => { + error!("Unable to build statement: {}", e); + return HttpResponse::InternalServerError(); + } + }; + + + let rows = stmt.query(&[&eatery]).unwrap().collect(); + println!("{}", rows); + HttpResponse::Ok() + +} diff --git a/backend/src/api/mod.rs b/backend/src/api/mod.rs index 34b2ad4..80bcc35 100644 --- a/backend/src/api/mod.rs +++ b/backend/src/api/mod.rs @@ -1,2 +1,3 @@ pub mod user; +pub mod eatery; diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index 81d1057..0cffdee 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -156,7 +156,7 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str } }; - let mut new_table = conn.statement("create table week_:netid ( item_id number(5), foreign key (item_id) references menu_item (id))").build()?; + let mut new_table = conn.statement("create table :net_id ( item_id number(5), foreign key (item_id) references menu_item (id))").build()?; match new_table.execute_named(&[("net_id", &username)]) { Ok(_) => { diff --git a/backend/src/main.rs b/backend/src/main.rs index ef0f741..169b24c 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -50,6 +50,10 @@ async fn main() -> std::io::Result<()> { web::resource("/signup") .route(web::post().to(api::user::signup)) ) + .service( + web::resource("/eatery/{eatery_id}") + .route(web::get().to(api::eatery::menu)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From ec08c1278073c79031a4696f054980d3e2090e3b Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 16:25:57 -0400 Subject: [PATCH 07/35] creating response json --- backend/src/api/eatery.rs | 62 +++++++++++++++++++++++++++------------ backend/src/main.rs | 2 +- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/backend/src/api/eatery.rs b/backend/src/api/eatery.rs index 4012fc0..4ef3795 100644 --- a/backend/src/api/eatery.rs +++ b/backend/src/api/eatery.rs @@ -1,13 +1,13 @@ use serde::{Serialize, Deserialize}; -use actix_web::{web::Path, Responder, HttpResponse}; -use oracle::{Connection, Error}; -use log::{error}; +use actix_web::{web::Path, Responder, HttpResponse, web::Json}; +use oracle::Connection; +use log::error; const ORACLE_USER: &str = "timmy"; const ORACLE_PASS: &str = "timmy"; #[derive(Serialize, Deserialize, Debug, Default)] -struct food_item { +struct FoodItem { item_id: u32, eatery_id: u32, item_name: String, @@ -26,27 +26,51 @@ struct food_item { } -pub fn menu(eatery: Path) -> impl Responder { +pub async fn menu(eatery: Path) -> impl Responder { let eatery = eatery.into_inner(); - let conn = match Connection::connect(ORACLE_USER, ORACLE_PASS, "") { - Ok(c) => c, + let response = match grab_rows(eatery) { + Ok(r) => r, Err(e) => { - error!("Unable to reach oracle server: {}", e); + error!("Failed to grab rows: {}", e); return HttpResponse::InternalServerError(); } }; - let mut stmt = match conn.statement("select * from menu_item natural join nutrition_info food where menu_item.eatery_id = :1").build() { - Ok(s) => s, - Err(e) => { - error!("Unable to build statement: {}", e); - return HttpResponse::InternalServerError(); - } - }; - - - let rows = stmt.query(&[&eatery]).unwrap().collect(); - println!("{}", rows); + Json(response); HttpResponse::Ok() } + + +fn grab_rows(eatery: String) -> oracle::Result> { + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, "")?; + + let mut stmt = conn.statement("select * from menu_item natural join nutrition_info food where menu_item.eatery_id = :1").build()?; + + + let rows = stmt.query(&[&eatery])?; + let mut row_vec: Vec = vec![]; + + for row_result in rows { + let row = row_result?; + row_vec.push( FoodItem { + item_id: row.get(0)?, + eatery_id: row.get(1)?, + item_name: row.get(2)?, + serving_size: row.get(3)?, + calories: row.get(4)?, + fat: row.get(5)?, + sat_fat: row.get(6)?, + trans_fat: row.get(7)?, + carbs: row.get(8)?, + fiber: row.get(9)?, + sugar: row.get(10)?, + protein: row.get(11)?, + sodium: row.get(12)?, + potassium: row.get(13)?, + cholesterol: row.get(14)?}); + } + + Ok(row_vec) +} diff --git a/backend/src/main.rs b/backend/src/main.rs index 169b24c..12f0a47 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -20,7 +20,6 @@ struct Login { #[actix_web::main] async fn main() -> std::io::Result<()> { - //init logging system let env = Env::default().filter_or("LOG_LEVEL", "info"); env_logger::init_from_env(env); @@ -36,6 +35,7 @@ async fn main() -> std::io::Result<()> { .allowed_methods(vec!["GET","POST","DELETE"]) .supports_credentials() .allow_any_header() + .expose_any_header() ) .wrap(IdentityMiddleware::default()) .wrap(SessionMiddleware::new(CookieSessionStore::default(), secret_key.clone())) From 5117a3318f6f9bff2f2269e731f9f0be4a7b935f Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 21:03:44 +0000 Subject: [PATCH 08/35] accounted for null --- backend/src/api/eatery.rs | 67 +++++++++++++++++++-------------------- backend/src/main.rs | 2 +- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/backend/src/api/eatery.rs b/backend/src/api/eatery.rs index 4ef3795..7bb63cd 100644 --- a/backend/src/api/eatery.rs +++ b/backend/src/api/eatery.rs @@ -7,37 +7,36 @@ const ORACLE_USER: &str = "timmy"; const ORACLE_PASS: &str = "timmy"; #[derive(Serialize, Deserialize, Debug, Default)] -struct FoodItem { +pub struct FoodItem { item_id: u32, - eatery_id: u32, - item_name: String, - serving_size: f32, - calories: f32, - fat: f32, - sat_fat: f32, - trans_fat: f32, - carbs: f32, - fiber: f32, - sugar: f32, - protein: f32, - sodium: f32, - potassium: f32, - cholesterol: f32 + eatery_id: Option, + item_name: Option, + serving_size: Option, + calories: Option, + fat: Option, + sat_fat: Option, + trans_fat: Option, + carbs: Option, + fiber: Option, + sugar: Option, + protein: Option, + sodium: Option, + potassium: Option, + cholesterol: Option } -pub async fn menu(eatery: Path) -> impl Responder { +pub async fn menu(eatery: Path) -> Json> { let eatery = eatery.into_inner(); let response = match grab_rows(eatery) { Ok(r) => r, Err(e) => { error!("Failed to grab rows: {}", e); - return HttpResponse::InternalServerError(); + return Json(vec![]); } }; - Json(response); - HttpResponse::Ok() + Json(response) } @@ -46,7 +45,7 @@ fn grab_rows(eatery: String) -> oracle::Result> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, "")?; - let mut stmt = conn.statement("select * from menu_item natural join nutrition_info food where menu_item.eatery_id = :1").build()?; + let mut stmt = conn.statement("select * from menu_item natural join nutrition_info where eatery_id = :1").build()?; let rows = stmt.query(&[&eatery])?; @@ -56,20 +55,20 @@ fn grab_rows(eatery: String) -> oracle::Result> { let row = row_result?; row_vec.push( FoodItem { item_id: row.get(0)?, - eatery_id: row.get(1)?, - item_name: row.get(2)?, - serving_size: row.get(3)?, - calories: row.get(4)?, - fat: row.get(5)?, - sat_fat: row.get(6)?, - trans_fat: row.get(7)?, - carbs: row.get(8)?, - fiber: row.get(9)?, - sugar: row.get(10)?, - protein: row.get(11)?, - sodium: row.get(12)?, - potassium: row.get(13)?, - cholesterol: row.get(14)?}); + eatery_id: row.get(1).unwrap_or(None), + item_name: row.get(2).unwrap_or(None), + serving_size: row.get(3).unwrap_or(None), + calories: row.get(4).unwrap_or(None), + fat: row.get(5).unwrap_or(None), + sat_fat: row.get(6).unwrap_or(None), + trans_fat: row.get(7).unwrap_or(None), + carbs: row.get(8).unwrap_or(None), + fiber: row.get(9).unwrap_or(None), + sugar: row.get(10).unwrap_or(None), + protein: row.get(11).unwrap_or(None), + sodium: row.get(12).unwrap_or(None), + potassium: row.get(13).unwrap_or(None), + cholesterol: row.get(14).unwrap_or(None)}); } Ok(row_vec) diff --git a/backend/src/main.rs b/backend/src/main.rs index 12f0a47..ea3061d 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -58,7 +58,7 @@ async fn main() -> std::io::Result<()> { ) .route("/", web::get().to(index)) }) - .bind(("127.0.0.1", PORT))? + .bind(("0.0.0.0", PORT))? .run() .await; From f009dd71661519774a89511a4afe0badc0afe377 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 17:33:47 -0400 Subject: [PATCH 09/35] added config + plan --- backend/src/api/eatery.rs | 6 ++--- backend/src/api/mod.rs | 1 + backend/src/api/plan.rs | 55 +++++++++++++++++++++++++++++++++++++++ backend/src/api/user.rs | 8 +++--- backend/src/config.rs | 4 +++ backend/src/main.rs | 5 ++++ 6 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 backend/src/api/plan.rs create mode 100644 backend/src/config.rs diff --git a/backend/src/api/eatery.rs b/backend/src/api/eatery.rs index 7bb63cd..8aba59a 100644 --- a/backend/src/api/eatery.rs +++ b/backend/src/api/eatery.rs @@ -2,9 +2,7 @@ use serde::{Serialize, Deserialize}; use actix_web::{web::Path, Responder, HttpResponse, web::Json}; use oracle::Connection; use log::error; - -const ORACLE_USER: &str = "timmy"; -const ORACLE_PASS: &str = "timmy"; +use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; #[derive(Serialize, Deserialize, Debug, Default)] pub struct FoodItem { @@ -43,7 +41,7 @@ pub async fn menu(eatery: Path) -> Json> { fn grab_rows(eatery: String) -> oracle::Result> { - let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, "")?; + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; let mut stmt = conn.statement("select * from menu_item natural join nutrition_info where eatery_id = :1").build()?; diff --git a/backend/src/api/mod.rs b/backend/src/api/mod.rs index 80bcc35..e575e43 100644 --- a/backend/src/api/mod.rs +++ b/backend/src/api/mod.rs @@ -1,3 +1,4 @@ pub mod user; pub mod eatery; +pub mod plan; diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs new file mode 100644 index 0000000..0740074 --- /dev/null +++ b/backend/src/api/plan.rs @@ -0,0 +1,55 @@ +use serde::{Serialize, Deserialize}; +use actix_web::{web::Json, Responder, HttpResponse}; +use oracle::{Connection, Result}; +use log::{error, info}; +use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; + +#[derive(Deserialize, Serialize, Debug, Default)] +struct PlanData{ + net_id: String, + total_cal: f32, + total_fat: f32, + total_sat_fat: f32, + total_trans_fat: f32, + total_carbs: f32, + total_fiber: f32, + total_sugar: f32, + total_protein: f32, + total_sodium: f32, + total_potassium: f32, + total_cholesterol: f32 +} + +pub async fn plan(body: Json) -> impl Responder { + let body = body.into_inner(); + match create_plan(body) { + Ok(_) => HttpResponse::Ok(), + Err(e) => { + error!("failed to create plan {}", e); + HttpResponse::InternalServerError() + } + } + +} + +fn create_plan(plan: PlanData) -> Result<()> { + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + + let mut stmt = conn.statement("insert into table goal values(:net_id, :total_cal, :total_fat, :total_sat_fat, :total_trans_fat, :total_carbs, :total_fiber, :total_sugar, :total_protein, :total_sodium, :total_potassium, :total_cholesterol)").build()?; + + stmt.execute_named(&[("net_id", &plan.net_id), ("total_cal", &plan.total_cal), + ("total_fat", &plan.total_fat), + ("total_sat_fat", &plan.total_sat_fat), + ("total_trans_fat", &plan.total_trans_fat), + ("total_carbs", &plan.total_carbs), + ("total_sugar", &plan.total_sugar), + ("total_protein", &plan.total_protein), + ("total_potassium", &plan.total_potassium), + ("total_cholesterol", &plan.total_cholesterol)])?; + + info!("Created new plan for user: {}", plan.net_id); + Ok(()) + +} + diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index 0cffdee..11b348a 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -5,10 +5,8 @@ use log::{info, warn, error}; use actix_identity::Identity; use actix_web::{web, Responder, HttpRequest, HttpMessage, HttpResponse, cookie}; use serde::{Deserialize, Serialize}; +use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; - -static SQL_USERNAME: &str = "group09_user"; -static SQL_PASSWORD: &str = "group09_user"; static SALT_LEN: usize = 16; #[derive(Deserialize, Serialize, Debug, Default)] @@ -80,7 +78,7 @@ fn authenticate(username: &str, password: &str) -> Option { info!("Authenticating user: {}", username); - let conn = match Connection::connect(SQL_USERNAME,SQL_PASSWORD, ""){ + let conn = match Connection::connect(ORACLE_USER,ORACLE_PASS, ORACLE_CON_STR){ Ok(c) => c, Err(e) => { error!("unable to open connection to server: {}", e); @@ -130,7 +128,7 @@ fn authenticate(username: &str, password: &str) -> Option { fn create_user(username: &str, password: &str, first_name: &str, last_name: &str) -> Result<(), Error> { info!("Creating user: {}", username); - let conn = Connection::connect(SQL_USERNAME, SQL_PASSWORD, "")?; + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; let mut stmt = conn.statement("insert into student values(:net_id, :first_name, :last_name, :pswd, :salt)").build()?; let salt: String = rand::thread_rng().sample_iter(&Alphanumeric).take(SALT_LEN).map(char::from).collect(); diff --git a/backend/src/config.rs b/backend/src/config.rs new file mode 100644 index 0000000..3e8e3db --- /dev/null +++ b/backend/src/config.rs @@ -0,0 +1,4 @@ +pub const ORACLE_USER: &str = "timmy"; +pub const ORACLE_PASS: &str = "timmy"; +pub const ORACLE_CON_STR: &str = ""; + diff --git a/backend/src/main.rs b/backend/src/main.rs index ea3061d..80a9766 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -6,6 +6,7 @@ use actix_identity::IdentityMiddleware; use actix_session::{SessionMiddleware, storage::CookieSessionStore}; mod api; +mod config; static PORT: u16 = 8000; const ALLOWED_ORIGIN: &str = "http://localhost:8009"; @@ -54,6 +55,10 @@ async fn main() -> std::io::Result<()> { web::resource("/eatery/{eatery_id}") .route(web::get().to(api::eatery::menu)) ) + .service( + web::resource("/goal") + .route(web::post().to(api::plan::plan)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From 24ca48fe51e0292dffb7adf57c3278f18126e9d8 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 22:06:09 +0000 Subject: [PATCH 10/35] changed to options --- backend/src/api/plan.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index 0740074..9f0b1a3 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -5,19 +5,19 @@ use log::{error, info}; use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; #[derive(Deserialize, Serialize, Debug, Default)] -struct PlanData{ +pub struct PlanData{ net_id: String, - total_cal: f32, - total_fat: f32, - total_sat_fat: f32, - total_trans_fat: f32, - total_carbs: f32, - total_fiber: f32, - total_sugar: f32, - total_protein: f32, - total_sodium: f32, - total_potassium: f32, - total_cholesterol: f32 + total_cal: Option, + total_fat: Option, + total_sat_fat: Option, + total_trans_fat: Option, + total_carbs: Option, + total_fiber: Option, + total_sugar: Option, + total_protein: Option, + total_sodium: Option, + total_potassium: Option, + total_cholesterol: Option } pub async fn plan(body: Json) -> impl Responder { From 443dc0e101059bc6d3eae2ac4b7c746a654c5aa1 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 22:35:58 +0000 Subject: [PATCH 11/35] fixed bug with sodium --- backend/src/api/plan.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index 9f0b1a3..4ae8938 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -36,15 +36,19 @@ fn create_plan(plan: PlanData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; - let mut stmt = conn.statement("insert into table goal values(:net_id, :total_cal, :total_fat, :total_sat_fat, :total_trans_fat, :total_carbs, :total_fiber, :total_sugar, :total_protein, :total_sodium, :total_potassium, :total_cholesterol)").build()?; + let mut stmt = conn.statement("insert into goal values(:net_id, :total_cal, :total_fat, :total_sat_fat, :total_trans_fat, :total_carbs, :total_fiber, :total_sugar, :total_protein, :total_sodium, :total_potassium, :total_cholesterol)").build()?; - stmt.execute_named(&[("net_id", &plan.net_id), ("total_cal", &plan.total_cal), + stmt.execute_named(&[ + ("net_id", &plan.net_id), + ("total_cal", &plan.total_cal), ("total_fat", &plan.total_fat), ("total_sat_fat", &plan.total_sat_fat), ("total_trans_fat", &plan.total_trans_fat), ("total_carbs", &plan.total_carbs), + ("total_fiber", &plan.total_fiber), ("total_sugar", &plan.total_sugar), ("total_protein", &plan.total_protein), + ("total_sodium", &plan.total_sodium), ("total_potassium", &plan.total_potassium), ("total_cholesterol", &plan.total_cholesterol)])?; From 5c11b7b463b8d5df6ef47b36f2e6d50f1cf70fcd Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 18:41:15 -0400 Subject: [PATCH 12/35] added date --- backend/src/api/plan.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index 4ae8938..7ae365f 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -7,6 +7,7 @@ use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; #[derive(Deserialize, Serialize, Debug, Default)] pub struct PlanData{ net_id: String, + week_date: String, total_cal: Option, total_fat: Option, total_sat_fat: Option, @@ -36,10 +37,11 @@ fn create_plan(plan: PlanData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; - let mut stmt = conn.statement("insert into goal values(:net_id, :total_cal, :total_fat, :total_sat_fat, :total_trans_fat, :total_carbs, :total_fiber, :total_sugar, :total_protein, :total_sodium, :total_potassium, :total_cholesterol)").build()?; + let mut stmt = conn.statement("insert into goal values(:net_id, :week_date, :total_cal, :total_fat, :total_sat_fat, :total_trans_fat, :total_carbs, :total_fiber, :total_sugar, :total_protein, :total_sodium, :total_potassium, :total_cholesterol)").build()?; stmt.execute_named(&[ ("net_id", &plan.net_id), + ("week_date", &plan.week_date), ("total_cal", &plan.total_cal), ("total_fat", &plan.total_fat), ("total_sat_fat", &plan.total_sat_fat), From 402dcd8efe727be7b8e33cbfa4882d75461faac3 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 22:46:10 +0000 Subject: [PATCH 13/35] closing and committing --- backend/src/api/eatery.rs | 2 ++ backend/src/api/plan.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/backend/src/api/eatery.rs b/backend/src/api/eatery.rs index 8aba59a..1c6b236 100644 --- a/backend/src/api/eatery.rs +++ b/backend/src/api/eatery.rs @@ -69,5 +69,7 @@ fn grab_rows(eatery: String) -> oracle::Result> { cholesterol: row.get(14).unwrap_or(None)}); } + conn.close()?; + Ok(row_vec) } diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index 7ae365f..f494d7c 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -55,6 +55,8 @@ fn create_plan(plan: PlanData) -> Result<()> { ("total_cholesterol", &plan.total_cholesterol)])?; info!("Created new plan for user: {}", plan.net_id); + conn.commit()?; + conn.close()?; Ok(()) } From bbab7882cc6865e35808ebf7531133619b465fc1 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 19:45:21 -0400 Subject: [PATCH 14/35] fix user table creation --- backend/src/api/mod.rs | 1 + backend/src/api/user.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/api/mod.rs b/backend/src/api/mod.rs index e575e43..5b20f13 100644 --- a/backend/src/api/mod.rs +++ b/backend/src/api/mod.rs @@ -1,4 +1,5 @@ pub mod user; pub mod eatery; pub mod plan; +pub mod week; diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index 11b348a..d0fea4b 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -154,9 +154,9 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str } }; - let mut new_table = conn.statement("create table :net_id ( item_id number(5), foreign key (item_id) references menu_item (id))").build()?; + let mut new_table = conn.statement(format!("create table {} ( item_id number(5), foreign key (item_id) references menu_item (id))", username).as_str()).build()?; - match new_table.execute_named(&[("net_id", &username)]) { + match new_table.execute(&[]) { Ok(_) => { info!("User {} week table created", username); conn.commit()?; From 159faa8fef3eec66d4164f212bfdcc668e01aea2 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 19:46:53 -0400 Subject: [PATCH 15/35] beginning week --- backend/src/api/week.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 backend/src/api/week.rs diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs new file mode 100644 index 0000000..727b84c --- /dev/null +++ b/backend/src/api/week.rs @@ -0,0 +1,14 @@ +use serde::{Serialize, Deserialize}; +use log::{error, info}; +use actix_web::{self, Responder}; +use oracle::{Connection, Result}; +use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; + + +pub async fn week(item: ItemData) -> impl Responder { + +} + +fn add_item(item: ItemData) -> Result<()> { + +} From b0dce09473f1f51a62e6f48289583e82b66e67e7 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 19:48:13 -0400 Subject: [PATCH 16/35] added amount --- backend/src/api/user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index d0fea4b..5583975 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -154,7 +154,7 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str } }; - let mut new_table = conn.statement(format!("create table {} ( item_id number(5), foreign key (item_id) references menu_item (id))", username).as_str()).build()?; + let mut new_table = conn.statement(format!("create table {} ( item_id number(5), amount number(5), foreign key (item_id) references menu_item (id))", username).as_str()).build()?; match new_table.execute(&[]) { Ok(_) => { From d65d412a11c88f22dad78e67c79f8dd0b7349e86 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 23:57:07 +0000 Subject: [PATCH 17/35] fixed table creation --- backend/src/api/user.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index 5583975..33c79b5 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -154,15 +154,15 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str } }; - let mut new_table = conn.statement(format!("create table {} ( item_id number(5), amount number(5), foreign key (item_id) references menu_item (id))", username).as_str()).build()?; + let mut new_table = conn.statement(format!("create table {} ( item_id number(5), amount number(5), foreign key (item_id) references menu_item (item_id))", username).as_str()).build()?; match new_table.execute(&[]) { Ok(_) => { info!("User {} week table created", username); conn.commit()?; }, - Err(_) => { - warn!("Failed to create week table for {}", username); + Err(e) => { + warn!("Failed to create week table for {} {}", username, e); conn.rollback()?; } }; From 509417bc751f8516ca95a918ac00a0c69b744e71 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 00:03:51 +0000 Subject: [PATCH 18/35] added fields to user table --- backend/src/api/user.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index 33c79b5..14688ab 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -154,7 +154,21 @@ fn create_user(username: &str, password: &str, first_name: &str, last_name: &str } }; - let mut new_table = conn.statement(format!("create table {} ( item_id number(5), amount number(5), foreign key (item_id) references menu_item (item_id))", username).as_str()).build()?; + let mut new_table = conn.statement(format!("create table {} ( item_id number(5), amount number(5), + item_name varchar2(128), + calories number(5), + fat_g number(5), + sat_fat_g number(5), + trans_fat_g number(5), + carbs_g number(5), + fiber_g number(5), + sugar_g number(5), + protein_g number(5), + sodium_mg number(5), + potassium_mg number(5), + cholesterol_mg number(5), + menu_item number(1), + foreign key (item_id) references menu_item (item_id))", username).as_str()).build()?; match new_table.execute(&[]) { Ok(_) => { From cff79f2cc6e817addeefb8793ef877bfa06d855b Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 20:26:49 -0400 Subject: [PATCH 19/35] created week endpoint --- backend/src/api/week.rs | 67 ++++++++++++++++++++++++++++++++++++++--- backend/src/main.rs | 4 +++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index 727b84c..023305a 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -1,14 +1,71 @@ use serde::{Serialize, Deserialize}; use log::{error, info}; -use actix_web::{self, Responder}; +use actix_web::{self, Responder, web::Json, HttpResponse}; use oracle::{Connection, Result}; use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; - -pub async fn week(item: ItemData) -> impl Responder { - +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct ItemData{ + net_id: String, + item_name: String, + calories: Option, + fat_g: Option, + sat_fat_g: Option, + trans_fat_g: Option, + carbs_g: Option, + fiber_g: Option, + sugar_g: Option, + protein_g: Option, + sodium_mg: Option, + potassium_mg: Option, + cholesterol_mg: Option } -fn add_item(item: ItemData) -> Result<()> { +pub async fn week(item: Json) -> impl Responder { + + let item = item.into_inner(); + match add_item(&item) { + Ok(_) => HttpResponse::Ok(), + Err(e) => { + error!("Unable to add item to table {}: {}", item.net_id, e); + HttpResponse::InternalServerError() + } + } +} + +fn add_item(item: &ItemData) -> Result<()> { + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)? ; + + let mut stmt = conn.statement(format!("insert into {} values (NULL, NULL, :item_name, + :calories, + :fat_g, + :sat_fat_g, + :trans_fat_g, + :carbs_g, + :fiber_g, + :sugar_g, + :protein_g, + :sodium_mg, + :potassium_mg, + :cholesterol_mg, + 0)", item.net_id).as_str()).build()?; + + stmt.execute_named(&[("item_name", &item.item_name), + ("calories", &item.calories), + ("fat_g", &item.fat_g), + ("sat_fat_g", &item.sat_fat_g), + ("trans_fat_g", &item.trans_fat_g), + ("carbs_g", &item.carbs_g), + ("fiber_g", &item.fiber_g), + ("sugar_g", &item.sugar_g), + ("protein_g", &item.protein_g), + ("sodium_mg", &item.sodium_mg), + ("potassium_mg", &item.potassium_mg), + ("cholesterol_mg", &item.cholesterol_mg)])?; + + conn.commit()?; + conn.close()?; + info!("Added item {} to table {}", item.item_name, item.net_id); + Ok(()) } diff --git a/backend/src/main.rs b/backend/src/main.rs index 80a9766..3905c03 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -59,6 +59,10 @@ async fn main() -> std::io::Result<()> { web::resource("/goal") .route(web::post().to(api::plan::plan)) ) + .service( + web::resource("/week_plan") + .route(web::post().to(api::week::week)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From 7dd488d23f34d12605cf44669689d497b6bc8e6f Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 20:30:04 -0400 Subject: [PATCH 20/35] added amount --- backend/src/api/week.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index 023305a..ff8a681 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -8,6 +8,7 @@ use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; pub struct ItemData{ net_id: String, item_name: String, + amount: Option, calories: Option, fat_g: Option, sat_fat_g: Option, @@ -36,7 +37,7 @@ pub async fn week(item: Json) -> impl Responder { fn add_item(item: &ItemData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)? ; - let mut stmt = conn.statement(format!("insert into {} values (NULL, NULL, :item_name, + let mut stmt = conn.statement(format!("insert into {} values (NULL, :amount, :item_name, :calories, :fat_g, :sat_fat_g, @@ -50,7 +51,9 @@ fn add_item(item: &ItemData) -> Result<()> { :cholesterol_mg, 0)", item.net_id).as_str()).build()?; - stmt.execute_named(&[("item_name", &item.item_name), + stmt.execute_named(&[ + ("amount", &item.amount), + ("item_name", &item.item_name), ("calories", &item.calories), ("fat_g", &item.fat_g), ("sat_fat_g", &item.sat_fat_g), From 4f6bffaf17891e97714f7ca5012923c8657add7d Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 20:57:26 -0400 Subject: [PATCH 21/35] added menu item end --- backend/src/api/week.rs | 50 +++++++++++++++++++++++++++++++++++++++++ backend/src/main.rs | 4 ++++ 2 files changed, 54 insertions(+) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index ff8a681..359bcd5 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -22,6 +22,13 @@ pub struct ItemData{ cholesterol_mg: Option } +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct MenuItems { + net_id: String, + item_list: Vec +} + + pub async fn week(item: Json) -> impl Responder { let item = item.into_inner(); @@ -34,6 +41,19 @@ pub async fn week(item: Json) -> impl Responder { } } +pub async fn week_meals(items: Json) -> impl Responder { + let items = items.into_inner(); + let netid = items.net_id.clone(); + + match add_menu_items(items) { + Ok(_) => HttpResponse::Ok(), + Err(e) => { + error!("Unable to add menu items to table {}: {}", netid, e); + HttpResponse::InternalServerError() + } + } +} + fn add_item(item: &ItemData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)? ; @@ -72,3 +92,33 @@ fn add_item(item: &ItemData) -> Result<()> { Ok(()) } + + +fn add_menu_items(items: MenuItems) -> Result<()> { + let conn = Connection::connect(ORACLE_USER,ORACLE_PASS, ORACLE_CON_STR)?; + + let mut stmt = conn.statement(format!("insert into {} values ( + :item_id, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 1)", items.net_id).as_str()).build()?; + + for item in items.item_list { + stmt.execute_named(&[("item_id",&item)])?; + } + + conn.commit()?; + conn.close()?; + info!("inserted menu items into week table {}", items.net_id); + Ok(()) +} diff --git a/backend/src/main.rs b/backend/src/main.rs index 3905c03..3e536fc 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -63,6 +63,10 @@ async fn main() -> std::io::Result<()> { web::resource("/week_plan") .route(web::post().to(api::week::week)) ) + .service( + web::resource("/week_meals") + .route(web::post().to(api::week::week_meals)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From 8ebf0c162c1266f9bfce688ac8150b7244fcd91a Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 01:03:29 +0000 Subject: [PATCH 22/35] added extra null --- backend/src/api/week.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index 359bcd5..1398fb8 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -111,6 +111,7 @@ fn add_menu_items(items: MenuItems) -> Result<()> { NULL, NULL, NULL, + NULL, 1)", items.net_id).as_str()).build()?; for item in items.item_list { From 7c52c2dd0eaedaee98af3e18501e35d57a6b9d95 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 21:31:04 -0400 Subject: [PATCH 23/35] added menu search --- backend/src/api/menu.rs | 61 +++++++++++++++++++++++++++++++++++++++++ backend/src/api/mod.rs | 1 + backend/src/main.rs | 4 +++ 3 files changed, 66 insertions(+) create mode 100644 backend/src/api/menu.rs diff --git a/backend/src/api/menu.rs b/backend/src/api/menu.rs new file mode 100644 index 0000000..195bc5d --- /dev/null +++ b/backend/src/api/menu.rs @@ -0,0 +1,61 @@ +use oracle::{Result, Connection}; +use serde::{Serialize, Deserialize}; +use log::{info, error}; +use actix_web::{self, Responder, web::Json, HttpResponse}; + +use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct SearchTerm{ + search_term: String +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct SearchResults { + results: Vec +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct SearchResult { + item_name: Option, + item_id: u32, + eatery_id: Option, + serving_size: Option +} + +pub async menu_search(term: Json) -> Json { + + let term = term.into_inner(); + + match fuzzy_search(term) { + Ok(result) => Json(result), + Err(e) => { + error!("failed to search for {}", term); + Json(vec![]) + } + } + +} + +fn fuzzy_search(term: &str) -> Result { + let conn = Connection::connect(ORACLE_USER,ORACLE_PASS,ORACLE_CON_STR)?; + let stmt = conn.statement("select * from menu_item where item_name like :term").build()?; + + let rows = stmt.query_named(&[("term", &term))?; + + let rows_vec = SearchResults::default(); + + for row_result in rows{ + let row = row_result?; + rows_vec.results.push( SearchResult { + item_name: row.get(0).unwrap_or(None), + item_id: row.get(1)?, + eatery_id: row.get(2).unwrap_or(None), + serving_size: row.get(3).unwrap_or(None) + }; + } + + Ok(rows_vec) + +} + diff --git a/backend/src/api/mod.rs b/backend/src/api/mod.rs index 5b20f13..1055da8 100644 --- a/backend/src/api/mod.rs +++ b/backend/src/api/mod.rs @@ -2,4 +2,5 @@ pub mod user; pub mod eatery; pub mod plan; pub mod week; +pub mod menu; diff --git a/backend/src/main.rs b/backend/src/main.rs index 3e536fc..e9506ef 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -67,6 +67,10 @@ async fn main() -> std::io::Result<()> { web::resource("/week_meals") .route(web::post().to(api::week::week_meals)) ) + .service( + web::resource("/week_progress/{net_id}") + .route(web::get().to(api::week::week_lookup)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From d1138c12cfbdacad0a15564419b461928089c6b0 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 21:32:38 -0400 Subject: [PATCH 24/35] fixed paren --- backend/src/api/menu.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/api/menu.rs b/backend/src/api/menu.rs index 195bc5d..1e11344 100644 --- a/backend/src/api/menu.rs +++ b/backend/src/api/menu.rs @@ -41,7 +41,7 @@ fn fuzzy_search(term: &str) -> Result { let conn = Connection::connect(ORACLE_USER,ORACLE_PASS,ORACLE_CON_STR)?; let stmt = conn.statement("select * from menu_item where item_name like :term").build()?; - let rows = stmt.query_named(&[("term", &term))?; + let rows = stmt.query_named(&[("term", &term)])?; let rows_vec = SearchResults::default(); @@ -52,7 +52,7 @@ fn fuzzy_search(term: &str) -> Result { item_id: row.get(1)?, eatery_id: row.get(2).unwrap_or(None), serving_size: row.get(3).unwrap_or(None) - }; + }); } Ok(rows_vec) From d4ee895b80983e648c9df28f074089c6369dd654 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 01:44:41 +0000 Subject: [PATCH 25/35] menu search complete --- backend/src/api/menu.rs | 17 +++++++++-------- backend/src/main.rs | 6 +++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/backend/src/api/menu.rs b/backend/src/api/menu.rs index 1e11344..0aeaf9a 100644 --- a/backend/src/api/menu.rs +++ b/backend/src/api/menu.rs @@ -1,7 +1,7 @@ use oracle::{Result, Connection}; use serde::{Serialize, Deserialize}; use log::{info, error}; -use actix_web::{self, Responder, web::Json, HttpResponse}; +use actix_web::{web::Json}; use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; @@ -23,15 +23,15 @@ pub struct SearchResult { serving_size: Option } -pub async menu_search(term: Json) -> Json { +pub async fn menu_search(term: Json) -> Json { let term = term.into_inner(); - match fuzzy_search(term) { + match fuzzy_search(&term.search_term) { Ok(result) => Json(result), Err(e) => { - error!("failed to search for {}", term); - Json(vec![]) + error!("failed to search for {}: {}", term.search_term, e); + Json(SearchResults::default()) } } @@ -39,11 +39,11 @@ pub async menu_search(term: Json) -> Json { fn fuzzy_search(term: &str) -> Result { let conn = Connection::connect(ORACLE_USER,ORACLE_PASS,ORACLE_CON_STR)?; - let stmt = conn.statement("select * from menu_item where item_name like :term").build()?; + let mut stmt = conn.statement(format!("select * from menu_item where item_name like '{}%'", term).as_str()).build()?; - let rows = stmt.query_named(&[("term", &term)])?; + let rows = stmt.query(&[])?; - let rows_vec = SearchResults::default(); + let mut rows_vec = SearchResults::default(); for row_result in rows{ let row = row_result?; @@ -54,6 +54,7 @@ fn fuzzy_search(term: &str) -> Result { serving_size: row.get(3).unwrap_or(None) }); } + conn.close()?; Ok(rows_vec) diff --git a/backend/src/main.rs b/backend/src/main.rs index e9506ef..e077a44 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -67,9 +67,13 @@ async fn main() -> std::io::Result<()> { web::resource("/week_meals") .route(web::post().to(api::week::week_meals)) ) - .service( + /* .service( web::resource("/week_progress/{net_id}") .route(web::get().to(api::week::week_lookup)) + ) */ + .service( + web::resource("/menu_search") + .route(web::post().to(api::menu::menu_search)) ) .route("/", web::get().to(api_index)) ) From 62821f2081815d317e5a94cda6b6f046b4b78e29 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 30 Apr 2023 23:43:51 -0400 Subject: [PATCH 26/35] week progress lookup and remove warnings --- backend/src/api/eatery.rs | 2 +- backend/src/api/menu.rs | 2 +- backend/src/api/user.rs | 6 ++-- backend/src/api/week.rs | 72 ++++++++++++++++++++++++++++++++++++++- backend/src/main.rs | 4 +-- 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/backend/src/api/eatery.rs b/backend/src/api/eatery.rs index 1c6b236..eaaf54c 100644 --- a/backend/src/api/eatery.rs +++ b/backend/src/api/eatery.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use actix_web::{web::Path, Responder, HttpResponse, web::Json}; +use actix_web::{web::Path, web::Json}; use oracle::Connection; use log::error; use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; diff --git a/backend/src/api/menu.rs b/backend/src/api/menu.rs index 0aeaf9a..d85d246 100644 --- a/backend/src/api/menu.rs +++ b/backend/src/api/menu.rs @@ -1,6 +1,6 @@ use oracle::{Result, Connection}; use serde::{Serialize, Deserialize}; -use log::{info, error}; +use log::error; use actix_web::{web::Json}; use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; diff --git a/backend/src/api/user.rs b/backend/src/api/user.rs index 14688ab..78315f9 100644 --- a/backend/src/api/user.rs +++ b/backend/src/api/user.rs @@ -3,7 +3,7 @@ use rand::{prelude::Rng, distributions::Alphanumeric }; use oracle::{Connection, Error}; use log::{info, warn, error}; use actix_identity::Identity; -use actix_web::{web, Responder, HttpRequest, HttpMessage, HttpResponse, cookie}; +use actix_web::{web, Responder, HttpRequest, HttpMessage, HttpResponse}; use serde::{Deserialize, Serialize}; use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}; @@ -41,7 +41,6 @@ pub async fn login(request: HttpRequest, body: web::Json) -> impl Respond println!("{:?}", body); match authenticate(net_id, password) { Some(user) => { - let id = Identity::login(&request.extensions(), net_id.into()).unwrap(); web::Json(user); HttpResponse::Ok() }, @@ -52,8 +51,7 @@ pub async fn login(request: HttpRequest, body: web::Json) -> impl Respond } } -pub async fn logout(user: Identity) -> impl Responder { - user.logout(); +pub async fn logout() -> impl Responder { HttpResponse::Ok() } diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index 1398fb8..d1fc3b5 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -1,6 +1,6 @@ use serde::{Serialize, Deserialize}; use log::{error, info}; -use actix_web::{self, Responder, web::Json, HttpResponse}; +use actix_web::{self, Responder, web::{Json, Path}, HttpResponse}; use oracle::{Connection, Result}; use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; @@ -28,6 +28,28 @@ pub struct MenuItems { item_list: Vec } +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct WeekData{ + week: Vec +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct ItemResult{ + item_id: Option, + amount: Option, + item_name: Option, + calories: Option, + fat_g: Option, + sat_fat_g: Option, + trans_fat_g: Option, + carbs_g: Option, + fiber_g: Option, + sugar_g: Option, + protein_g: Option, + sodium_mg: Option, + potassium_mg: Option, + cholesterol_mg: Option +} pub async fn week(item: Json) -> impl Responder { @@ -54,6 +76,21 @@ pub async fn week_meals(items: Json) -> impl Responder { } } +pub async fn week_lookup(net_id: Path) -> Json { + + let net_id = net_id.into_inner(); + + match get_week(&net_id) { + Ok(week) => Json(week), + Err(e) => { + error!("failed to grab week info from {}: {}", net_id, e); + Json(WeekData::default()) + } + } + +} + + fn add_item(item: &ItemData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)? ; @@ -123,3 +160,36 @@ fn add_menu_items(items: MenuItems) -> Result<()> { info!("inserted menu items into week table {}", items.net_id); Ok(()) } + + +fn get_week(net_id: &str) -> Result { + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + let mut stmt = conn.statement(format!("select * from {}", net_id).as_str()).build()?; + + let rows = stmt.query(&[])?; + let mut week = WeekData::default(); + + for row_result in rows { + let row = row_result?; + week.week.push( ItemResult { + item_id: row.get(0).unwrap_or(None), + amount: row.get(1).unwrap_or(None), + item_name: row.get(2).unwrap_or(None), + calories: row.get(3).unwrap_or(None), + fat_g: row.get(4).unwrap_or(None), + sat_fat_g: row.get(5).unwrap_or(None), + trans_fat_g: row.get(6).unwrap_or(None), + carbs_g: row.get(7).unwrap_or(None), + fiber_g: row.get(8).unwrap_or(None), + sugar_g: row.get(9).unwrap_or(None), + protein_g: row.get(10).unwrap_or(None), + sodium_mg: row.get(11).unwrap_or(None), + potassium_mg: row.get(12).unwrap_or(None), + cholesterol_mg: row.get(13).unwrap_or(None) }); + } + + Ok(week) + + +} diff --git a/backend/src/main.rs b/backend/src/main.rs index e077a44..fb7d16b 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -67,10 +67,10 @@ async fn main() -> std::io::Result<()> { web::resource("/week_meals") .route(web::post().to(api::week::week_meals)) ) - /* .service( + .service( web::resource("/week_progress/{net_id}") .route(web::get().to(api::week::week_lookup)) - ) */ + ) .service( web::resource("/menu_search") .route(web::post().to(api::menu::menu_search)) From 1355ce7b498a55ab6b597abca597e26f67db26d3 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 04:08:18 +0000 Subject: [PATCH 27/35] changed to vec --- backend/src/api/week.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index d1fc3b5..be30e29 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -28,11 +28,6 @@ pub struct MenuItems { item_list: Vec } -#[derive(Serialize, Deserialize, Debug, Default)] -pub struct WeekData{ - week: Vec -} - #[derive(Serialize, Deserialize, Debug, Default)] pub struct ItemResult{ item_id: Option, @@ -76,7 +71,7 @@ pub async fn week_meals(items: Json) -> impl Responder { } } -pub async fn week_lookup(net_id: Path) -> Json { +pub async fn week_lookup(net_id: Path) -> Json> { let net_id = net_id.into_inner(); @@ -84,7 +79,7 @@ pub async fn week_lookup(net_id: Path) -> Json { Ok(week) => Json(week), Err(e) => { error!("failed to grab week info from {}: {}", net_id, e); - Json(WeekData::default()) + Json(vec![]) } } @@ -162,17 +157,17 @@ fn add_menu_items(items: MenuItems) -> Result<()> { } -fn get_week(net_id: &str) -> Result { +fn get_week(net_id: &str) -> Result> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; let mut stmt = conn.statement(format!("select * from {}", net_id).as_str()).build()?; let rows = stmt.query(&[])?; - let mut week = WeekData::default(); + let mut week = vec![]; for row_result in rows { let row = row_result?; - week.week.push( ItemResult { + week.push( ItemResult { item_id: row.get(0).unwrap_or(None), amount: row.get(1).unwrap_or(None), item_name: row.get(2).unwrap_or(None), @@ -188,7 +183,6 @@ fn get_week(net_id: &str) -> Result { potassium_mg: row.get(12).unwrap_or(None), cholesterol_mg: row.get(13).unwrap_or(None) }); } - Ok(week) From d2127218ee81813ad13e90089b22b73adfb5a467 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 00:31:39 -0400 Subject: [PATCH 28/35] lookup on instert into week --- backend/src/api/week.rs | 59 ++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index be30e29..9025cf7 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -132,22 +132,55 @@ fn add_menu_items(items: MenuItems) -> Result<()> { let mut stmt = conn.statement(format!("insert into {} values ( :item_id, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + :item_name, + :calories, + :fat_g, + :sat_fat_g, + :trans_fat_g, + :carbs_g, + :fiber_g, + :sugar_g, + :protein_g, + :sodium_mg, + :potassium_mg, + :cholesterol_mg, 1)", items.net_id).as_str()).build()?; + let mut lookup = conn.statement("select * from nutrition_info natural join menu_item where item_id = :item_id").build()?; + for item in items.item_list { - stmt.execute_named(&[("item_id",&item)])?; + let row = lookup.query_row_named(&[("item_id", &item)])?; + let result: ItemData = ItemData { + net_id: "".to_string(), + item_name: row.get(13).unwrap_or("".to_string()), + amount: None, + calories: row.get(2).unwrap_or(None), + fat_g: row.get(3).unwrap_or(None), + sat_fat_g: row.get(4).unwrap_or(None), + trans_fat_g: row.get(5).unwrap_or(None), + carbs_g: row.get(6).unwrap_or(None), + fiber_g: row.get(7).unwrap_or(None), + sugar_g: row.get(8).unwrap_or(None), + protein_g: row.get(9).unwrap_or(None), + sodium_mg: row.get(10).unwrap_or(None), + potassium_mg: row.get(11).unwrap_or(None), + cholesterol_mg: row.get(12).unwrap_or(None) }; + + stmt.execute_named(&[ + ("item_id",&item), + ("item_name", &result.item_name), + ("calories", &result.calories), + ("fat_g", &result.fat_g), + ("sat_fat_g", &result.sat_fat_g), + ("trans_fat_g", &result.trans_fat_g), + ("carbs_g", &result.carbs_g), + ("fiber_g", &result.fiber_g), + ("sugar_g", &result.sugar_g), + ("protein_g", &result.protein_g), + ("sodium_mg", &result.sodium_mg), + ("potassium_mg", &result.potassium_mg), + ("cholesterol_mg", &result.cholesterol_mg) + ])?; } conn.commit()?; From 9a362728e3bb8293ca389f8c39ba16ff46f886c8 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 00:56:41 -0400 Subject: [PATCH 29/35] added sums --- backend/src/api/week.rs | 44 +++++++++++++++++++++++++++++++++++++++++ backend/src/main.rs | 4 ++++ 2 files changed, 48 insertions(+) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index 9025cf7..dfdf843 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -46,6 +46,21 @@ pub struct ItemResult{ cholesterol_mg: Option } +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct Sums{ + calories: f32, + fat_g: f32, + sat_fat_g: f32, + trans_fat_g: f32, + carbs_g: f32, + fiber_g: f32, + sugar_g: f32, + protein_g: f32, + sodium_mg: f32, + potassium_mg: f32, + cholesterol_mg: f32 +} + pub async fn week(item: Json) -> impl Responder { let item = item.into_inner(); @@ -85,6 +100,35 @@ pub async fn week_lookup(net_id: Path) -> Json> { } +pub async fn week_sums(net_id: Path) -> Json { + let net_id = net_id.into_inner(); + + let week = match get_week(&net_id) { + Ok(week) => week, + Err(e) => { + error!("failed to grab week info from {}: {}", net_id, e); + return Json(Sums::default()); + } + }; + + let mut sums = Sums::default(); + for item in week{ + sums.calories += item.calories.unwrap_or_default(); + sums.fat_g += item.fat_g.unwrap_or_default(); + sums.sat_fat_g += item.sat_fat_g.unwrap_or_default(); + sums.trans_fat_g += item.trans_fat_g.unwrap_or_default(); + sums.carbs_g += item.carbs_g.unwrap_or_default(); + sums.fiber_g += item.fiber_g.unwrap_or_default(); + sums.sugar_g += item.sugar_g.unwrap_or_default(); + sums.protein_g += item.protein_g.unwrap_or_default(); + sums.sodium_mg += item.sodium_mg.unwrap_or_default(); + sums.potassium_mg += item.potassium_mg.unwrap_or_default(); + sums.cholesterol_mg += item.cholesterol_mg.unwrap_or_default(); + } + + Json(sums) +} + fn add_item(item: &ItemData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)? ; diff --git a/backend/src/main.rs b/backend/src/main.rs index fb7d16b..18c7b5f 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -75,6 +75,10 @@ async fn main() -> std::io::Result<()> { web::resource("/menu_search") .route(web::post().to(api::menu::menu_search)) ) + .service( + web::resource("week_sum/{net_id}") + .route(web::get().to(api::week::week_sums)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From 50b5fe53dda927b50ccf3e8c9a7372e1f3fcf807 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 17:16:12 -0400 Subject: [PATCH 30/35] added endpoint for plan lookup --- backend/src/api/plan.rs | 46 ++++++++++++++++++++++++++++++++++++++++- backend/src/main.rs | 4 ++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index f494d7c..dc4dba9 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -1,5 +1,5 @@ use serde::{Serialize, Deserialize}; -use actix_web::{web::Json, Responder, HttpResponse}; +use actix_web::{web::{Json, Path}, Responder, HttpResponse}; use oracle::{Connection, Result}; use log::{error, info}; use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; @@ -33,6 +33,20 @@ pub async fn plan(body: Json) -> impl Responder { } +pub async fn plan_lookup(net_id: Path) -> Json { + + let net_id = net_id.into_inner(); + + match plan_search(&net_id) { + Ok(plan) => Json(plan), + Err(e) => { + error!("failed to grab plan from {}: {}", net_id, e); + Json(PlanData::default()) + } + } + +} + fn create_plan(plan: PlanData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; @@ -61,3 +75,33 @@ fn create_plan(plan: PlanData) -> Result<()> { } + +fn plan_search(net_id: &str) -> Result { + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + + let mut stmt = conn.statement("select * from goal where net_id = :1 and ROWNUM = 1 order by date").build()?; + + let row = stmt.query_row(&[&net_id])?; + + + let plan: PlanData = PlanData { + net_id: row.get(0)?, + week_date: row.get(1)?, + total_cal: row.get(2).unwrap_or(None), + total_fat: row.get(3).unwrap_or(None), + total_sat_fat: row.get(4).unwrap_or(None), + total_trans_fat: row.get(5).unwrap_or(None), + total_carbs: row.get(6).unwrap_or(None), + total_fiber: row.get(7).unwrap_or(None), + total_sugar: row.get(8).unwrap_or(None), + total_protein: row.get(9).unwrap_or(None), + total_sodium: row.get(10).unwrap_or(None), + total_potassium: row.get(11).unwrap_or(None), + total_cholesterol: row.get(12).unwrap_or(None) + }; + + + Ok(plan) + +} diff --git a/backend/src/main.rs b/backend/src/main.rs index 18c7b5f..e0d1754 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -59,6 +59,10 @@ async fn main() -> std::io::Result<()> { web::resource("/goal") .route(web::post().to(api::plan::plan)) ) + .service( + web::resource("/goal/{net_id}") + .route(web::get().to(api::plan::plan_lookup)) + ) .service( web::resource("/week_plan") .route(web::post().to(api::week::week)) From c37166eb123ef07a577903b71a507fce20e85a71 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Mon, 1 May 2023 17:18:49 -0400 Subject: [PATCH 31/35] fixed query --- backend/src/api/plan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index dc4dba9..071ece2 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -80,7 +80,7 @@ fn plan_search(net_id: &str) -> Result { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; - let mut stmt = conn.statement("select * from goal where net_id = :1 and ROWNUM = 1 order by date").build()?; + let mut stmt = conn.statement("select * from goal where s_net_id = :1 and ROWNUM = 1 order by week_date").build()?; let row = stmt.query_row(&[&net_id])?; From 1517e72833eccaf7a870c3a87ba67216f1d363b9 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Tue, 2 May 2023 17:53:33 -0400 Subject: [PATCH 32/35] added 3 new endpoints --- backend/src/api/mod.rs | 2 ++ backend/src/api/plan.rs | 45 ++++++++++++++++++++++++++++++++++++ backend/src/api/result.rs | 48 +++++++++++++++++++++++++++++++++++++++ backend/src/api/week.rs | 27 ++++++++++++++++++++++ backend/src/main.rs | 9 ++++++++ 5 files changed, 131 insertions(+) create mode 100644 backend/src/api/result.rs diff --git a/backend/src/api/mod.rs b/backend/src/api/mod.rs index 1055da8..624e50f 100644 --- a/backend/src/api/mod.rs +++ b/backend/src/api/mod.rs @@ -3,4 +3,6 @@ pub mod eatery; pub mod plan; pub mod week; pub mod menu; +pub mod result; + diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index 071ece2..1173b80 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -47,6 +47,18 @@ pub async fn plan_lookup(net_id: Path) -> Json { } +pub async fn all_plan(net_id: Path) -> Json> { + + let net_id = net_id.into_inner(); + + match get_all_plan(&net_id) { + Ok(plans) => Json(plans), + Err(e) => { + error!("failed to grab plans from {}: {}", net_id, e); + Json(vec![]) + } + } +} fn create_plan(plan: PlanData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; @@ -105,3 +117,36 @@ fn plan_search(net_id: &str) -> Result { Ok(plan) } + +fn get_all_plan(net_id: &str) -> Result> { + + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + + let mut stmt = conn.statement("select * from goal where s_net_id = :1 order by week_date").build()?; + + + let rows = stmt.query(&[&net_id])?; + let mut row_vec: Vec = vec![]; + + for row_result in rows { + let row = row_result?; + row_vec.push(PlanData { + net_id: row.get(0)?, + week_date: row.get(1)?, + total_cal: row.get(2).unwrap_or(None), + total_fat: row.get(3).unwrap_or(None), + total_sat_fat: row.get(4).unwrap_or(None), + total_trans_fat: row.get(5).unwrap_or(None), + total_carbs: row.get(6).unwrap_or(None), + total_fiber: row.get(7).unwrap_or(None), + total_sugar: row.get(8).unwrap_or(None), + total_protein: row.get(9).unwrap_or(None), + total_sodium: row.get(10).unwrap_or(None), + total_potassium: row.get(11).unwrap_or(None), + total_cholesterol: row.get(12).unwrap_or(None)}); + } + + Ok(row_vec) + +} diff --git a/backend/src/api/result.rs b/backend/src/api/result.rs new file mode 100644 index 0000000..fcc79e4 --- /dev/null +++ b/backend/src/api/result.rs @@ -0,0 +1,48 @@ +use log::error; +use actix_web::{web::Json, web::Path}; +use oracle::{Connection, Result}; +use crate::{api::plan::PlanData, config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}}; + + + +pub async fn all_result(net_id: Path) -> Json> { + let net_id = net_id.into_inner(); + + match get_result(&net_id){ + Ok(r) => Json(r), + Err(e) => { + error!("failed to get results for user {}: {}", net_id, e); + Json(vec![]) + } + } +} + + +fn get_result(net_id: &str) -> Result> { + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + let mut stmt = conn.statement("select * from result where net_id = :1").build()?; + + let rows = stmt.query(&[&net_id])?; + let mut row_vec: Vec = vec![]; + for row_result in rows { + let row = row_result?; + + row_vec.push(PlanData { + net_id: row.get(0)?, + week_date: row.get(1)?, + total_cal: row.get(2).unwrap_or(None), + total_fat: row.get(3).unwrap_or(None), + total_sat_fat: row.get(4).unwrap_or(None), + total_trans_fat: row.get(5).unwrap_or(None), + total_carbs: row.get(6).unwrap_or(None), + total_fiber: row.get(7).unwrap_or(None), + total_sugar: row.get(8).unwrap_or(None), + total_protein: row.get(9).unwrap_or(None), + total_sodium: row.get(10).unwrap_or(None), + total_potassium: row.get(11).unwrap_or(None), + total_cholesterol: row.get(12).unwrap_or(None) }); + } + + Ok(row_vec) +} diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index dfdf843..651370a 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -130,6 +130,19 @@ pub async fn week_sums(net_id: Path) -> Json { } +pub async fn delete_meals(items: Json ) -> impl Responder { + let items = items.into_inner(); + + match week_meal_delete(&items) { + Ok(_) => HttpResponse::Ok(), + Err(e) => { + error!("failed to delete items from {}: {}", items.net_id, e); + HttpResponse::InternalServerError() + } + } +} + + fn add_item(item: &ItemData) -> Result<()> { let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)? ; @@ -264,3 +277,17 @@ fn get_week(net_id: &str) -> Result> { } + + +fn week_meal_delete(items: &MenuItems) -> Result<()> { + + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + + let mut stmt = conn.statement(format!("delete from {} where item_id = :1", items.net_id).as_str()).build()?; + + for meal in items.item_list { + stmt.execute(&[&items.net_id])?; + } + + Ok(()) +} diff --git a/backend/src/main.rs b/backend/src/main.rs index e0d1754..6bf9992 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -70,6 +70,7 @@ async fn main() -> std::io::Result<()> { .service( web::resource("/week_meals") .route(web::post().to(api::week::week_meals)) + .route(web::delete().to(api::week::delete_meals)) ) .service( web::resource("/week_progress/{net_id}") @@ -83,6 +84,14 @@ async fn main() -> std::io::Result<()> { web::resource("week_sum/{net_id}") .route(web::get().to(api::week::week_sums)) ) + .service( + web::resource("all_goal/{net_id}") + .route(web::get().to(api::plan::all_plan)) + ) + .service( + web::resource("result/{net_id}") + .route(web::get().to(api::result::all_result)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From c52bc3ce7ed33d494b517ff9709edd89c535c259 Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Tue, 2 May 2023 18:08:03 -0400 Subject: [PATCH 33/35] add to result and pub plan --- backend/src/api/plan.rs | 26 +++++++++++++------------- backend/src/api/result.rs | 38 +++++++++++++++++++++++++++++++++++++- backend/src/main.rs | 4 ++++ 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/backend/src/api/plan.rs b/backend/src/api/plan.rs index 1173b80..072b075 100644 --- a/backend/src/api/plan.rs +++ b/backend/src/api/plan.rs @@ -6,19 +6,19 @@ use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR}; #[derive(Deserialize, Serialize, Debug, Default)] pub struct PlanData{ - net_id: String, - week_date: String, - total_cal: Option, - total_fat: Option, - total_sat_fat: Option, - total_trans_fat: Option, - total_carbs: Option, - total_fiber: Option, - total_sugar: Option, - total_protein: Option, - total_sodium: Option, - total_potassium: Option, - total_cholesterol: Option + pub net_id: String, + pub week_date: String, + pub total_cal: Option, + pub total_fat: Option, + pub total_sat_fat: Option, + pub total_trans_fat: Option, + pub total_carbs: Option, + pub total_fiber: Option, + pub total_sugar: Option, + pub total_protein: Option, + pub total_sodium: Option, + pub total_potassium: Option, + pub total_cholesterol: Option } pub async fn plan(body: Json) -> impl Responder { diff --git a/backend/src/api/result.rs b/backend/src/api/result.rs index fcc79e4..5bb308f 100644 --- a/backend/src/api/result.rs +++ b/backend/src/api/result.rs @@ -1,5 +1,5 @@ use log::error; -use actix_web::{web::Json, web::Path}; +use actix_web::{web::Json, web::Path, Responder, HttpResponse}; use oracle::{Connection, Result}; use crate::{api::plan::PlanData, config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR}}; @@ -17,6 +17,18 @@ pub async fn all_result(net_id: Path) -> Json> { } } +pub async fn add_result(result: Json) -> impl Responder { + let result = result.into_inner(); + + match push_result(&result){ + Ok(_) => HttpResponse::Ok(), + Err(e) => { + error!("failed to add result for user {}: {}", result.net_id, e); + HttpResponse::InternalServerError() + } + } +} + fn get_result(net_id: &str) -> Result> { @@ -46,3 +58,27 @@ fn get_result(net_id: &str) -> Result> { Ok(row_vec) } + + +fn push_result(plan: &PlanData) -> Result<()> { + let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?; + let mut stmt = conn.statement("insert into result values(:net_id, :week_date, :total_cal, :total_fat, :total_sat_fat, :total_trans_fat, :total_carbs, :total_fiber, :total_sugar, :total_protein, :total_sodium, :total_potassium, :total_cholesterol)").build()?; + + stmt.execute_named(&[ + ("net_id", &plan.net_id), + ("week_date", &plan.week_date), + ("total_cal", &plan.total_cal), + ("total_fat", &plan.total_fat), + ("total_sat_fat", &plan.total_sat_fat), + ("total_trans_fat", &plan.total_trans_fat), + ("total_carbs", &plan.total_carbs), + ("total_fiber", &plan.total_fiber), + ("total_sugar", &plan.total_sugar), + ("total_protein", &plan.total_protein), + ("total_sodium", &plan.total_sodium), + ("total_potassium", &plan.total_potassium), + ("total_cholesterol", &plan.total_cholesterol)])?; + + Ok(()) + +} diff --git a/backend/src/main.rs b/backend/src/main.rs index 6bf9992..98009df 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -92,6 +92,10 @@ async fn main() -> std::io::Result<()> { web::resource("result/{net_id}") .route(web::get().to(api::result::all_result)) ) + .service( + web::resource("add_result/") + .route(web::post().to(api::result::add_result)) + ) .route("/", web::get().to(api_index)) ) .route("/", web::get().to(index)) From 12f16b414540083cf89ede701a0a562d3f83d53e Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Tue, 2 May 2023 22:12:31 +0000 Subject: [PATCH 34/35] minor bug fix --- backend/src/api/week.rs | 4 ++-- backend/src/main.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/api/week.rs b/backend/src/api/week.rs index 651370a..10d1422 100644 --- a/backend/src/api/week.rs +++ b/backend/src/api/week.rs @@ -285,8 +285,8 @@ fn week_meal_delete(items: &MenuItems) -> Result<()> { let mut stmt = conn.statement(format!("delete from {} where item_id = :1", items.net_id).as_str()).build()?; - for meal in items.item_list { - stmt.execute(&[&items.net_id])?; + for meal in &items.item_list { + stmt.execute(&[meal])?; } Ok(()) diff --git a/backend/src/main.rs b/backend/src/main.rs index 98009df..2cff7be 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -93,7 +93,7 @@ async fn main() -> std::io::Result<()> { .route(web::get().to(api::result::all_result)) ) .service( - web::resource("add_result/") + web::resource("/add_result") .route(web::post().to(api::result::add_result)) ) .route("/", web::get().to(api_index)) From f7f00e93641d05342e2673891e7260fcc7728f9e Mon Sep 17 00:00:00 2001 From: Colin McKechney Date: Sun, 7 May 2023 19:12:58 +0000 Subject: [PATCH 35/35] final commit for backend --- backend/src/api/menu.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/src/api/menu.rs b/backend/src/api/menu.rs index d85d246..8178c45 100644 --- a/backend/src/api/menu.rs +++ b/backend/src/api/menu.rs @@ -20,7 +20,8 @@ pub struct SearchResult { item_name: Option, item_id: u32, eatery_id: Option, - serving_size: Option + serving_size: Option, + eatery_name: Option } pub async fn menu_search(term: Json) -> Json { @@ -39,7 +40,7 @@ pub async fn menu_search(term: Json) -> Json { fn fuzzy_search(term: &str) -> Result { let conn = Connection::connect(ORACLE_USER,ORACLE_PASS,ORACLE_CON_STR)?; - let mut stmt = conn.statement(format!("select * from menu_item where item_name like '{}%'", term).as_str()).build()?; + let mut stmt = conn.statement(format!("select * from menu_item inner join eatery on menu_item.eatery_id = eatery.id where item_name like '%{}%'", term).as_str()).build()?; let rows = stmt.query(&[])?; @@ -51,7 +52,8 @@ fn fuzzy_search(term: &str) -> Result { item_name: row.get(0).unwrap_or(None), item_id: row.get(1)?, eatery_id: row.get(2).unwrap_or(None), - serving_size: row.get(3).unwrap_or(None) + serving_size: row.get(3).unwrap_or(None), + eatery_name: row.get(5).unwrap_or(None) }); } conn.close()?;