From cd87a665a68e034c87e0f33a8f60738cbcb2b676 Mon Sep 17 00:00:00 2001 From: vedantgu Date: Sat, 11 Jun 2022 10:45:25 +0530 Subject: [PATCH 1/3] working version --- .DS_Store | Bin 0 -> 6148 bytes README.md | 6 +-- sample-config.toml | 2 +- src/admin.rs | 7 ++-- src/backend.rs | 99 ++++++++++++++++++++++++++++++++++++++++----- src/questions.rs | 16 +++----- src/schema.sql | 9 +++-- 7 files changed, 109 insertions(+), 30 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..da7185f53c25eefd427e62b4103745b35aefb852 GIT binary patch literal 6148 zcmeHK&1%~~5T3Q2L?RS?Xd%aiTwUt?G*EgGZt?G(%^U6~t4p~BZ@<(0>KxP{?Ylhv1Hil^gL z@A?@}tI||g@UVB28cMM6E6S-^O%D;s>6#`~B7yCCHH=abVL%uV2A($qeise4pZ7B4 z>4gDd;0YMu{Xs(+Baf{^yLDi&Eda0ww-wmjOK^?$77*iuG71C2z(WSQZrbPb|K#!h|6!5LgaKjTMKPdy z$MNw9OY&#y+T!@E)zAwl3+J^C|CGS6M=^5wDBgiufnT!$j6Aju;ep7HfTckOVc?%K F@Ed%6TPy$o literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 26ef349..2915b36 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # websubmit-rs: a simple class submission system This is a fork for websubmit-rs, a web application for collecting student homework -submissions, written using [Rocket](https://rocket.rs) for a MySQL backend. +submissions, written using [Rocket](https://rocket.rs) running on a GDPR compliant Pelton backend. -To run it, you need to run a MySQL server deployment. +To run it, you need to run a Pelton server deployment. Then you can run the web application, which will automatically connect -to MySQL database `myclass`: +to Pelton database `myclass`: ``` websubmit-rs$ cargo run --release -- -i myclass ``` diff --git a/sample-config.toml b/sample-config.toml index cb2ef3e..de48448 100644 --- a/sample-config.toml +++ b/sample-config.toml @@ -11,6 +11,6 @@ resource_dir = "/path/to/resources" # a secret that will be hashed into user's API keys to make them unforgeable secret = "SECRET" # whether to send emails (set to false for development) -send_emails = true +send_emails = false # whether to reset the db (set to false for production) prime = true diff --git a/src/admin.rs b/src/admin.rs index a357e21..40fe0f8 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -94,7 +94,7 @@ pub(crate) fn lec_add_submit( pub(crate) fn lec(_adm: Admin, num: u8, backend: &State>>) -> Template { let mut bg = backend.lock().unwrap(); let res = bg.prep_exec( - "SELECT * FROM questions WHERE lec = ?", + "SELECT lec , q , question FROM questions WHERE lec = ?", vec![(num as u64).into()], ); drop(bg); @@ -130,6 +130,7 @@ pub(crate) fn addq( bg.insert( "questions", vec![ + format!("{}-{}", num, data.q_id).into(), (num as u64).into(), (data.q_id as u64).into(), data.q_prompt.to_string().into(), @@ -149,7 +150,7 @@ pub(crate) fn editq( ) -> Template { let mut bg = backend.lock().unwrap(); let res = bg.prep_exec( - "SELECT * FROM questions WHERE lec = ?", + "SELECT lec , q , question FROM questions WHERE lec = ?", vec![(num as u64).into()], ); drop(bg); @@ -194,7 +195,7 @@ pub(crate) fn get_registered_users( config: &State, ) -> Template { let mut bg = backend.lock().unwrap(); - let res = bg.prep_exec("SELECT email, is_admin, apikey FROM users", vec![]); + let res = bg.prep_exec("SELECT PII_email, is_admin, apikey FROM users", vec![]); drop(bg); let users: Vec<_> = res diff --git a/src/backend.rs b/src/backend.rs index a3df7e6..d7bd6de 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -4,6 +4,7 @@ pub use mysql::Value; use mysql::*; use std::collections::HashMap; + pub struct MySqlBackend { pub handle: mysql::Conn, pub log: slog::Logger, @@ -25,19 +26,20 @@ impl MySqlBackend { "Connecting to MySql DB and initializing schema {}...", dbname ); let mut db = mysql::Conn::new( - Opts::from_url(&format!("mysql://root:password@127.0.0.1/{}", dbname)).unwrap(), + Opts::from_url(&format!("mysql://pelton:password@127.0.0.1:10001/{}", dbname)).unwrap(), ) .unwrap(); assert_eq!(db.ping(), true); if prime { - db.query_drop(format!("DROP DATABASE IF EXISTS {};", dbname)) - .unwrap(); - db.query_drop(format!("CREATE DATABASE {};", dbname)) - .unwrap(); + //note remember to fix this + //db.query_drop(format!("DROP DATABASE IF EXISTS {};", dbname)) + // .unwrap(); + //db.query_drop(format!("CREATE DATABASE {};", dbname)) + // .unwrap(); // reconnect db = mysql::Conn::new( - Opts::from_url(&format!("mysql://root:password@127.0.0.1/{}", dbname)).unwrap(), + Opts::from_url(&format!("mysql://pelton:password@127.0.0.1:10001/{}", dbname)).unwrap(), ) .unwrap(); for line in schema.lines() { @@ -80,11 +82,36 @@ impl MySqlBackend { fn do_insert(&mut self, table: &str, vals: Vec, replace: bool) { let op = if replace { "REPLACE" } else { "INSERT" }; + //changes to be made here + let mut insert_vals = String::new(); + let temp = vals.iter().map(|_| "?").collect::>().join(","); + // let mut vals2 = Vec::new(); + // //debug!(self.log, "HEREtmp {}", temp); + // if table == "questions" { + // let vv = vals[0..2].to_vec(); + // //let key = vv.iter().map(|_| "?").collect::>().join("-"); + // //insert_vals += "test"; //for testing purposes //&key.to_string(); + // //insert_vals += ","; + // //insert_vals += &temp.to_string(); + // insert_vals += "1, 1, 1, 1"; + // vals2 = vec![1, 1, 1, 1]; + // } else if table == "answers" { + // let vv = vals[0..3].to_vec(); + // let key = vv.iter().map(|_| "?").collect::>().join("-"); + // insert_vals += &key; + // insert_vals += ","; + // insert_vals += &temp; + // } else { + insert_vals += &temp; + //vals2 = vals; + //} + //debug!(self.log, "HERE {}", insert_vals); let q = format!( "{} INTO {} VALUES ({})", op, table, - vals.iter().map(|_| "?").collect::>().join(",") + insert_vals + //vals.iter().map(|_| "?").collect::>().join(",") ); debug!(self.log, "executed insert query {} for row {:?}", q, vals); self.handle @@ -93,10 +120,64 @@ impl MySqlBackend { } pub fn insert(&mut self, table: &str, vals: Vec) { - self.do_insert(table, vals, false); + // if table == "questions" { + // let vals2 = vals[0..2].to_vec(); + // let vals2_unwrapped: Vec = vals2.iter().map(|x| from_value(x.clone())).collect::>(); + // let key = vals2_unwrapped.iter().map(|x| format!("{}", x)).collect::>().join("-"); + // let key_as_bytes: Vec = key.as_bytes().to_vec(); + // let mut vals_m = vals; + // let mut new_vals : Vec = Vec::new(); + // new_vals.push(mysql::Value::Bytes(key_as_bytes)); + // new_vals.append(&mut vals_m); + // self.do_insert(table, new_vals, false); + // } else if table == "answers" { + // let unwrapped1:Vec = from_value(vals[0].clone()); + // let unwrapped2:i64 = from_value(vals[1].clone()); + // let unwrapped3:i64 = from_value(vals[2].clone()); + + // let email_string: String = String::from_utf8(unwrapped1).unwrap(); + // let key = format!("{}-{}-{}", email_string, unwrapped2, unwrapped3); + // // let vals3 = vals[0..3].to_vec(); + // // let key = vals3.iter().map(|_| "?").collect::>().join("-"); + // let key_as_bytes: Vec = key.as_bytes().to_vec(); + // let mut vals_m = vals; + // let mut new_vals : Vec = Vec::new(); + // new_vals.push(mysql::Value::Bytes(key_as_bytes)); + // new_vals.append(&mut vals_m); + // self.do_insert(table, new_vals, false); + //} else { + self.do_insert(table, vals, false); + //} } pub fn replace(&mut self, table: &str, vals: Vec) { - self.do_insert(table, vals, true); + // if table == "questions" { + // let vals2 = vals[0..2].to_vec(); + // let vals2_unwrapped: Vec = vals2.iter().map(|x| from_value(x.clone())).collect::>(); + // let key = vals2_unwrapped.iter().map(|x| format!("{}", x)).collect::>().join("-"); + // let key_as_bytes: Vec = key.as_bytes().to_vec(); + // let mut vals_m = vals; + // let mut new_vals : Vec = Vec::new(); + // new_vals.push(mysql::Value::Bytes(key_as_bytes)); + // new_vals.append(&mut vals_m); + // self.do_insert(table, new_vals, true); + // } else if table == "answers" { + // let unwrapped1:Vec = from_value(vals[0].clone()); + // let unwrapped2:i64 = from_value(vals[1].clone()); + // let unwrapped3:i64 = from_value(vals[2].clone()); + + // let email_string: String = String::from_utf8(unwrapped1).unwrap(); + // let key = format!("{}-{}-{}", email_string, unwrapped2, unwrapped3); + // // let vals3 = vals[0..3].to_vec(); + // // let key = vals3.iter().map(|_| "?").collect::>().join("-"); + // let key_as_bytes: Vec = key.as_bytes().to_vec(); + // let mut vals_m = vals; + // let mut new_vals : Vec = Vec::new(); + // new_vals.push(mysql::Value::Bytes(key_as_bytes)); + // new_vals.append(&mut vals_m); + // self.do_insert(table, new_vals, true); + // } else { + self.do_insert(table, vals, true); + //} } } diff --git a/src/questions.rs b/src/questions.rs index ab18f10..2e4a9a0 100644 --- a/src/questions.rs +++ b/src/questions.rs @@ -115,7 +115,7 @@ pub(crate) fn answers( ) -> Template { let mut bg = backend.lock().unwrap(); let key: Value = (num as u64).into(); - let res = bg.prep_exec("SELECT * FROM answers WHERE lec = ?", vec![key]); + let res = bg.prep_exec("SELECT email, lec, q, answer, submitted_at FROM answers WHERE lec = ?", vec![key]); drop(bg); let answers: Vec<_> = res .into_iter() @@ -123,14 +123,9 @@ pub(crate) fn answers( id: from_value(r[2].clone()), user: from_value(r[0].clone()), answer: from_value(r[3].clone()), - time: if let Value::Time(..) = r[4] { - Some(from_value::(r[4].clone())) - } else { - None - }, + time: NaiveDateTime::parse_from_str(&String::from_utf8(from_value::>(r[4].clone())).unwrap(), "%Y-%m-%d %H:%M:%S").ok() }) .collect(); - let ctx = LectureAnswersContext { lec_id: num, answers: answers, @@ -151,7 +146,7 @@ pub(crate) fn questions( let key: Value = (num as u64).into(); let answers_res = bg.prep_exec( - "SELECT answers.* FROM answers WHERE answers.lec = ? AND answers.email = ?", + "SELECT answers.email, answers.lec, answers.q, answers.answer, answers.submitted_at FROM answers WHERE answers.lec = ? AND answers.email = ?", vec![(num as u64).into(), apikey.user.clone().into()], ); let mut answers = HashMap::new(); @@ -161,7 +156,7 @@ pub(crate) fn questions( let atext: String = from_value(r[3].clone()); answers.insert(id, atext); } - let res = bg.prep_exec("SELECT * FROM questions WHERE lec = ?", vec![key]); + let res = bg.prep_exec("SELECT lec , q , question FROM questions WHERE lec = ?", vec![key]); drop(bg); let mut qs: Vec<_> = res .into_iter() @@ -195,10 +190,11 @@ pub(crate) fn questions_submit( ) -> Redirect { let mut bg = backend.lock().unwrap(); let vnum: Value = (num as u64).into(); - let ts: Value = Local::now().naive_local().into(); + let ts: Value = Local::now().naive_local().to_string().into(); for (id, answer) in &data.answers { let rec: Vec = vec![ + format!("{}-{}-{}", apikey.user.clone(), num, (*id)).into(), apikey.user.clone().into(), vnum.clone(), (*id).into(), diff --git a/src/schema.sql b/src/schema.sql index 340ea14..6d037dd 100644 --- a/src/schema.sql +++ b/src/schema.sql @@ -1,6 +1,7 @@ -CREATE TABLE users (email varchar(255), apikey varchar(255), is_admin tinyint, PRIMARY KEY (apikey)); +SET echo; +CREATE TABLE users (PII_email varchar(255), apikey varchar(255), is_admin int, PRIMARY KEY (apikey)); CREATE TABLE lectures (id int, label varchar(255), PRIMARY KEY (id)); -CREATE TABLE questions (lec int, q int, question text, PRIMARY KEY (lec, q)); -CREATE TABLE answers (email varchar(255), lec int, q int, answer text, submitted_at datetime, PRIMARY KEY (email, lec, q)); +CREATE TABLE questions (id text, lec int, q int, question text, PRIMARY KEY (id)); +CREATE TABLE answers (id text, email varchar(255), lec int, q int, answer text, submitted_at datetime, FOREIGN KEY (email) REFERENCES users(PII_email), PRIMARY KEY (id)); -CREATE VIEW lec_qcount as SELECT questions.lec, COUNT(questions.q) AS qcount FROM questions GROUP BY questions.lec; +CREATE VIEW lec_qcount as '"SELECT questions.lec, COUNT(questions.q) AS qcount FROM questions GROUP BY questions.lec"'; From b4b86a02f2ebe85393dfdc9e50632da2260ebc8d Mon Sep 17 00:00:00 2001 From: vedantgu Date: Sat, 11 Jun 2022 10:55:23 +0530 Subject: [PATCH 2/3] cleaned up --- src/backend.rs | 83 +------------------------------------------------- 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/src/backend.rs b/src/backend.rs index d7bd6de..5cc8a6f 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -32,12 +32,6 @@ impl MySqlBackend { assert_eq!(db.ping(), true); if prime { - //note remember to fix this - //db.query_drop(format!("DROP DATABASE IF EXISTS {};", dbname)) - // .unwrap(); - //db.query_drop(format!("CREATE DATABASE {};", dbname)) - // .unwrap(); - // reconnect db = mysql::Conn::new( Opts::from_url(&format!("mysql://pelton:password@127.0.0.1:10001/{}", dbname)).unwrap(), ) @@ -85,33 +79,12 @@ impl MySqlBackend { //changes to be made here let mut insert_vals = String::new(); let temp = vals.iter().map(|_| "?").collect::>().join(","); - // let mut vals2 = Vec::new(); - // //debug!(self.log, "HEREtmp {}", temp); - // if table == "questions" { - // let vv = vals[0..2].to_vec(); - // //let key = vv.iter().map(|_| "?").collect::>().join("-"); - // //insert_vals += "test"; //for testing purposes //&key.to_string(); - // //insert_vals += ","; - // //insert_vals += &temp.to_string(); - // insert_vals += "1, 1, 1, 1"; - // vals2 = vec![1, 1, 1, 1]; - // } else if table == "answers" { - // let vv = vals[0..3].to_vec(); - // let key = vv.iter().map(|_| "?").collect::>().join("-"); - // insert_vals += &key; - // insert_vals += ","; - // insert_vals += &temp; - // } else { insert_vals += &temp; - //vals2 = vals; - //} - //debug!(self.log, "HERE {}", insert_vals); let q = format!( "{} INTO {} VALUES ({})", op, table, insert_vals - //vals.iter().map(|_| "?").collect::>().join(",") ); debug!(self.log, "executed insert query {} for row {:?}", q, vals); self.handle @@ -120,64 +93,10 @@ impl MySqlBackend { } pub fn insert(&mut self, table: &str, vals: Vec) { - // if table == "questions" { - // let vals2 = vals[0..2].to_vec(); - // let vals2_unwrapped: Vec = vals2.iter().map(|x| from_value(x.clone())).collect::>(); - // let key = vals2_unwrapped.iter().map(|x| format!("{}", x)).collect::>().join("-"); - // let key_as_bytes: Vec = key.as_bytes().to_vec(); - // let mut vals_m = vals; - // let mut new_vals : Vec = Vec::new(); - // new_vals.push(mysql::Value::Bytes(key_as_bytes)); - // new_vals.append(&mut vals_m); - // self.do_insert(table, new_vals, false); - // } else if table == "answers" { - // let unwrapped1:Vec = from_value(vals[0].clone()); - // let unwrapped2:i64 = from_value(vals[1].clone()); - // let unwrapped3:i64 = from_value(vals[2].clone()); - - // let email_string: String = String::from_utf8(unwrapped1).unwrap(); - // let key = format!("{}-{}-{}", email_string, unwrapped2, unwrapped3); - // // let vals3 = vals[0..3].to_vec(); - // // let key = vals3.iter().map(|_| "?").collect::>().join("-"); - // let key_as_bytes: Vec = key.as_bytes().to_vec(); - // let mut vals_m = vals; - // let mut new_vals : Vec = Vec::new(); - // new_vals.push(mysql::Value::Bytes(key_as_bytes)); - // new_vals.append(&mut vals_m); - // self.do_insert(table, new_vals, false); - //} else { - self.do_insert(table, vals, false); - //} + self.do_insert(table, vals, false); } pub fn replace(&mut self, table: &str, vals: Vec) { - // if table == "questions" { - // let vals2 = vals[0..2].to_vec(); - // let vals2_unwrapped: Vec = vals2.iter().map(|x| from_value(x.clone())).collect::>(); - // let key = vals2_unwrapped.iter().map(|x| format!("{}", x)).collect::>().join("-"); - // let key_as_bytes: Vec = key.as_bytes().to_vec(); - // let mut vals_m = vals; - // let mut new_vals : Vec = Vec::new(); - // new_vals.push(mysql::Value::Bytes(key_as_bytes)); - // new_vals.append(&mut vals_m); - // self.do_insert(table, new_vals, true); - // } else if table == "answers" { - // let unwrapped1:Vec = from_value(vals[0].clone()); - // let unwrapped2:i64 = from_value(vals[1].clone()); - // let unwrapped3:i64 = from_value(vals[2].clone()); - - // let email_string: String = String::from_utf8(unwrapped1).unwrap(); - // let key = format!("{}-{}-{}", email_string, unwrapped2, unwrapped3); - // // let vals3 = vals[0..3].to_vec(); - // // let key = vals3.iter().map(|_| "?").collect::>().join("-"); - // let key_as_bytes: Vec = key.as_bytes().to_vec(); - // let mut vals_m = vals; - // let mut new_vals : Vec = Vec::new(); - // new_vals.push(mysql::Value::Bytes(key_as_bytes)); - // new_vals.append(&mut vals_m); - // self.do_insert(table, new_vals, true); - // } else { self.do_insert(table, vals, true); - //} } } From 41306b50909f042898bd6de1a10ff95fa0ee6607 Mon Sep 17 00:00:00 2001 From: vedantgu Date: Thu, 16 Jun 2022 11:33:48 +0530 Subject: [PATCH 3/3] Date time issue plus other comments resolved --- .DS_Store | Bin 6148 -> 6148 bytes src/backend.rs | 8 ++------ src/questions.rs | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.DS_Store b/.DS_Store index da7185f53c25eefd427e62b4103745b35aefb852..307363da91145f53fd0fdea9a40d3afdde4ea036 100644 GIT binary patch delta 181 zcmZoMXfc=|#>B!ku~2NHo+2ar#(>?7ivyUM7}+=TFtIc8B$XEzB<18MF)%P}o2dQht68Bf3Oca8X`PeqK6Ie6uw3KgP}M9Q+(WM{Raw{?0s^U&N6E PsD%kA%dj~@WDPR_cs(p? delta 77 zcmZoMXfc=|#>B)qu~2NHo+2ab#(>?7jI5h^SlAgkQi_vvlJfI&HgmH5W8B#Aj%hPH f2R{c;@n%7e@640=MI1R8fPj&Kfn{@q$Qot, replace: bool) { let op = if replace { "REPLACE" } else { "INSERT" }; - //changes to be made here - let mut insert_vals = String::new(); - let temp = vals.iter().map(|_| "?").collect::>().join(","); - insert_vals += &temp; let q = format!( "{} INTO {} VALUES ({})", op, table, - insert_vals + vals.iter().map(|_| "?").collect::>().join(",") ); debug!(self.log, "executed insert query {} for row {:?}", q, vals); self.handle @@ -97,6 +93,6 @@ impl MySqlBackend { } pub fn replace(&mut self, table: &str, vals: Vec) { - self.do_insert(table, vals, true); + self.do_insert(table, vals, true); } } diff --git a/src/questions.rs b/src/questions.rs index 2e4a9a0..fad847d 100644 --- a/src/questions.rs +++ b/src/questions.rs @@ -123,7 +123,7 @@ pub(crate) fn answers( id: from_value(r[2].clone()), user: from_value(r[0].clone()), answer: from_value(r[3].clone()), - time: NaiveDateTime::parse_from_str(&String::from_utf8(from_value::>(r[4].clone())).unwrap(), "%Y-%m-%d %H:%M:%S").ok() + time: NaiveDateTime::parse_from_str(&String::from_utf8(from_value::>(r[4].clone())).unwrap().chars().collect::>()[..19].iter().collect::(), "%Y-%m-%d %H:%M:%S").ok() }) .collect(); let ctx = LectureAnswersContext {