Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
```
Expand Down
2 changes: 1 addition & 1 deletion sample-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 4 additions & 3 deletions src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub(crate) fn lec_add_submit(
pub(crate) fn lec(_adm: Admin, num: u8, backend: &State<Arc<Mutex<MySqlBackend>>>) -> 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 = ?",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this change necessary? Does Pelton not handle * correctly?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing to do with pelton. This is because I added the extra primary key column to questions, and we dont want to be selecting that.

vec![(num as u64).into()],
);
drop(bg);
Expand Down Expand Up @@ -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(),
Expand All @@ -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);
Expand Down Expand Up @@ -194,7 +195,7 @@ pub(crate) fn get_registered_users(
config: &State<Config>,
) -> 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
Expand Down
10 changes: 3 additions & 7 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -25,19 +26,14 @@ 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();
// 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() {
Expand Down
16 changes: 6 additions & 10 deletions src/questions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,17 @@ 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()
.map(|r| LectureAnswer {
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::<NaiveDateTime>(r[4].clone()))
} else {
None
},
time: NaiveDateTime::parse_from_str(&String::from_utf8(from_value::<Vec<u8>>(r[4].clone())).unwrap().chars().collect::<Vec<char>>()[..19].iter().collect::<String>(), "%Y-%m-%d %H:%M:%S").ok()
})
.collect();

let ctx = LectureAnswersContext {
lec_id: num,
answers: answers,
Expand All @@ -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();
Expand All @@ -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()
Expand Down Expand Up @@ -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<Value> = vec![
format!("{}-{}-{}", apikey.user.clone(), num, (*id)).into(),
apikey.user.clone().into(),
vnum.clone(),
(*id).into(),
Expand Down
9 changes: 5 additions & 4 deletions src/schema.sql
Original file line number Diff line number Diff line change
@@ -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"';