Compare commits
44 Commits
6c30a3e0eb
...
9a6996d2c1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a6996d2c1 | ||
|
|
fbbdfd246c | ||
|
|
7fc27e3337 | ||
|
|
c07b0143e7 | ||
|
|
342f0c9501 | ||
|
|
f7f00e9364 | ||
|
|
6e1ed08637 | ||
|
|
264d3ff80b | ||
|
|
b91b1afa62 | ||
|
|
2c05005ca0 | ||
|
|
12f16b4145 | ||
|
|
c52bc3ce7e | ||
|
|
1517e72833 | ||
|
|
c37166eb12 | ||
|
|
50b5fe53dd | ||
|
|
9a362728e3 | ||
|
|
d2127218ee | ||
|
|
1355ce7b49 | ||
|
|
62821f2081 | ||
|
|
d4ee895b80 | ||
|
|
d1138c12cf | ||
|
|
7c52c2dd0e | ||
|
|
8ebf0c162c | ||
|
|
4f6bffaf17 | ||
|
|
7dd488d23f | ||
|
|
cff79f2cc6 | ||
|
|
509417bc75 | ||
|
|
d65d412a11 | ||
|
|
b0dce09473 | ||
|
|
159faa8fef | ||
|
|
bbab7882cc | ||
|
|
402dcd8efe | ||
|
|
5c11b7b463 | ||
|
|
443dc0e101 | ||
|
|
24ca48fe51 | ||
|
|
f009dd7166 | ||
|
|
5117a3318f | ||
|
|
ec08c12780 | ||
|
|
82b4be1ba1 | ||
|
|
c76a63735a | ||
|
|
cc1c370e56 | ||
|
|
7f1e4a0808 | ||
|
|
2a47588eb1 | ||
|
|
e32c1f9492 |
BIN
Advanced Databases Final Report.pdf
Normal file
BIN
Advanced Databases Final Report.pdf
Normal file
Binary file not shown.
BIN
Group 09 Final Presentation.pptx
Normal file
BIN
Group 09 Final Presentation.pptx
Normal file
Binary file not shown.
211
Cargo.lock → backend/Cargo.lock
generated
211
Cargo.lock → backend/Cargo.lock
generated
@@ -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"
|
||||
@@ -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"
|
||||
75
backend/src/api/eatery.rs
Normal file
75
backend/src/api/eatery.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use actix_web::{web::Path, web::Json};
|
||||
use oracle::Connection;
|
||||
use log::error;
|
||||
use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct FoodItem {
|
||||
item_id: u32,
|
||||
eatery_id: Option<u32>,
|
||||
item_name: Option<String>,
|
||||
serving_size: Option<String>,
|
||||
calories: Option<f32>,
|
||||
fat: Option<f32>,
|
||||
sat_fat: Option<f32>,
|
||||
trans_fat: Option<f32>,
|
||||
carbs: Option<f32>,
|
||||
fiber: Option<f32>,
|
||||
sugar: Option<f32>,
|
||||
protein: Option<f32>,
|
||||
sodium: Option<f32>,
|
||||
potassium: Option<f32>,
|
||||
cholesterol: Option<f32>
|
||||
}
|
||||
|
||||
|
||||
pub async fn menu(eatery: Path<String>) -> Json<Vec<FoodItem>> {
|
||||
let eatery = eatery.into_inner();
|
||||
let response = match grab_rows(eatery) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
error!("Failed to grab rows: {}", e);
|
||||
return Json(vec![]);
|
||||
}
|
||||
};
|
||||
|
||||
Json(response)
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn grab_rows(eatery: String) -> oracle::Result<Vec<FoodItem>> {
|
||||
|
||||
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()?;
|
||||
|
||||
|
||||
let rows = stmt.query(&[&eatery])?;
|
||||
let mut row_vec: Vec<FoodItem> = vec![];
|
||||
|
||||
for row_result in rows {
|
||||
let row = row_result?;
|
||||
row_vec.push( FoodItem {
|
||||
item_id: row.get(0)?,
|
||||
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)});
|
||||
}
|
||||
|
||||
conn.close()?;
|
||||
|
||||
Ok(row_vec)
|
||||
}
|
||||
64
backend/src/api/menu.rs
Normal file
64
backend/src/api/menu.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use oracle::{Result, Connection};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use log::error;
|
||||
use actix_web::{web::Json};
|
||||
|
||||
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<SearchResult>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct SearchResult {
|
||||
item_name: Option<String>,
|
||||
item_id: u32,
|
||||
eatery_id: Option<u32>,
|
||||
serving_size: Option<String>,
|
||||
eatery_name: Option<String>
|
||||
}
|
||||
|
||||
pub async fn menu_search(term: Json<SearchTerm>) -> Json<SearchResults> {
|
||||
|
||||
let term = term.into_inner();
|
||||
|
||||
match fuzzy_search(&term.search_term) {
|
||||
Ok(result) => Json(result),
|
||||
Err(e) => {
|
||||
error!("failed to search for {}: {}", term.search_term, e);
|
||||
Json(SearchResults::default())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn fuzzy_search(term: &str) -> Result<SearchResults> {
|
||||
let conn = Connection::connect(ORACLE_USER,ORACLE_PASS,ORACLE_CON_STR)?;
|
||||
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(&[])?;
|
||||
|
||||
let mut 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),
|
||||
eatery_name: row.get(5).unwrap_or(None)
|
||||
});
|
||||
}
|
||||
conn.close()?;
|
||||
|
||||
Ok(rows_vec)
|
||||
|
||||
}
|
||||
|
||||
8
backend/src/api/mod.rs
Normal file
8
backend/src/api/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod user;
|
||||
pub mod eatery;
|
||||
pub mod plan;
|
||||
pub mod week;
|
||||
pub mod menu;
|
||||
pub mod result;
|
||||
|
||||
|
||||
152
backend/src/api/plan.rs
Normal file
152
backend/src/api/plan.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
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};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
pub struct PlanData{
|
||||
pub net_id: String,
|
||||
pub week_date: String,
|
||||
pub total_cal: Option<f32>,
|
||||
pub total_fat: Option<f32>,
|
||||
pub total_sat_fat: Option<f32>,
|
||||
pub total_trans_fat: Option<f32>,
|
||||
pub total_carbs: Option<f32>,
|
||||
pub total_fiber: Option<f32>,
|
||||
pub total_sugar: Option<f32>,
|
||||
pub total_protein: Option<f32>,
|
||||
pub total_sodium: Option<f32>,
|
||||
pub total_potassium: Option<f32>,
|
||||
pub total_cholesterol: Option<f32>
|
||||
}
|
||||
|
||||
pub async fn plan(body: Json<PlanData>) -> impl Responder {
|
||||
let body = body.into_inner();
|
||||
match create_plan(body) {
|
||||
Ok(_) => HttpResponse::Ok(),
|
||||
Err(e) => {
|
||||
error!("failed to create plan {}", e);
|
||||
HttpResponse::InternalServerError()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn plan_lookup(net_id: Path<String>) -> Json<PlanData> {
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn all_plan(net_id: Path<String>) -> Json<Vec<PlanData>> {
|
||||
|
||||
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)?;
|
||||
|
||||
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),
|
||||
("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)])?;
|
||||
|
||||
info!("Created new plan for user: {}", plan.net_id);
|
||||
conn.commit()?;
|
||||
conn.close()?;
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn plan_search(net_id: &str) -> Result<PlanData> {
|
||||
|
||||
let conn = Connection::connect(ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR)?;
|
||||
|
||||
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])?;
|
||||
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
fn get_all_plan(net_id: &str) -> Result<Vec<PlanData>> {
|
||||
|
||||
|
||||
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<PlanData> = 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)
|
||||
|
||||
}
|
||||
84
backend/src/api/result.rs
Normal file
84
backend/src/api/result.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use log::error;
|
||||
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}};
|
||||
|
||||
|
||||
|
||||
pub async fn all_result(net_id: Path<String>) -> Json<Vec<PlanData>> {
|
||||
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![])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_result(result: Json<PlanData>) -> 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<Vec<PlanData>> {
|
||||
|
||||
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<PlanData> = 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)
|
||||
}
|
||||
|
||||
|
||||
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(())
|
||||
|
||||
}
|
||||
185
backend/src/api/user.rs
Normal file
185
backend/src/api/user.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
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};
|
||||
use crate::config::{ORACLE_USER, ORACLE_PASS, ORACLE_CON_STR};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
pub struct NewUser {
|
||||
net_id: String,
|
||||
password: String,
|
||||
first_name: String,
|
||||
last_name: String
|
||||
}
|
||||
|
||||
|
||||
pub async fn login(request: HttpRequest, body: web::Json<Entry>) -> 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) => {
|
||||
web::Json(user);
|
||||
HttpResponse::Ok()
|
||||
},
|
||||
None => {
|
||||
web::Json(User::default());
|
||||
HttpResponse::Unauthorized()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn logout() -> impl Responder {
|
||||
HttpResponse::Ok()
|
||||
}
|
||||
|
||||
pub async fn signup(request: HttpRequest, body: web::Json<NewUser>) -> impl Responder {
|
||||
let body = body.into_inner();
|
||||
|
||||
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.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) => {
|
||||
error!("Error creating new user: {}", e);
|
||||
HttpResponse::InternalServerError()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn authenticate(username: &str, password: &str) -> Option<User> {
|
||||
|
||||
info!("Authenticating user: {}", username);
|
||||
|
||||
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);
|
||||
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(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();
|
||||
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), ("pswd", &hash_string), ("salt", &salt)]) {
|
||||
Ok(_) => {
|
||||
info!("User {} successfully created", username);
|
||||
conn.commit()?;
|
||||
},
|
||||
Err(_) => {
|
||||
warn!("Failed to create user {}", username);
|
||||
conn.rollback()?;
|
||||
}
|
||||
};
|
||||
|
||||
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(_) => {
|
||||
info!("User {} week table created", username);
|
||||
conn.commit()?;
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Failed to create week table for {} {}", username, e);
|
||||
conn.rollback()?;
|
||||
}
|
||||
};
|
||||
|
||||
conn.close()?;
|
||||
Ok(())
|
||||
|
||||
}
|
||||
295
backend/src/api/week.rs
Normal file
295
backend/src/api/week.rs
Normal file
@@ -0,0 +1,295 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use log::{error, info};
|
||||
use actix_web::{self, Responder, web::{Json, Path}, HttpResponse};
|
||||
use oracle::{Connection, Result};
|
||||
use crate::config::{ORACLE_PASS, ORACLE_USER, ORACLE_CON_STR};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct ItemData{
|
||||
net_id: String,
|
||||
item_name: String,
|
||||
amount: Option<f32>,
|
||||
calories: Option<f32>,
|
||||
fat_g: Option<f32>,
|
||||
sat_fat_g: Option<f32>,
|
||||
trans_fat_g: Option<f32>,
|
||||
carbs_g: Option<f32>,
|
||||
fiber_g: Option<f32>,
|
||||
sugar_g: Option<f32>,
|
||||
protein_g: Option<f32>,
|
||||
sodium_mg: Option<f32>,
|
||||
potassium_mg: Option<f32>,
|
||||
cholesterol_mg: Option<f32>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct MenuItems {
|
||||
net_id: String,
|
||||
item_list: Vec<u32>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct ItemResult{
|
||||
item_id: Option<u32>,
|
||||
amount: Option<u32>,
|
||||
item_name: Option<String>,
|
||||
calories: Option<f32>,
|
||||
fat_g: Option<f32>,
|
||||
sat_fat_g: Option<f32>,
|
||||
trans_fat_g: Option<f32>,
|
||||
carbs_g: Option<f32>,
|
||||
fiber_g: Option<f32>,
|
||||
sugar_g: Option<f32>,
|
||||
protein_g: Option<f32>,
|
||||
sodium_mg: Option<f32>,
|
||||
potassium_mg: Option<f32>,
|
||||
cholesterol_mg: Option<f32>
|
||||
}
|
||||
|
||||
#[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<ItemData>) -> 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn week_meals(items: Json<MenuItems>) -> 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn week_lookup(net_id: Path<String>) -> Json<Vec<ItemResult>> {
|
||||
|
||||
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(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn week_sums(net_id: Path<String>) -> Json<Sums> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
pub async fn delete_meals(items: Json<MenuItems> ) -> 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)? ;
|
||||
|
||||
let mut stmt = conn.statement(format!("insert into {} values (NULL, :amount, :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(&[
|
||||
("amount", &item.amount),
|
||||
("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(())
|
||||
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
: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 {
|
||||
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()?;
|
||||
conn.close()?;
|
||||
info!("inserted menu items into week table {}", items.net_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn get_week(net_id: &str) -> Result<Vec<ItemResult>> {
|
||||
|
||||
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 = vec![];
|
||||
|
||||
for row_result in rows {
|
||||
let row = row_result?;
|
||||
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)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
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(&[meal])?;
|
||||
}
|
||||
|
||||
conn.commit()?;
|
||||
conn.close()?;
|
||||
Ok(())
|
||||
}
|
||||
4
backend/src/config.rs
Normal file
4
backend/src/config.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub const ORACLE_USER: &str = "timmy";
|
||||
pub const ORACLE_PASS: &str = "timmy";
|
||||
pub const ORACLE_CON_STR: &str = "";
|
||||
|
||||
116
backend/src/main.rs
Normal file
116
backend/src/main.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use env_logger::Env;
|
||||
use actix_web::{web, App, HttpResponse, HttpServer, Responder, middleware, cookie::Key};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use actix_cors::Cors;
|
||||
use actix_identity::IdentityMiddleware;
|
||||
use actix_session::{SessionMiddleware, storage::CookieSessionStore};
|
||||
|
||||
mod api;
|
||||
mod config;
|
||||
|
||||
static PORT: u16 = 8000;
|
||||
const ALLOWED_ORIGIN: &str = "http://3.219.93.142:8009";
|
||||
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
||||
struct Login {
|
||||
net_id: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
|
||||
#[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);
|
||||
|
||||
let secret_key = Key::generate();
|
||||
|
||||
let _ = HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(middleware::Logger::default())
|
||||
.wrap(
|
||||
Cors::default()
|
||||
.allowed_origin(ALLOWED_ORIGIN)
|
||||
.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()))
|
||||
.service(
|
||||
web::scope("/api")
|
||||
.service(
|
||||
web::resource("/auth")
|
||||
.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))
|
||||
)
|
||||
.service(
|
||||
web::resource("/eatery/{eatery_id}")
|
||||
.route(web::get().to(api::eatery::menu))
|
||||
)
|
||||
.service(
|
||||
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))
|
||||
)
|
||||
.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}")
|
||||
.route(web::get().to(api::week::week_lookup))
|
||||
)
|
||||
.service(
|
||||
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))
|
||||
)
|
||||
.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))
|
||||
)
|
||||
.service(
|
||||
web::resource("/add_result")
|
||||
.route(web::post().to(api::result::add_result))
|
||||
)
|
||||
.route("/", web::get().to(api_index))
|
||||
)
|
||||
.route("/", web::get().to(index))
|
||||
})
|
||||
.bind(("0.0.0.0", PORT))?
|
||||
.run()
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn api_index() -> impl Responder {
|
||||
HttpResponse::Ok().body("api")
|
||||
}
|
||||
async fn index() -> impl Responder {
|
||||
HttpResponse::Ok().body("/")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "db_app",
|
||||
"homepage": "https://3.219.93.142:8009",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -41,6 +41,10 @@ export function Login() {
|
||||
navigate('/Plan');
|
||||
}
|
||||
|
||||
const navigateProg = () => {
|
||||
navigate('/ThisWeek');
|
||||
}
|
||||
|
||||
//State variable for login data
|
||||
const [data,setData] = useState({
|
||||
net_id:"",
|
||||
@@ -74,7 +78,7 @@ export function Login() {
|
||||
console.log(response.status);
|
||||
if (response.status === 200){
|
||||
setSession();
|
||||
navigateHome();
|
||||
navigateProg();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -125,17 +125,17 @@ const submitGoalHandler = evt => {
|
||||
{
|
||||
net_id: net_id,
|
||||
week_date: weekStart(),
|
||||
total_cal: Number(total_cal[0]),
|
||||
total_fat: Number(total_fat[0]),
|
||||
total_sat_fat: Number(total_sat_fat[0]),
|
||||
total_trans_fat: Number(total_trans_fat[0]),
|
||||
total_carbs: Number(total_carbs[0]),
|
||||
total_fiber: Number(total_fiber[0]),
|
||||
total_sugar: Number(total_sugar[0]),
|
||||
total_protein: Number(total_protein[0]),
|
||||
total_sodium: Number(total_sodium[0]),
|
||||
total_potassium: Number(total_potassium[0]),
|
||||
total_cholesterol: Number(total_cholesterol[0])
|
||||
total_cal: Number(total_cal[0])*7,
|
||||
total_fat: Number(total_fat[0])*7,
|
||||
total_sat_fat: Number(total_sat_fat[0])*7,
|
||||
total_trans_fat: Number(total_trans_fat[0])*7,
|
||||
total_carbs: Number(total_carbs[0])*7,
|
||||
total_fiber: Number(total_fiber[0])*7,
|
||||
total_sugar: Number(total_sugar[0])*7,
|
||||
total_protein: Number(total_protein[0])*7,
|
||||
total_sodium: Number(total_sodium[0])*7,
|
||||
total_potassium: Number(total_potassium[0])*7,
|
||||
total_cholesterol: Number(total_cholesterol[0])*7
|
||||
}).then((response) => {
|
||||
console.log(response);
|
||||
console.log(response.status);
|
||||
|
||||
@@ -142,7 +142,7 @@ const net_id = ReactSession.get("net_id");
|
||||
|
||||
}
|
||||
|
||||
const [toDelete, setToDelete] = useState([]);
|
||||
const [toDelete, setToDelete] = useState([{}]);
|
||||
|
||||
const removeItem = (index) => {
|
||||
setToDelete([
|
||||
@@ -197,7 +197,9 @@ const net_id = ReactSession.get("net_id");
|
||||
).then((response) => {
|
||||
console.log(response);
|
||||
});
|
||||
console.log("results sent");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -314,6 +316,8 @@ const net_id = ReactSession.get("net_id");
|
||||
setColors()
|
||||
console.log('Colors set')
|
||||
console.log(planDay())
|
||||
sendResults()
|
||||
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
66
src/main.rs
66
src/main.rs
@@ -1,66 +0,0 @@
|
||||
use log::{info, warn, error};
|
||||
use env_logger::Env;
|
||||
use actix_web::{web, get, post, web::Json, App, HttpResponse, HttpServer, Responder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
mod security;
|
||||
|
||||
static PORT: u16 = 8009;
|
||||
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
||||
struct Login {
|
||||
net_id: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
|
||||
#[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);
|
||||
|
||||
let _ = HttpServer::new( || {
|
||||
App::new()
|
||||
.service(index)
|
||||
.service(login)
|
||||
.service(homepage)
|
||||
.service(plan_page)
|
||||
})
|
||||
.bind(("0.0.0.0", 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 index() -> impl Responder {
|
||||
HttpResponse::Ok().body("Hello world!")
|
||||
}
|
||||
|
||||
#[get("/login")]
|
||||
async fn login(json: Json<Login>) -> Result<String, actix_web::Error> {
|
||||
Ok(format!("{} {}", json.net_id, json.password))
|
||||
}
|
||||
|
||||
#[get("/{net_id}/home")]
|
||||
async fn homepage(path: web::Path<String>) -> 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<String>) -> impl Responder {
|
||||
let net_id = path.into_inner();
|
||||
HttpResponse::Ok().body(format!("You have reached the plan page of {}", net_id))
|
||||
}
|
||||
@@ -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<bool, Error> {
|
||||
|
||||
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(())
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user