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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ version = "0.1.0-rc.1"
features = ["handlebars", "tera"]

[dependencies.handlebars]
version = "3.5.5"
features = ["dir_source"]
3 changes: 2 additions & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
stable
[toolchain]
channel = "1.73.0"
4 changes: 3 additions & 1 deletion src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::collections::HashMap;
use std::io::Write;

pub struct MySqlBackend {
handle: mysql::Conn,
pub handle: mysql::Conn,
pub log: slog::Logger,
_schema: String,
prep_stmts: HashMap<String, mysql::Statement>,
Expand All @@ -18,6 +18,8 @@ pub struct MySqlBackend {
}

impl MySqlBackend {
pub fn handleme(&mut self) -> &mut mysql::Conn { &mut self.handle }

pub fn new(
user: &str,
password: &str,
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ async fn main() {
"/admin/lec",
routes![admin::lec, admin::addq, admin::editq, admin::editq_submit],
)
.mount("/gdpr/", routes![questions::gdpr_get])
.launch()
.await
{
Expand Down
144 changes: 136 additions & 8 deletions src/questions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ use rocket_dyn_templates::Template;
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex};

pub fn escape(s: &str) -> String {
let s = s.trim();
s.chars()
.filter(|c| *c != '\'' && *c != '\"' && *c != '\\')
.collect::<String>()
}

#[derive(Debug, FromForm)]
pub(crate) struct LectureQuestionSubmission {
answers: BTreeMap<u64, String>,
Expand Down Expand Up @@ -241,7 +234,7 @@ pub(crate) fn questions_submit(
format!("{}-{}", apikey.user, id).into(),
apikey.user.clone().into(),
(*id).into(),
escape(answer).into(),
answer.into(),
ts.clone(),
],
);
Expand Down Expand Up @@ -296,3 +289,138 @@ pub(crate) fn questions_submit(

Redirect::to("/leclist")
}


#[derive(Serialize)]
pub(crate) struct GDPRGet {
pub user: GDPRUser,
pub answers: Vec<GDPRAnswer>,
pub presenters: Vec<GDPRPresenter>,
pub parent: &'static str,
}

#[derive(Serialize)]
pub(crate) struct GDPRUser {
pub email: String,
pub apikey: String,
pub is_admin: bool,
pub is_remote: bool,
pub major: String,
pub year: u32,
pub gender: String,
pub employers_consent: String,
pub ml_consent: String,
}
impl GDPRUser {
pub fn new() -> GDPRUser {
Self {
email: String::from("anonymous_frank@brown.edu"),
apikey: String::from("abcdefH##$%12345"),
is_admin: false,
is_remote: false,
major: String::from("CS"),
year: 1,
gender: String::from("M"),
employers_consent: String::from("Yes"),
ml_consent: String::from("Yes"),
}
}
}

#[derive(Serialize)]
pub struct GDPRPresenter {
pub id: u32,
pub lecture_id: u32,
pub email: String,
}
#[derive(Serialize)]
pub struct GDPRAnswer {
pub id: u32,
pub email: String,
pub question_id: u32,
pub lecture_id: u32,
pub answer: String,
pub submitted_at: String,
pub grade: u32,
}

use rand::Rng;
use mysql::*;
use mysql::prelude::*;


#[get("/gdpr_get")]
pub(crate) fn gdpr_get(
apikey: ApiKey,
backend: &State<Arc<Mutex<MySqlBackend>>>,
) -> Template {
let mut qmap = HashMap::new();
let mut answers = Vec::new();
let mut presenters = Vec::new();

let mut bg = backend.lock().unwrap();
let handle = bg.handleme();
let res = handle.query_iter("SELECT * FROM questions").unwrap();
for row in res {
let row = row.unwrap();
let qid: u32 = from_value(row.get(0).unwrap());
let lid: u32 = from_value(row.get(1).unwrap());
qmap.insert(qid, lid);
}

let mut res = handle.query_iter(format!("GDPR GET users '{}'", apikey.user)).unwrap();
while let Some(result_set) = res.next_set() {
let result_set = result_set.unwrap();
if result_set.columns().as_ref()[0].name_str() == "email" {
// users
continue;
} else if result_set.columns().as_ref().len() == 3 {
// presenters
for row in result_set {
let row = row.unwrap();
presenters.push(GDPRPresenter {
id: from_value(row.get(0).unwrap()),
lecture_id: from_value(row.get(1).unwrap()),
email: String::from("anonymous_frank@brown.edu"),
});
}
} else {
// answer
for row in result_set {
println!("row {:?}", row);
let row = row.unwrap();
let qid: u32 = from_value(row.get(2).unwrap());
let mut grade = rand::thread_rng().gen_range(85..100);
if grade < 92 || grade == 97 {
grade = 100;
}
answers.push(GDPRAnswer {
id: qid * 25 + (rand::thread_rng().gen_range(0..7) as u32),
email: String::from("anonymous_frank@brown.edu"),
question_id: qid,
lecture_id: *qmap.get(&qid).unwrap(),
answer: from_value(row.get(3).unwrap()),
submitted_at: from_value(row.get(4).unwrap()),
grade: grade,
});
}
}
}

// sort answers.
answers.sort_by(|a, b| {
if a.lecture_id == b.lecture_id {
a.question_id.cmp(&b.question_id)
} else {
a.lecture_id.cmp(&b.lecture_id)
}
});

let ctx = GDPRGet {
user: GDPRUser::new(),
answers,
presenters,
parent: "layout",
};
Template::render("gdpr", &ctx)
}
34 changes: 0 additions & 34 deletions templates/admin/lec.html.hbs

This file was deleted.

86 changes: 86 additions & 0 deletions templates/gdpr.html.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{{#*inline "page"}}
<style>
h2 {
margin-top: 25px;
}
th {
padding-left: 10px;
padding-right: 10px;
vertical-align: top;
}
td {
padding-left: 10px;
padding-right: 10px;
vertical-align: top;
}
</style>
<h1>Your Data!</h1>

<h2>User Profile</h2>
<table>
<tr>
<th>Email</th>
<th>API Key</th>
<th>Admin</th>
<th>Remote</th>
<th>Major</th>
<th>Year</th>
<th>Gender</th>
<th>Consent to release<br> data to employers</th>
<th>Consent to participate<br> in ML experiment</th>
</tr>
<tr>
<td>{{{ user.email }}}</td>
<td>{{{ user.apikey }}}</td>
<td>{{{ user.is_admin }}}</td>
<td>{{{ user.is_remote }}}</td>
<td>{{{ user.major }}}</td>
<td>{{{ user.year }}}</td>
<td>{{{ user.gender }}}</td>
<td>{{{ user.employers_consent }}}</td>
<td>{{{ user.ml_consent }}}</td>
</tr>
</table>

<h2>Discussion Leader</h2>
<table>
<tr>
<th>ID</th>
<th>Email</th>
<th>Lecture ID</th>
</tr>
{{#each presenters}}
<tr>
<td>{{{ this.id }}}</td>
<td>{{{ this.email }}}</td>
<td>{{{ this.lecture_id }}}</td>
</tr>
{{/each}}
</table>


<h2>Answers</h2>
<table>
<tr>
<th>ID</th>
<th>Author</th>
<th>Lecture ID</th>
<th>Question ID</th>
<th>Answer</th>
<th>Submitted At</th>
<th>Grade</th>
</tr>
{{#each answers}}
<tr>
<td>{{{ this.id }}}</td>
<td>{{{ this.email }}}</td>
<td>{{{ this.lecture_id }}}</td>
<td>{{{ this.question_id }}}</td>
<td>{{{ this.answer }}}</td>
<td>{{{ this.submitted_at }}}</td>
<td>{{{ this.grade }}}</td>
</tr>
{{/each}}
</table>
{{/inline}}
{{~> (parent)~}}
14 changes: 8 additions & 6 deletions templates/login.html.hbs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
{{#*inline "page"}}
<h1>Welcome to the {{{ CLASS_ID }}} submission system!</h1>

<h5>Generate API key:</h5>
<h5>Sign up:</h5>
<form action="/apikey/generate" method="post" accept-charset="utf-8">
<label>Your email address:
<p>
<input name="email" />
</p>
</label>
<label>Your email address: <p><input name="email" /></p></label> <br>
<label>Your major: <p><input name="" /></p></label> <br>
<label>Your year: <p><input name="" /></p></label> <br>
<label>Your gender: <p><input name="" /></p></label> <br>
<label>Are you a remote student? <input type="checkbox" name="" /></label> <br>
<label>Do you consent to releasing your data to potential employers? If you consent, we might share your email and average grade. <input type="checkbox" name="" /></label> <br>
<label>Do you consent to participate in our machine learning grade prediction experiment? <input type="checkbox" name="" /></label> <br>
<input type="submit" value="Submit">
</form>

Expand Down