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

Merge branch 'v1.7' into deploy

parents a9e54f35 7c39b28c
Pipeline #949 failed with stages
in 16 minutes and 47 seconds
This diff is collapsed.
/* medal *\
* Copyright (C) 2020 Bundesweite Informatikwettbewerbe *
* *
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero *
* General Public License as published by the Free Software Foundation, either version 3 of the License, or (at *
* your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the *
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public *
* License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see *
\* <http://www.gnu.org/licenses/>. */
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct OauthProvider {
pub provider_id: String,
pub medal_oauth_type: String,
pub url: String,
pub client_id: String,
pub client_secret: String,
pub access_token_url: String,
pub user_data_url: String,
pub school_data_url: Option<String>,
pub school_data_secret: Option<String>,
pub login_link_text: String,
}
......@@ -36,7 +36,7 @@ use urlencoded::{UrlEncodedBody, UrlEncodedQuery};
#[cfg(feature = "debug")]
use iron::BeforeMiddleware;
use config::Config;
use config::{Config, OauthProvider};
use core;
use db_conn::MedalConnection;
use iron::typemap::Key;
......@@ -99,7 +99,7 @@ impl AfterMiddleware for ErrorShower {
Ok(match response.status {
Some(s) => {
let n = s.to_u16();
if n >= 400 && n <= 599 {
if (400..=599).contains(&n) {
response.set((mime!(Text / Html),
format!("<h1>{} {}</h1>", n, s.canonical_reason().unwrap_or("(Unknown error)"))))
} else {
......@@ -1055,6 +1055,27 @@ fn admin_export_contest<C>(req: &mut Request) -> IronResult<Response>
Ok(Response::with((status::Found, RedirectRaw(format!("/export/{}", filename)))))
}
fn admin_cleanup<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
let session_token = req.expect_session_token()?;
let csrf_token = if let Ok(formdata) = req.get_ref::<UrlEncodedBody>() {
formdata.get("csrf_token").map(|x| x[0].to_owned())
} else {
None
};
let (template, data) = if let Some(csrf_token) = csrf_token {
with_conn![core::admin_do_cleanup, C, req, &session_token, &csrf_token].aug(req)?
} else {
with_conn![core::admin_show_cleanup, C, req, &session_token].aug(req)?
};
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn oauth<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
println!("{:?}", req.url.query().unwrap_or(""));
......@@ -1179,7 +1200,6 @@ fn pms_hash_school(school_id: &str, secret: &str) -> String {
format!("{:02X?}", hashed_string).chars().filter(|c| c.is_ascii_alphanumeric()).collect()
}
use oauth_provider::OauthProvider;
fn oauth_pms(req: &mut Request, oauth_provider: OauthProvider, school_id: Option<&String>)
-> Result<Result<core::ForeignUserData, Response>, core::MedalError> {
use core::{UserSex, UserType};
......@@ -1221,7 +1241,7 @@ fn oauth_pms(req: &mut Request, oauth_provider: OauthProvider, school_id: Option
if let Some(SchoolIdOrSchoolIds::SchoolIds(school_ids)) = user_data.schoolId {
// Has there been a school selected?
if let Some(school_id) = school_id {
if school_id == "none" {
if school_id == "none" && oauth_provider.allow_teacher_login_without_school == Some(true) {
// Nothing to do
}
// Is the school a valid school for the user?
......@@ -1265,6 +1285,8 @@ fn oauth_pms(req: &mut Request, oauth_provider: OauthProvider, school_id: Option
data.insert("parent".to_string(), to_json(&"base"));
data.insert("no_login".to_string(), to_json(&true));
data.insert("teacher_login_without_school".to_string(), to_json(&oauth_provider.allow_teacher_login_without_school.unwrap_or(false)));
let mut resp = Response::new();
resp.set_mut(Template::new(&"oauth_school_selector", data)).set_mut(status::Ok);
return Ok(Err(resp));
......@@ -1405,6 +1427,8 @@ pub fn start_server<C>(conn: C, config: Config) -> iron::error::HttpResult<iron:
admin_participation_post: post "/admin/user/:userid/:contestid" => admin_participation::<C>,
admin_contests: get "/admin/contest/" => admin_contests::<C>,
admin_export_contest: get "/admin/contest/:contestid/export" => admin_export_contest::<C>,
admin_cleanup: get "/admin/cleanup" => admin_cleanup::<C>,
admin_cleanup_post: post "/admin/cleanup" => admin_cleanup::<C>,
oauth: get "/oauth/:oauthid/" => oauth::<C>,
oauth_school: get "/oauth/:oauthid/:schoolid" => oauth::<C>,
check_cookie: get "/cookie" => cookie_warning,
......
......@@ -50,6 +50,7 @@
<input type="submit" value="Nach PMS-ID suchen">
</form>
</p>
<h2>Wettbewerbs-Export</h2>
<a href="/admin/contest/">Wettbewerbsübersicht</a>
......@@ -60,3 +61,6 @@
<a href="/dbstatus">
{{/if}}
Datenbankstatus</a>
<h2>Alte Benutzeraccounts aufräumen</h2>
<a href="/admin/cleanup">Datenbank-Cleanup</a>
<h1>Administration</h1>
<h2>Alte Daten löschen</h2>
<p>Dies Löscht alle verwalteten Schüleraccounts, die länger als 180 Tage nicht genutzt wurden, sowie alle Lehreraccounts länger als 3 Jahre und alle anderen Accounts die länger als 10 Jahre nicht genutzt wurden.</p>
<p>
<form action="" method="post">
<input type="hidden" name="csrf_token" value="{{csrf_token}}">
<input type="submit" value="Alte Daten löschen!">
</form>
</p>
{"status":"ok"}
{"status":"ok"{{{data}}}}
......@@ -104,7 +104,7 @@ function fileLoadHandler(event) {
for (var i = 0; i < data.length; i++) {
var acc = [];
if (data[i].length < 4) {
if (data[i].length < 5) {
// Count errors except for empty lines
if (data[i].length > 1 || (data[i].length == 1 && data[i][0] != "")) {
skiplines++;
......@@ -114,7 +114,7 @@ function fileLoadHandler(event) {
// Check if line is valid:
var line_valid = true;
for (var j = 0; j < 4; j++) {
for (var j = 0; j < 5; j++) {
// Skip line if any name is longer than 128 chars
if (data[i][j].length > 128) {
break;
......@@ -136,7 +136,20 @@ function fileLoadHandler(event) {
has13 = true;
}
for (var j = 0; j < 4; j++) {
if (data[i].length == 4) {
data[i].push("?");
}
if (data[i][4][0] == "m" || data[i][4][0] == "M") {
data[i][4] = "m";
} else if (data[i][4][0] == "w" || data[i][4][0] == "W" || data[i][4][0] == "f" || data[i][4][0] == "F") {
data[i][4] = "f";
} else if (data[i][4][0] == "d" || data[i][4][0] == "D") {
data[i][4] = "d";
} else {
data[i][4] = "?";
}
for (var j = 0; j < 5; j++) {
acc.push(data[i][j]);
}
......@@ -151,6 +164,19 @@ function fileLoadHandler(event) {
td.innerText = acc[j];
tr.appendChild(td);
}
var td = document.createElement("td");
if (acc[4] == "m") {
td.innerText = "männlich";
} else if (acc[4] == "f") {
td.innerText = "weiblich";
} else if (acc[4] == "d") {
td.innerText = "divers";
} else {
td.innerText = "?";
}
tr.appendChild(td);
document.getElementById("data").appendChild(tr);
// And add the accont data:
......@@ -217,38 +243,39 @@ function copyDataBeforeSend() {
<body ondrop="dropHandler(event);" ondragover="dragOverHandler(event);" ondragleave="dragLeaveHandler(event);" style="overflow-y:scroll;">
<div style="width:800px; margin: 10px auto;">
<div style="width:800px; margin: 10px auto;">
<h1>Gruppen per CSV-Upload anlegen</h1>
<p><a href="/">Zur Startseite</a></p>
<p><a href=".">Zur Gruppenübersicht</a></p>
<h1>Gruppen per CSV-Upload anlegen</h1>
<p><a href="/">Zur Startseite</a></p>
<p><a href=".">Zur Gruppenübersicht</a></p>
<p>Hier können Sie Gruppen und Accounts über eine CSV-Datei anlegen. Schieben Sie dazu die CSV-Datei auf das grüne Feld.</p>
<p>Die hochzuladene CSV-Datei muss den folgenden Kriterien genügen:
<ul>
<li>Die CSV-Datei muss Komma- oder Tab-getrennt sein</li>
<li>Die Datei muss in UTF-8 (Unicode UTF-8) kodiert sein</li>
<li>Die Datei muss mindestens vier Spalten enthalten. Alle weiteren Spalten werden ignoriert.
<ol>
<li>Der Name der Gruppe. (Es können mehrere Gruppen in einer Datei definert sein.)</li>
<li>Die Jahrgangsstufe des Teilnehmers.</li>
<li>Der Vorname des Teilnehmers.</li>
<li>Der Nachname des Teilnehmers.</li>
</ol>
Diese vier Spalten entsprechen den ersten vier Spalten der CSV-Dateien für den Upload zum Informatik-Biber.
</li>
</ul>
Ein Beispiel könnte so aussehen:
<pre>
Gruppenname,Stufe,Vorname,Nachname
7a,7,Gabi,Musterfrau
7a,7,Max,Mustermann
Info19,12,Ferdinand,Fallbeispiel</pre>
</p>
<p>Im Anschluss auf den Upload haben Sie hier noch die Möglichkeit einzelne Zeilen zu löschen (z. B. Kopfzeilen) bevor Sie die Gruppen anlegen. Angelegte Gruppen lassen sich nicht mehr löschen.</p>
<p>Hier können Sie Gruppen und Accounts über eine CSV-Datei anlegen. Schieben Sie dazu die CSV-Datei auf das grüne Feld.</p>
<p>Die hochzuladene CSV-Datei muss den folgenden Kriterien genügen:
<ul>
<li>Die CSV-Datei muss Komma- oder Tab-getrennt sein</li>
<li>Die Datei muss in UTF-8 (Unicode UTF-8) kodiert sein</li>
<li>Die Datei muss mindestens fünf Spalten enthalten. Alle weiteren Spalten werden ignoriert.
<ol>
<li>Der Name der Gruppe. (Es können mehrere Gruppen in einer Datei definert sein.)</li>
<li>Die Jahrgangsstufe des Teilnehmers.</li>
<li>Der Vorname des Teilnehmers.</li>
<li>Der Nachname des Teilnehmers.</li>
<li>Das Geschlecht des Teilnehmers.</li>
</ol>
Diese fünf Spalten entsprechen den ersten fünf Spalten der CSV-Dateien für den Upload zum Informatik-Biber (ohne Benutzernamen und Passwörter).
</li>
</ul>
Ein Beispiel könnte so aussehen:
<pre>
Gruppenname,Stufe,Vorname,Nachname,Geschlecht
7a,7,Gabi,Musterfrau,m
7a,7,Max,Mustermann,w
Info19,12,Ferdinand,Fallbeispiel,d</pre>
</p>
<p>Im Anschluss auf den Upload haben Sie hier noch die Möglichkeit einzelne Zeilen zu löschen (z. B. Kopfzeilen) bevor Sie die Gruppen anlegen. Angelegte Gruppen lassen sich nicht mehr löschen.</p>
</div>
<div id="drop_zone">
......@@ -264,13 +291,13 @@ Info19,12,Ferdinand,Fallbeispiel</pre>
<input type="submit" style=" color:blue;" value="Gruppen erstellen"></input><br>
</form>
<p>Bitte prüfen Sie vorher, dass alle Daten korrekt sind und Umlaute richtig dargestellt werden. Löschen Sie eventuell vorhandene Kopfzeilen. Kein Name darf länger als 100 Zeichen lang sein.
<br>Die Auswahl G8/G9 betrifft nur Schülerinnen und Schüler ab Jahrgangsstufe 11.</p>
<p id="error_message"></p>
<br>Die Auswahl G8/G9 betrifft nur Schülerinnen und Schüler ab Jahrgangsstufe 11.</p>
<p id="error_message"></p>
</div>
<a href="javascript:clearEverything();" style=""><button id="clear_all">Alle Löschen</button></a><br/>
<table>
<thead>
<tr><th></th><th>Gruppe</th><th>Jgst.</th><th>Vorname</th><th>Nachname</th></tr>
<tr><th></th><th>Gruppe</th><th>Jgst.</th><th>Vorname</th><th>Nachname</th><th>Geschlecht</th></tr>
</thead>
<tbody id="data">
</tbody>
......
......@@ -2,13 +2,20 @@
{{#if logged_in}}
Eingeloggt als <em>{{ username }}</em>
{{#if firstname}}{{#if lastname}}
({{firstname}} {{lastname}})
{{/if}}{{/if}}
{{#if firstname}}
({{firstname}}
{{/if}}
{{#if lastname}}
{{lastname}})
{{/if}}
{{#if teacher}}
[Lehrer]
{{/if}}
{{#if admin}}
[ADMIN]
{{/if}}
<a href="/logout">Logout</a>
{{else}}
......@@ -43,6 +50,10 @@
<p><a href="/group">Gruppenverwaltung</a></p>
{{/if}}
{{#if admin}}
<a href="/admin/">Administration</a>
{{/if}}
{{#if logged_in}}
<p><a href="/profile">Profil</a></p>
{{/if}}
......@@ -6,4 +6,10 @@
{{/each}}
</p>
<p>Wenn die gewünschte Schule hier nicht aufgeführt ist, bitte die Schule unter <a href="https://login.bwinf.de">login.bwinf.de</a> eintragen und ein Dokument hochladen, das die Zugehörigkeit zu Ihrer Schule bestätigt.<p>
<p>Wenn die gewünschte Schule hier nicht aufgeführt ist, bitte die Schule unter <a href="https://login.bwinf.de">login.bwinf.de</a> eintragen und ein Dokument hochladen, das die Zugehörigkeit zu Ihrer Schule bestätigt.</p>
{{#if teacher_login_without_school}}
<h2>Ohne Schule einloggen</h2>
<p>Sie können sich ohne Schule einloggen. Damit werden die Daten Ihrer Teilnehmer nicht Ihrer Schule zugeordnet.</p>
<p><a href="none?{{../query}}" class="button is-danger">Ohne Schule einloggen! Keine Teilnahmen am Jugendwettbewerb Informatik 2021 möglich.</a></p>
{{/if}}
../default/admin_cleanup.hbs
\ No newline at end of file
......@@ -134,11 +134,16 @@
{{/if}}
{{else}}
{{#if logged_in}}
{{#if constraints.grade_too_low}}
<p>Deine angegebene Jahrgangsstufe entspricht nicht den für diesen Wettbewerb vorgesehenen Altersgruppen.</p>
{{/if}}
{{#if constraints.grade_too_high}}
<p>Deine angegebene Jahrgangsstufe entspricht nicht den für diesen Wettbewerb vorgesehenen Altersgruppen.</p>
{{#if is_qualified}}
{{#if constraints.grade_too_low}}
<p>Deine angegebene Jahrgangsstufe entspricht nicht den für diesen Wettbewerb vorgesehenen Altersgruppen.</p>
{{/if}}
{{#if constraints.grade_too_high}}
<p>Deine angegebene Jahrgangsstufe entspricht nicht den für diesen Wettbewerb vorgesehenen Altersgruppen.</p>
{{/if}}
{{else}}
<p>Du bist für diesen Wettbewerb nicht qualifiziert.</p>
<p>Du hast nicht an der vorhergehenden Wettbewerbsrunde teilgenommen, die Voraussetzung für diesen Wettbewerb ist oder nicht die vorhergehenden Aufgaben bearbeitet, die Voraussetzung für diese Aufgaben sind.</p>
{{/if}}
{{else}}
<p>Möglicherweise musst du dich zunächst <a href="/login">einloggen</a>.</p>
......
......@@ -19,6 +19,7 @@
</div>
{{#if teacher_login_without_school}}
<div class="columns" >
<div class="column">
<h1 class="title is-4">Ohne Schule einloggen</h1>
......@@ -32,6 +33,7 @@
</p>
</div>
</div>
{{/if}}
{{/inline}}
{{~> (parent)~}}
......
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