Commit 3c8fb5be authored by Robert Czechowski's avatar Robert Czechowski
Browse files

Add db query to get contest results for own groups

parent 1601500e
......@@ -24,6 +24,7 @@ pub trait MedalConnection {
fn load_submission(&self, session: &SessionUser, task: u32, subtask: Option<String>) -> Option<Submission>;
fn submit_submission(&self, submission: Submission);
fn get_contest_groups_grades(&self, session_id: u32, contest_id: u32) -> (Vec<String>, Vec<(Group, Vec<(UserInfo, Vec<Grade>)>)>);
fn get_contest_list(&self) -> Vec<Contest>;
fn get_contest_by_id(&self, contest_id: u32) -> Contest;
......
......@@ -250,6 +250,88 @@ impl MedalConnection for Connection {
fn submit_submission(&self, mut submission: Submission) {
submission.save(self);
}
fn get_contest_groups_grades(&self, session_id: u32, contest_id: u32) -> (Vec<String>, Vec<(Group, Vec<(UserInfo, Vec<Grade>)>)>) {
let mut stmt = self.prepare("SELECT id, name FROM taskgroup WHERE contest = ?1 ORDER BY id ASC").unwrap();
let mut tasknames_iter = stmt.query_map(&[&contest_id], |row| {
let x : (u32, String) = (row.get(0), row.get(1));
x
}).unwrap();
let tasknames : Vec<(u32, String)> = tasknames_iter.map(|x| x.unwrap()).collect();
let mut taskindex: ::std::collections::BTreeMap<u32, usize> = ::std::collections::BTreeMap::new();
let n_tasks = tasknames.len();
let mut index = 0;
for (i, _) in &tasknames {
taskindex.insert(*i, index);
index = index + 1
}
let mut stmt = self.prepare("SELECT grade.taskgroup, grade.user, grade.grade, grade.validated, group.id, group.name, group.groupcode, group.tag, student.id, student.username, student.firstname, student.lastname
FROM grade
JOIN taskgroup ON grade.taskgroup = taskgroup.id
JOIN session_user AS student ON grade.user = student.id
JOIN group ON student.managed_by = group.id
WHERE group.admin = ?1 AND taskgroup.contest = ?2
ORDER BY group.id, student.id, taskgroup.id ASC").unwrap();
let mut gradeinfo_iter = stmt.query_map(&[&session_id, &contest_id], |row| {
(Grade {
taskgroup: row.get(0),
user: row.get(1),
grade: row.get(2),
validated: row.get(3),
},Group {
id: Some(row.get(4)),
name: row.get(5),
groupcode: row.get(6),
tag: row.get(7),
admin: session_id,
members: Vec::new()
},UserInfo {
id: row.get(8),
username: row.get(9),
logincode: row.get(10),
firstname: row.get(11),
lastname: row.get(12),
})
}).unwrap();
let (grade, mut group, mut userinfo) = gradeinfo_iter.next().unwrap().unwrap();
let mut grades: Vec<Grade> = vec![Default::default(); n_tasks];
let mut users: Vec<(UserInfo, Vec<Grade>)> = Vec::new();
let mut groups: Vec<(Group, Vec<(UserInfo, Vec<Grade>)>)> = Vec::new();
let index = grade.taskgroup;
grades[taskindex[&index]] = grade;
// TODO: does
// https://stackoverflow.com/questions/29859892/mutating-an-item-inside-of-nested-loops
// help to spare all these clones?
for ggu in gradeinfo_iter {
if let Ok((g, gr, ui)) = ggu {
if gr.id != group.id {
users.push((userinfo.clone(), grades));
grades = vec![Default::default(); n_tasks];
groups.push((group.clone(), users));
users = Vec::new();
}
else if ui.id != userinfo.id {
users.push((userinfo.clone(), grades));
grades = vec![Default::default(); n_tasks];
}
let index = g.taskgroup;
grades[taskindex[&index]] = g;
}
}
users.push((userinfo, grades));
groups.push((group, users));
(tasknames.iter().map(|(_, name)| name.clone()).collect(), groups)
}
fn get_contest_list(&self) -> Vec<Contest> {
let mut stmt = self.prepare("SELECT id, location, filename, name, duration, public, start_date, end_date FROM contest").unwrap();
......
......@@ -3,6 +3,7 @@ extern crate time;
use self::time::{Timespec, Duration};
#[derive(Clone)]
pub struct SessionUser {
pub id: u32,
pub session_token: Option<String>, // delete this to log out
......@@ -33,6 +34,17 @@ pub struct SessionUser {
pub pms_school_id: Option<u32>,
}
// Short version for display
#[derive(Clone, Default)]
pub struct UserInfo {
pub id: u32,
pub username: Option<String>,
pub logincode: Option<String>,
pub firstname: Option<String>,
pub lastname: Option<String>,
}
#[derive(Clone)]
pub struct Group {
pub id: Option<u32>,
pub name: String,
......@@ -83,6 +95,7 @@ pub struct Submission {
pub date: Timespec,
}
#[derive(Clone, Copy, Default)]
pub struct Grade {
pub taskgroup: u32,
pub user: u32,
......
......@@ -126,6 +126,14 @@ pub fn show_contest<T: MedalConnection>(conn: &T, contest_id: u32, session_token
let mut data = json_val::Map::new();
data.insert("contest".to_string(), to_json(&ci));
if let Some(session) = conn.get_session(session_token.clone()) { // TODO: Work with string slices here
data.insert("logged_in".to_string(), to_json(&true));
data.insert("username".to_string(), to_json(&session.username));
data.insert("firstname".to_string(), to_json(&session.firstname));
data.insert("lastname".to_string(), to_json(&session.lastname));
data.insert("teacher".to_string(), to_json(&session.is_teacher));
}
match conn.get_participation(session_token, contest_id) {
None => {
Ok(("contest".to_owned(), data))
......@@ -366,7 +374,16 @@ pub fn add_group<T: MedalConnection>(conn: &T, session_token: String, csrf_token
Ok(group.id.unwrap())
}
pub fn show_groups_results<T: MedalConnection>(conn: &T, contest_id: u32, session_token: String) -> MedalValueResult {
let session = conn.get_session_or_new(session_token).ensure_logged_in().ok_or(MedalError::NotLoggedIn)?;
let g = conn.get_contest_groups_grades(session.id, contest_id);
let mut data = json_val::Map::new();
Ok(("groupresults".into(), data))
}
pub fn show_profile<T: MedalConnection>(conn: &T, session_token: String) -> MedalValueResult {
let session = conn.get_session_or_new(session_token).ensure_alive().ok_or(MedalError::AccessDenied)?; // TODO SessionTimeout
......
......@@ -778,6 +778,7 @@ pub fn start_server(conn: Connection, config: ::Config) {
greet: get "/" => greet_personal,
contests: get "/contest/" => contests,
contest: get "/contest/:contestid" => contest,
contestresults: get "/contest/:contestid/results" => contest,
contest_post: post "/contest/:contestid" => contest_post,
login: get "/login" => login,
login_post: post "/login" => login_post,
......
......@@ -40,6 +40,6 @@ Der Wettbewerb kann nach dem starten nicht mehr pausiert werden.
{{/if}}
{{#if is_teacher}}
<a href="/contestresults/{{ contest.id }}">Ergebnisse meiner Gruppen anzeigen.</a>
{{#if teacher}}
<a href="/contest/{{ contest.id }}/results">Ergebnisse meiner Gruppen anzeigen.</a>
{{/if}}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment