Commit a0a01807 authored by Robert Czechowski's avatar Robert Czechowski
Browse files

Merge branch 'min-max-grade'

parents 2b3938e2 efa4ad6d
Pipeline #385 canceled with stages
ALTER TABLE contest ADD COLUMN min_grade INTEGER;
ALTER TABLE contest ADD COLUMN max_grade INTEGER;
ALTER TABLE contest ADD COLUMN min_grade INTEGER;
ALTER TABLE contest ADD COLUMN max_grade INTEGER;
ALTER TABLE contest ADD COLUMN min_grade INTEGER;
ALTER TABLE contest ADD COLUMN max_grade INTEGER;
......@@ -12,6 +12,9 @@ struct ContestYaml {
duration_minutes: Option<i32>,
public_listing: Option<bool>,
min_grade: Option<i32>,
max_grade: Option<i32>,
tasks: Option<serde_yaml::Mapping>,
}
......@@ -35,7 +38,9 @@ pub fn parse_yaml(content: &str, filename: &str, directory: &str) -> Option<Cont
config.participation_end
.map(|x| {
strptime(&x, &"%FT%T%z").map(|t| t.to_timespec()).unwrap_or_else(|_| Timespec::new(0, 0))
}));
}),
config.min_grade,
config.max_grade);
// TODO: Timeparsing should fail more pleasantly (-> Panic, thus shows message)
for (positionalnumber, (name, info)) in config.tasks?.into_iter().enumerate() {
......
......@@ -246,6 +246,18 @@ pub fn show_contest<T: MedalConnection>(conn: &T, contest_id: i32, session_token
data.insert("can_start".to_string(), to_json(&false));
}
}
let student_grade = session.grade % 100 - if session.grade / 100 == 1 { 1 } else { 0 };
if c.min_grade.map(|ming| student_grade < ming).unwrap_or(false) {
data.insert("can_start".to_string(), to_json(&false));
data.insert("grade_too_low".to_string(), to_json(&true));
}
if c.max_grade.map(|maxg| student_grade > maxg).unwrap_or(false) {
data.insert("can_start".to_string(), to_json(&false));
data.insert("grade_too_high".to_string(), to_json(&true));
}
}
if let Some(start_date) = c.start {
......@@ -260,7 +272,7 @@ pub fn show_contest<T: MedalConnection>(conn: &T, contest_id: i32, session_token
}
// This only checks if a query string is existent, so any query string will
// lead to the assumption that a base page is requested. This is usefull to
// lead to the assumption that a bare page is requested. This is useful to
// disable caching (via random token) but should be changed if query string
// can obtain more than only this meaning in the future
if query_string.is_none() {
......@@ -392,6 +404,8 @@ pub fn start_contest<T: MedalConnection>(conn: &T, contest_id: i32, session_toke
}
}
// TODO: Check participant is in correct age group (not super important)
// Check logged in or open contest
if c.duration != 0 && !session.is_logged_in() {
return Err(MedalError::AccessDenied);
......
......@@ -614,7 +614,7 @@ impl MedalConnection for Connection {
}
fn get_contest_list(&self) -> Vec<Contest> {
let query = "SELECT id, location, filename, name, duration, public, start_date, end_date
let query = "SELECT id, location, filename, name, duration, public, start_date, end_date, min_grade, max_grade
FROM contest
ORDER BY id";
self.query_map_many(query, &[], |row| Contest { id: Some(row.get(0)),
......@@ -625,12 +625,14 @@ impl MedalConnection for Connection {
public: row.get(5),
start: row.get(6),
end: row.get(7),
min_grade: row.get(8),
max_grade: row.get(9),
taskgroups: Vec::new() })
.unwrap()
}
fn get_contest_by_id(&self, contest_id: i32) -> Contest {
let query = "SELECT location, filename, name, duration, public, start_date, end_date
let query = "SELECT location, filename, name, duration, public, start_date, end_date, min_grade, max_grade
FROM contest
WHERE id = $1";
self.query_map_one(query, &[&contest_id], |row| Contest { id: Some(contest_id),
......@@ -641,6 +643,8 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() })
.unwrap()
.unwrap() // TODO: Should return Option?
......@@ -648,8 +652,8 @@ impl MedalConnection for Connection {
fn get_contest_by_id_complete(&self, contest_id: i32) -> Contest {
let query = "SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public,
contest.start_date, contest.end_date, taskgroup.id, taskgroup.name, task.id, task.location,
task.stars
contest.start_date, contest.end_date, contest.min_grade, contest.max_grade, taskgroup.id,
taskgroup.name, task.id, task.location, task.stars
FROM contest
JOIN taskgroup ON contest.id = taskgroup.contest
JOIN task ON taskgroup.id = task.taskgroup
......@@ -665,13 +669,15 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() },
Taskgroup { id: Some(row.get(7)),
Taskgroup { id: Some(row.get(9)),
contest: contest_id,
name: row.get(8),
name: row.get(10),
positionalnumber: None,
tasks: Vec::new() },
Task { id: Some(row.get(9)), taskgroup: row.get(7), location: row.get(10), stars: row.get(11) })
Task { id: Some(row.get(11)), taskgroup: row.get(9), location: row.get(11), stars: row.get(13) })
})
.unwrap();
let mut taskgroupcontest_iter = taskgroupcontest.into_iter();
......@@ -692,7 +698,8 @@ impl MedalConnection for Connection {
fn get_contest_by_id_partial(&self, contest_id: i32) -> Contest {
let query = "SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public,
contest.start_date, contest.end_date, taskgroup.id, taskgroup.name
contest.start_date, contest.end_date, contest.min_grade, contest.max_grade, taskgroup.id,
taskgroup.name
FROM contest
JOIN taskgroup ON contest.id = taskgroup.contest
WHERE contest.id = $1";
......@@ -705,10 +712,12 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() },
Taskgroup { id: Some(row.get(7)),
Taskgroup { id: Some(row.get(9)),
contest: contest_id,
name: row.get(8),
name: row.get(10),
positionalnumber: None,
tasks: Vec::new() })
})
......@@ -770,7 +779,7 @@ impl MedalConnection for Connection {
fn get_task_by_id_complete(&self, task_id: i32) -> (Task, Taskgroup, Contest) {
let query = "SELECT task.location, task.stars, taskgroup.id, taskgroup.name, contest.id, contest.location,
contest.filename, contest.name, contest.duration, contest.public, contest.start_date,
contest.end_date
contest.end_date, contest.min_grade, contest.max_grade
FROM contest
JOIN taskgroup ON taskgroup.contest = contest.id
JOIN task ON task.taskgroup = taskgroup.id
......@@ -790,6 +799,8 @@ impl MedalConnection for Connection {
public: row.get(9),
start: row.get(10),
end: row.get(11),
min_grade: row.get(12),
max_grade: row.get(13),
taskgroups: Vec::new() })
})
.unwrap()
......@@ -1000,8 +1011,9 @@ impl MedalObject<Connection> for Contest {
let id = match self.get_id() {
Some(id) => {
let query = "UPDATE contest
SET location = $1,filename = $2, name = $3, duration = $4, public = $5, start_date = $6, end_date = $7
WHERE id = $8";
SET location = $1,filename = $2, name = $3, duration = $4, public = $5, start_date = $6,
end_date = $7, min_grade =$8 , max_grade = $9
WHERE id = $10";
conn.execute(query,
&[&self.location,
&self.filename,
......@@ -1010,13 +1022,16 @@ impl MedalObject<Connection> for Contest {
&self.public,
&self.start,
&self.end,
&self.min_grade,
&self.max_grade,
&id])
.unwrap();
id
}
None => {
let query = "INSERT INTO contest (location, filename, name, duration, public, start_date, end_date)
VALUES ($1, $2, $3, $4, $5, $6, $7)";
let query = "INSERT INTO contest (location, filename, name, duration, public, start_date, end_date,
min_grade, max_grade)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)";
conn.execute(query,
&[&self.location,
&self.filename,
......@@ -1024,7 +1039,9 @@ impl MedalObject<Connection> for Contest {
&self.duration,
&self.public,
&self.start,
&self.end])
&self.end,
&self.min_grade,
&self.max_grade])
.unwrap();
conn.get_last_id().unwrap()
}
......
......@@ -614,7 +614,7 @@ impl MedalConnection for Connection {
}
fn get_contest_list(&self) -> Vec<Contest> {
let query = "SELECT id, location, filename, name, duration, public, start_date, end_date
let query = "SELECT id, location, filename, name, duration, public, start_date, end_date, min_grade, max_grade
FROM contest
ORDER BY id";
self.query_map_many(query, &[], |row| Contest { id: Some(row.get(0)),
......@@ -625,12 +625,14 @@ impl MedalConnection for Connection {
public: row.get(5),
start: row.get(6),
end: row.get(7),
min_grade: row.get(8),
max_grade: row.get(9),
taskgroups: Vec::new() })
.unwrap()
}
fn get_contest_by_id(&self, contest_id: i32) -> Contest {
let query = "SELECT location, filename, name, duration, public, start_date, end_date
let query = "SELECT location, filename, name, duration, public, start_date, end_date, min_grade, max_grade
FROM contest
WHERE id = ?1";
self.query_map_one(query, &[&contest_id], |row| Contest { id: Some(contest_id),
......@@ -641,6 +643,8 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() })
.unwrap()
.unwrap() // TODO: Should return Option?
......@@ -648,8 +652,8 @@ impl MedalConnection for Connection {
fn get_contest_by_id_complete(&self, contest_id: i32) -> Contest {
let query = "SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public,
contest.start_date, contest.end_date, taskgroup.id, taskgroup.name, task.id, task.location,
task.stars
contest.start_date, contest.end_date, contest.min_grade, contest.max_grade, taskgroup.id,
taskgroup.name, task.id, task.location, task.stars
FROM contest
JOIN taskgroup ON contest.id = taskgroup.contest
JOIN task ON taskgroup.id = task.taskgroup
......@@ -665,13 +669,15 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() },
Taskgroup { id: Some(row.get(7)),
Taskgroup { id: Some(row.get(9)),
contest: contest_id,
name: row.get(8),
name: row.get(10),
positionalnumber: None,
tasks: Vec::new() },
Task { id: Some(row.get(9)), taskgroup: row.get(7), location: row.get(10), stars: row.get(11) })
Task { id: Some(row.get(11)), taskgroup: row.get(9), location: row.get(12), stars: row.get(13) })
})
.unwrap();
let mut taskgroupcontest_iter = taskgroupcontest.into_iter();
......@@ -692,7 +698,8 @@ impl MedalConnection for Connection {
fn get_contest_by_id_partial(&self, contest_id: i32) -> Contest {
let query = "SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public,
contest.start_date, contest.end_date, taskgroup.id, taskgroup.name
contest.start_date, contest.end_date, contest.min_grade, contest.max_grade, taskgroup.id,
taskgroup.name
FROM contest
JOIN taskgroup ON contest.id = taskgroup.contest
WHERE contest.id = ?1";
......@@ -705,10 +712,12 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() },
Taskgroup { id: Some(row.get(7)),
Taskgroup { id: Some(row.get(9)),
contest: contest_id,
name: row.get(8),
name: row.get(10),
positionalnumber: None,
tasks: Vec::new() })
})
......@@ -770,7 +779,7 @@ impl MedalConnection for Connection {
fn get_task_by_id_complete(&self, task_id: i32) -> (Task, Taskgroup, Contest) {
let query = "SELECT task.location, task.stars, taskgroup.id, taskgroup.name, contest.id, contest.location,
contest.filename, contest.name, contest.duration, contest.public, contest.start_date,
contest.end_date
contest.end_date, contest.min_grade, contest.max_grade
FROM contest
JOIN taskgroup ON taskgroup.contest = contest.id
JOIN task ON task.taskgroup = taskgroup.id
......@@ -790,6 +799,8 @@ impl MedalConnection for Connection {
public: row.get(9),
start: row.get(10),
end: row.get(11),
min_grade: row.get(12),
max_grade: row.get(13),
taskgroups: Vec::new() })
})
.unwrap()
......@@ -1000,8 +1011,9 @@ impl MedalObject<Connection> for Contest {
let id = match self.get_id() {
Some(id) => {
let query = "UPDATE contest
SET location = ?1,filename = ?2, name = ?3, duration = ?4, public = ?5, start_date = ?6, end_date = ?7
WHERE id = ?8";
SET location = ?1, filename = ?2, name = ?3, duration = ?4, public = ?5, start_date = ?6,
end_date = ?7, min_grade = ?8, max_grade =?9
WHERE id = ?10";
conn.execute(query,
&[&self.location,
&self.filename,
......@@ -1010,13 +1022,16 @@ impl MedalObject<Connection> for Contest {
&self.public,
&self.start,
&self.end,
&self.min_grade,
&self.max_grade,
&id])
.unwrap();
id
}
None => {
let query = "INSERT INTO contest (location, filename, name, duration, public, start_date, end_date)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)";
let query = "INSERT INTO contest (location, filename, name, duration, public, start_date, end_date,
min_grade, max_grade)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)";
conn.execute(query,
&[&self.location,
&self.filename,
......@@ -1024,7 +1039,9 @@ impl MedalObject<Connection> for Contest {
&self.duration,
&self.public,
&self.start,
&self.end])
&self.end,
&self.min_grade,
&self.max_grade])
.unwrap();
conn.get_last_id().unwrap()
}
......
......@@ -614,7 +614,7 @@ impl MedalConnection for Connection {
}
fn get_contest_list(&self) -> Vec<Contest> {
let query = "SELECT id, location, filename, name, duration, public, start_date, end_date
let query = "SELECT id, location, filename, name, duration, public, start_date, end_date, min_grade, max_grade
FROM contest
ORDER BY id";
self.query_map_many(query, &[], |row| Contest { id: Some(row.get(0)),
......@@ -625,12 +625,14 @@ impl MedalConnection for Connection {
public: row.get(5),
start: row.get(6),
end: row.get(7),
min_grade: row.get(8),
max_grade: row.get(9),
taskgroups: Vec::new() })
.unwrap()
}
fn get_contest_by_id(&self, contest_id: i32) -> Contest {
let query = "SELECT location, filename, name, duration, public, start_date, end_date
let query = "SELECT location, filename, name, duration, public, start_date, end_date, min_grade, max_grade
FROM contest
WHERE id = ?1";
self.query_map_one(query, &[&contest_id], |row| Contest { id: Some(contest_id),
......@@ -641,6 +643,8 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() })
.unwrap()
.unwrap() // TODO: Should return Option?
......@@ -648,8 +652,8 @@ impl MedalConnection for Connection {
fn get_contest_by_id_complete(&self, contest_id: i32) -> Contest {
let query = "SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public,
contest.start_date, contest.end_date, taskgroup.id, taskgroup.name, task.id, task.location,
task.stars
contest.start_date, contest.end_date, contest.min_grade, contest.max_grade, taskgroup.id,
taskgroup.name, task.id, task.location, task.stars
FROM contest
JOIN taskgroup ON contest.id = taskgroup.contest
JOIN task ON taskgroup.id = task.taskgroup
......@@ -665,13 +669,15 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() },
Taskgroup { id: Some(row.get(7)),
Taskgroup { id: Some(row.get(9)),
contest: contest_id,
name: row.get(8),
name: row.get(10),
positionalnumber: None,
tasks: Vec::new() },
Task { id: Some(row.get(9)), taskgroup: row.get(7), location: row.get(10), stars: row.get(11) })
Task { id: Some(row.get(11)), taskgroup: row.get(9), location: row.get(12), stars: row.get(13) })
})
.unwrap();
let mut taskgroupcontest_iter = taskgroupcontest.into_iter();
......@@ -692,7 +698,8 @@ impl MedalConnection for Connection {
fn get_contest_by_id_partial(&self, contest_id: i32) -> Contest {
let query = "SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public,
contest.start_date, contest.end_date, taskgroup.id, taskgroup.name
contest.start_date, contest.end_date, contest.min_grade, contest.max_grade, taskgroup.id,
taskgroup.name
FROM contest
JOIN taskgroup ON contest.id = taskgroup.contest
WHERE contest.id = ?1";
......@@ -705,10 +712,12 @@ impl MedalConnection for Connection {
public: row.get(4),
start: row.get(5),
end: row.get(6),
min_grade: row.get(7),
max_grade: row.get(8),
taskgroups: Vec::new() },
Taskgroup { id: Some(row.get(7)),
Taskgroup { id: Some(row.get(9)),
contest: contest_id,
name: row.get(8),
name: row.get(10),
positionalnumber: None,
tasks: Vec::new() })
})
......@@ -770,7 +779,7 @@ impl MedalConnection for Connection {
fn get_task_by_id_complete(&self, task_id: i32) -> (Task, Taskgroup, Contest) {
let query = "SELECT task.location, task.stars, taskgroup.id, taskgroup.name, contest.id, contest.location,
contest.filename, contest.name, contest.duration, contest.public, contest.start_date,
contest.end_date
contest.end_date, contest.min_grade, contest.max_grade
FROM contest
JOIN taskgroup ON taskgroup.contest = contest.id
JOIN task ON task.taskgroup = taskgroup.id
......@@ -790,6 +799,8 @@ impl MedalConnection for Connection {
public: row.get(9),
start: row.get(10),
end: row.get(11),
min_grade: row.get(12),
max_grade: row.get(13),
taskgroups: Vec::new() })
})
.unwrap()
......@@ -1000,8 +1011,9 @@ impl MedalObject<Connection> for Contest {
let id = match self.get_id() {
Some(id) => {
let query = "UPDATE contest
SET location = ?1,filename = ?2, name = ?3, duration = ?4, public = ?5, start_date = ?6, end_date = ?7
WHERE id = ?8";
SET location = ?1,filename = ?2, name = ?3, duration = ?4, public = ?5, start_date = ?6,
end_date = ?7, min_grade =?8 , max_grade = ?9
WHERE id = ?10";
conn.execute(query,
&[&self.location,
&self.filename,
......@@ -1010,13 +1022,16 @@ impl MedalObject<Connection> for Contest {
&self.public,
&self.start,
&self.end,
&self.min_grade,
&self.max_grade,
&id])
.unwrap();
id
}
None => {
let query = "INSERT INTO contest (location, filename, name, duration, public, start_date, end_date)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)";
let query = "INSERT INTO contest (location, filename, name, duration, public, start_date, end_date,
min_grade, max_grade)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)";
conn.execute(query,
&[&self.location,
&self.filename,
......@@ -1024,7 +1039,9 @@ impl MedalObject<Connection> for Contest {
&self.duration,
&self.public,
&self.start,
&self.end])
&self.end,
&self.min_grade,
&self.max_grade])
.unwrap();
conn.get_last_id().unwrap()
}
......
......@@ -68,6 +68,8 @@ pub struct Contest {
pub public: bool,
pub start: Option<Timespec>,
pub end: Option<Timespec>,
pub min_grade: Option<i32>,
pub max_grade: Option<i32>,
pub taskgroups: Vec<Taskgroup>,
}
......@@ -141,8 +143,10 @@ impl HasId for Group {
}
impl Contest {
// TODO: Rewrite, so this attribute can be removed
#[allow(clippy::too_many_arguments)]
pub fn new(location: String, filename: String, name: String, duration: i32, public: bool,
start: Option<Timespec>, end: Option<Timespec>)
start: Option<Timespec>, end: Option<Timespec>, min_grade: Option<i32>, max_grade: Option<i32>)
-> Self
{
Contest { id: None,
......@@ -153,6 +157,8 @@ impl Contest {
public: public,
start: start,
end: end,
min_grade: min_grade,
max_grade: max_grade,
taskgroups: Vec::new() }
}
}
......
......@@ -271,6 +271,8 @@ mod tests {
1,
true,
None,
None,
None,
None);
contest.save(&conn);
......@@ -281,6 +283,8 @@ mod tests {
1,
true,
None,
None,
None,
None);
let mut taskgroup = Taskgroup::new("TaskgroupName".to_string(), None);
let task = Task::new("taskdir1".to_string(), 3); // ID: 1
......@@ -297,6 +301,8 @@ mod tests {
1,
false,
None,
None,
None,
None);
let mut taskgroup = Taskgroup::new("TaskgroupName".to_string(), None);
let task = Task::new("taskdir1".to_string(), 3); // ID: 3
......@@ -313,6 +319,8 @@ mod tests {
0,
true,
None,
None,
None,
None);
let mut taskgroup = Taskgroup::new("TaskgroupRenameName".to_string(), None);
let task = Task::new("taskdir1".to_string(), 3); // ID: 5
......
......@@ -155,11 +155,17 @@
<p>Der Wettbewerb kann nach dem Starten nicht mehr pausiert werden.</p>
{{/if}}
{{else}}
<p>Du kannst diesen Wettbewerb im Moment nicht starten.</p>
<p>Du kannst diesen Wettbewerb nicht starten.</p>
{{#if time_until_d}}
<p>Der Wettbewerb wird geöffnet in: {{ time_until_d }} Tagen, {{ time_until_h }} Stunden, {{ time_until_m }} Minuten.
{{else}}
<p>Der Wettbewerb wird geöffnet in: {{ time_until_d }} Tagen, {{ time_until_h }} Stunden, {{ time_until_m }} Minuten.
{{else}}
{{#if logged_in}}
{{#if grade_too_low}}
<p>Deine angegebene Jahrgangsstufe entspricht nicht den für diesen Wettbewerb vorgesehenen Altersgruppen.</p>
{{/if}}
{{#if grade_too_high}}
<p>Deine angegebene Jahrgangsstufe entspricht nicht den für diesen Wettbewerb vorgesehenen Altersgruppen.</p>
{{/if}}
{{else}}
<p>Möglicherweise musst du dich zunächst <a href="/login">einloggen</a>.</p>
{{/if}}
......
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