Commit 53d1f710 authored by Robert Czechowski's avatar Robert Czechowski

Admin page: Contest export: Stub for export into file

parent 83f9a8a1
Pipeline #688 failed with stage
in 4 minutes and 1 second
......@@ -170,6 +170,17 @@ dependencies = [
"serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bstr"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "buf_redux"
version = "0.6.3"
......@@ -351,6 +362,26 @@ dependencies = [
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "csv"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "digest"
version = "0.7.6"
......@@ -895,6 +926,7 @@ name = "medal"
version = "1.3.0"
dependencies = [
"bcrypt 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"handlebars-iron 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"iron-sessionstorage 0.7.0",
......@@ -1650,6 +1682,14 @@ dependencies = [
"regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-automata"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.5.6"
......@@ -2533,6 +2573,7 @@ dependencies = [
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
"checksum bodyparser 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6928e817538b74a73d1dd6e9a942a2a35c632a597b6bb14fd009480f859a6bf5"
"checksum bodyparser 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afa8a0260bb79363b68e8bfbc6e2a2d1be61f5a086aab8d9fe7d0a304a34f6a9"
"checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
"checksum buf_redux 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9279646319ff816b05fb5897883ece50d7d854d12b59992683d4f8a71b0f949"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
......@@ -2554,6 +2595,8 @@ dependencies = [
"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
"checksum crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958"
"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279"
"checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
......@@ -2693,6 +2736,7 @@ dependencies = [
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
......
......@@ -38,6 +38,7 @@ structopt = "0.2.18"
reqwest = "0.9.19"
linked-hash-map = "0.5.1"
bcrypt = "0.3"
csv = "1.1"
[dependencies.serde_json]
version = "1.0.20"
......
......@@ -1287,7 +1287,7 @@ pub fn admin_contest_export<T: MedalConnection>(conn: &T, contest_id: i32, sessi
let contest = conn.get_contest_by_id_complete(contest_id);
let taskgroup_ids : Vec<i32> = contest.taskgroups.iter().map(|tg| tg.id.unwrap()).collect();
let taskgroup_ids : Vec<(i32, String)> = contest.taskgroups.into_iter().map(|tg| (tg.id.unwrap(),tg.name)).collect();
let filename = "./export/blub.csv";
let contest = conn.export_contest_results_to_file(contest_id, &taskgroup_ids, filename);
......
......@@ -796,13 +796,93 @@ impl MedalConnection for Connection {
.unwrap_or_default()
}
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups_ids: &[i32], filename: &str) {
let query = "COPY (
SELECT * from contest
)
TO '/tmp/output.csv'
WITH CSV DELIMITER ',' HEADER;";
self.execute(query, &[]).unwrap();
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups: &[(i32, String)], filename: &str) {
use std::fs::OpenOptions;
let file = OpenOptions::new().write(true).create(true).truncate(true).open("foo.txt").unwrap();
let mut headers = vec![
"id",
"username",
"logincode",
"oauth_foreign_id",
"oauth_provider",
"firstname",
"lastname",
"grade",
"sex",
"is_teacher",
"group_id",
"group_name",
"group_tag",
"teacher_id",
"teacher_firstname",
"teacher_lastname",
"teacher_oauth_foreign_id",
"teacher_oauth_provider",
"contest_id",
"start_date"];
let mut select_part = String::new();
let mut join_part = String::new();
let mut join_params = Vec::<&dyn rusqlite::types::ToSql>::new();
join_params.push(&contest_id);
for (n,(id, name)) in taskgroups.iter().enumerate() {
select_part.push_str(&format!(",\n g{}.grade ", n));
join_part.push_str(&format!("\n LEFT JOIN grade AS g{} ON session.id = g{}.session AND g{}.taskgroup = ${} ", n, n, n, n + 2));
join_params.push(id);
headers.push(&name);
}
let query = format!("SELECT session.id,
session.username,
session.logincode,
session.oauth_foreign_id,
session.oauth_provider,
session.firstname,
session.lastname,
session.grade,
session.sex,
session.is_teacher,
session.managed_by,
usergroup.name,
usergroup.tag,
teacher.id,
teacher.firstname,
teacher.lastname,
teacher.oauth_foreign_id,
teacher.oauth_provider,
participation.contest,
participation.start_date
{}
FROM participation
JOIN session ON participation.session = session.id
{}
LEFT JOIN usergroup ON session.managed_by = usergroup.id
LEFT JOIN session AS teacher ON usergroup.admin = teacher.id
WHERE participation.contest = $1", select_part, join_part);
use csv::Writer;
let mut wtr = Writer::from_writer(file);
wtr.serialize(&headers).unwrap();
wtr.flush().unwrap();
let file = wtr.into_inner().unwrap();
let mut wtr = Writer::from_writer(file);
self.query_map_many(&query, join_params.as_slice(),
|row| {
wtr.serialize(
(
row.get::<_, i32>(0),
row.get::<_, Option<String>>(1),
row.get::<_, Option<String>>(2),
)
).unwrap();
()
}
);
wtr.flush().unwrap();
}
fn get_contest_list(&self) -> Vec<Contest> {
......
......@@ -47,7 +47,7 @@ pub trait MedalConnection {
-> (Vec<String>, Vec<(Group, Vec<(UserInfo, Vec<Grade>)>)>);
fn get_taskgroup_user_grade(&self, session: &str, taskgroup_id: i32) -> Grade;
fn get_contest_user_grades(&self, session: &str, contest_id: i32) -> Vec<Grade>;
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups_ids: &[i32], filename: &str);
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups_ids: &[(i32, String)], filename: &str);
fn get_contest_list(&self) -> Vec<Contest>;
fn get_contest_by_id(&self, contest_id: i32) -> Contest;
......
......@@ -906,13 +906,93 @@ impl MedalConnection for Connection {
.unwrap_or_default()
}
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups_ids: &[i32], filename: &str) {
let query = "COPY (
SELECT * from contest
)
TO '/tmp/output.csv'
WITH CSV DELIMITER ',' HEADER;";
self.execute(query, &[]).unwrap();
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups: &[(i32, String)], filename: &str) {
use std::fs::OpenOptions;
let file = OpenOptions::new().write(true).create(true).truncate(true).open("foo.txt").unwrap();
let mut headers = vec![
"id",
"username",
"logincode",
"oauth_foreign_id",
"oauth_provider",
"firstname",
"lastname",
"grade",
"sex",
"is_teacher",
"group_id",
"group_name",
"group_tag",
"teacher_id",
"teacher_firstname",
"teacher_lastname",
"teacher_oauth_foreign_id",
"teacher_oauth_provider",
"contest_id",
"start_date"];
let mut select_part = String::new();
let mut join_part = String::new();
let mut join_params = Vec::<&dyn rusqlite::types::ToSql>::new();
join_params.push(&contest_id);
for (n,(id, name)) in taskgroups.iter().enumerate() {
select_part.push_str(&format!(",\n g{}.grade ", n));
join_part.push_str(&format!("\n LEFT JOIN grade AS g{} ON session.id = g{}.session AND g{}.taskgroup = ${} ", n, n, n, n + 2));
join_params.push(id);
headers.push(&name);
}
let query = format!("SELECT session.id,
session.username,
session.logincode,
session.oauth_foreign_id,
session.oauth_provider,
session.firstname,
session.lastname,
session.grade,
session.sex,
session.is_teacher,
session.managed_by,
usergroup.name,
usergroup.tag,
teacher.id,
teacher.firstname,
teacher.lastname,
teacher.oauth_foreign_id,
teacher.oauth_provider,
participation.contest,
participation.start_date
{}
FROM participation
JOIN session ON participation.session = session.id
{}
LEFT JOIN usergroup ON session.managed_by = usergroup.id
LEFT JOIN session AS teacher ON usergroup.admin = teacher.id
WHERE participation.contest = $1", select_part, join_part);
use csv::Writer;
let mut wtr = Writer::from_writer(file);
wtr.serialize(&headers).unwrap();
wtr.flush().unwrap();
let file = wtr.into_inner().unwrap();
let mut wtr = Writer::from_writer(file);
self.query_map_many(&query, join_params.as_slice(),
|row| {
wtr.serialize(
(
row.get::<_, i32>(0),
row.get::<_, Option<String>>(1),
row.get::<_, Option<String>>(2),
)
).unwrap();
()
}
);
wtr.flush().unwrap();
}
fn get_contest_list(&self) -> Vec<Contest> {
......
......@@ -906,13 +906,93 @@ impl MedalConnection for Connection {
.unwrap_or_default()
}
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups_ids: &[i32], filename: &str) {
let query = "COPY (
SELECT * from contest
)
TO '/tmp/output.csv'
WITH CSV DELIMITER ',' HEADER;";
self.execute(query, &[]).unwrap();
fn export_contest_results_to_file(&self, contest_id: i32, taskgroups: &[(i32, String)], filename: &str) {
use std::fs::OpenOptions;
let file = OpenOptions::new().write(true).create(true).truncate(true).open("foo.txt").unwrap();
let mut headers = vec![
"id",
"username",
"logincode",
"oauth_foreign_id",
"oauth_provider",
"firstname",
"lastname",
"grade",
"sex",
"is_teacher",
"group_id",
"group_name",
"group_tag",
"teacher_id",
"teacher_firstname",
"teacher_lastname",
"teacher_oauth_foreign_id",
"teacher_oauth_provider",
"contest_id",
"start_date"];
let mut select_part = String::new();
let mut join_part = String::new();
let mut join_params = Vec::<&dyn rusqlite::types::ToSql>::new();
join_params.push(&contest_id);
for (n,(id, name)) in taskgroups.iter().enumerate() {
select_part.push_str(&format!(",\n g{}.grade ", n));
join_part.push_str(&format!("\n LEFT JOIN grade AS g{} ON session.id = g{}.session AND g{}.taskgroup = ?{} ", n, n, n, n + 2));
join_params.push(id);
headers.push(&name);
}
let query = format!("SELECT session.id,
session.username,
session.logincode,
session.oauth_foreign_id,
session.oauth_provider,
session.firstname,
session.lastname,
session.grade,
session.sex,
session.is_teacher,
session.managed_by,
usergroup.name,
usergroup.tag,
teacher.id,
teacher.firstname,
teacher.lastname,
teacher.oauth_foreign_id,
teacher.oauth_provider,
participation.contest,
participation.start_date
{}
FROM participation
JOIN session ON participation.session = session.id
{}
LEFT JOIN usergroup ON session.managed_by = usergroup.id
LEFT JOIN session AS teacher ON usergroup.admin = teacher.id
WHERE participation.contest = ?1", select_part, join_part);
use csv::Writer;
let mut wtr = Writer::from_writer(file);
wtr.serialize(&headers).unwrap();
wtr.flush().unwrap();
let file = wtr.into_inner().unwrap();
let mut wtr = Writer::from_writer(file);
self.query_map_many(&query, join_params.as_slice(),
|row| {
wtr.serialize(
(
row.get::<_, i32>(0),
row.get::<_, Option<String>>(1),
row.get::<_, Option<String>>(2),
)
).unwrap();
()
}
);
wtr.flush().unwrap();
}
fn get_contest_list(&self) -> Vec<Contest> {
......
......@@ -34,6 +34,7 @@ extern crate staticfile;
extern crate structopt;
extern crate time;
extern crate urlencoded;
extern crate csv;
#[cfg(feature = "postgres")]
extern crate postgres;
......
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