Commit b8718f46 authored by Robert Czechowski's avatar Robert Czechowski

Add cleanup function that deletes temporary sessions (session without login credentials)

parent 46f94141
......@@ -1587,9 +1587,37 @@ pub fn admin_do_cleanup<T: MedalConnection>(conn: &T, session_token: &str, csrf_
let result = conn.remove_old_users_and_groups(maxstudentage, Some(maxteacherage), Some(maxage));
let mut data = json_val::Map::new();
if let Ok((n_users, n_groups, n_teachers, n_other)) = result {
let infodata = format!(",\"n_users\":{},\"n_groups\":{},\"n_teachers\":{},\"n_other\":{}",
n_users, n_groups, n_teachers, n_other);
if let Ok((n_user, n_group, n_teacher, n_other)) = result {
let infodata = format!(",\"n_user\":{},\"n_group\":{},\"n_teacher\":{},\"n_other\":{}",
n_user, n_group, n_teacher, n_other);
data.insert("data".to_string(), to_json(&infodata));
Ok(("delete_ok".to_string(), data))
} else {
data.insert("reason".to_string(), to_json(&"Fehler."));
Ok(("delete_fail".to_string(), data))
}
}
pub fn admin_do_session_cleanup<T: MedalConnection>(conn: &T, session_token: &str, csrf_token: &str)
-> MedalValueResult {
let session = conn.get_session(&session_token)
.ensure_logged_in()
.ok_or(MedalError::NotLoggedIn)?
.ensure_admin()
.ok_or(MedalError::AccessDenied)?;
if session.csrf_token != csrf_token {
return Err(MedalError::CsrfCheckFailed);
}
let now = time::get_time();
let maxage = now - time::Duration::days(30); // Delete all temporary sessions after 30 days
let result = conn.remove_temporary_sessions(maxage);
let mut data = json_val::Map::new();
if let Ok((n_session,)) = result {
let infodata = format!(",\"n_session\":{}", n_session);
data.insert("data".to_string(), to_json(&infodata));
Ok(("delete_ok".to_string(), data))
} else {
......@@ -1612,7 +1640,10 @@ pub fn admin_do_soft_cleanup<T: MedalConnection>(conn: &T, session_token: &str,
let result = conn.remove_unreferenced_participation_data();
let mut data = json_val::Map::new();
if let Ok(()) = result {
if let Ok((n_submission, n_grade, n_participation)) = result {
let infodata = format!(",\"n_submission\":{},\"n_grade\":{},\"n_participation\":{}",
n_submission, n_grade, n_participation);
data.insert("data".to_string(), to_json(&infodata));
Ok(("delete_ok".to_string(), data))
} else {
data.insert("reason".to_string(), to_json(&"Fehler."));
......
......@@ -1620,7 +1620,31 @@ impl MedalConnection for Connection {
Ok((n_users, n_groups, n_teachers, n_other))
}
fn remove_unreferenced_participation_data(&self) -> Result<(), ()> {
fn remove_temporary_sessions(&self, maxage: time::Timespec) -> Result<(i32,), ()> {
// WARNING: This function could possibly be dangerous if the login possibilities change in a way
// that not every possibility is covered her …
// TODO: How can we make sure, this function is always safe, even in cases of changes elsewhere?
let query = "SELECT count(*)
FROM session
WHERE (last_activity < $1 OR last_activity IS NULL)
AND logincode IS NULL
AND password IS NULL
AND oauth_foreign_id IS NULL";
let n_session = self.query_map_one(query, &[&maxage], |row| row.get(0)).unwrap().unwrap();
let query = "DELETE
FROM session
WHERE (last_activity < $1 OR last_activity IS NULL)
AND logincode IS NULL
AND password IS NULL
AND oauth_foreign_id IS NULL";
self.execute(query, &[&maxage]).unwrap();
Ok((n_session,))
}
fn remove_unreferenced_participation_data(&self) -> Result<(i32, i32, i32), ()> {
// We use
// DELETE FROM submission WHERE session NOT IN (SELECT id FROM session);
// which works on Postgres as well es on Sqlite
......@@ -1628,6 +1652,24 @@ impl MedalConnection for Connection {
// DELETE FROM submission WHERE NOT EXISTS (SELECT FROM session WHERE session.id = submission.session);
// and the latter might be faster on Postgres, so if we ever feel the need to speed up this function,
// it should be split up in database specific code
let query = "SELECT count(*)
FROM submission
WHERE session NOT IN (SELECT id
FROM session)";
let n_submission = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "SELECT count(*)
FROM grade
WHERE session NOT IN (SELECT id
FROM session)";
let n_grade = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "SELECT count(*)
FROM participation
WHERE session NOT IN (SELECT id
FROM session)";
let n_participation = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "DELETE
FROM submission
......@@ -1636,18 +1678,18 @@ impl MedalConnection for Connection {
self.execute(query, &[]).unwrap();
let query = "DELETE
FROM participation
FROM grade
WHERE session NOT IN (SELECT id
FROM session)";
self.execute(query, &[]).unwrap();
let query = "DELETE
FROM grade
FROM participation
WHERE session NOT IN (SELECT id
FROM session)";
self.execute(query, &[]).unwrap();
Ok(())
Ok((n_submission, n_grade, n_participation))
}
fn get_debug_information(&self) -> String {
......
......@@ -149,7 +149,8 @@ pub trait MedalConnection {
fn remove_old_users_and_groups(&self, maxstudentage: time::Timespec, maxteacherage: Option<time::Timespec>,
maxage: Option<time::Timespec>)
-> Result<(i32, i32, i32, i32), ()>;
fn remove_unreferenced_participation_data(&self) -> Result<(), ()>;
fn remove_temporary_sessions(&self, maxage: time::Timespec) -> Result<(i32,), ()>;
fn remove_unreferenced_participation_data(&self) -> Result<(i32, i32, i32), ()>;
fn get_search_users(
&self, _: (Option<i32>, Option<String>, Option<String>, Option<String>, Option<String>, Option<String>))
......
......@@ -1739,7 +1739,31 @@ impl MedalConnection for Connection {
Ok((n_users, n_groups, n_teachers, n_other))
}
fn remove_unreferenced_participation_data(&self) -> Result<(), ()> {
fn remove_temporary_sessions(&self, maxage: time::Timespec) -> Result<(i32,), ()> {
// WARNING: This function could possibly be dangerous if the login possibilities change in a way
// that not every possibility is covered her …
// TODO: How can we make sure, this function is always safe, even in cases of changes elsewhere?
let query = "SELECT count(*)
FROM session
WHERE (last_activity < $1 OR last_activity IS NULL)
AND logincode IS NULL
AND password IS NULL
AND oauth_foreign_id IS NULL";
let n_session = self.query_map_one(query, &[&maxage], |row| row.get(0)).unwrap().unwrap();
let query = "DELETE
FROM session
WHERE (last_activity < $1 OR last_activity IS NULL)
AND logincode IS NULL
AND password IS NULL
AND oauth_foreign_id IS NULL";
self.execute(query, &[&maxage]).unwrap();
Ok((n_session,))
}
fn remove_unreferenced_participation_data(&self) -> Result<(i32, i32, i32), ()> {
// We use
// DELETE FROM submission WHERE session NOT IN (SELECT id FROM session);
// which works on Postgres as well es on Sqlite
......@@ -1748,6 +1772,24 @@ impl MedalConnection for Connection {
// and the latter might be faster on Postgres, so if we ever feel the need to speed up this function,
// it should be split up in database specific code
let query = "SELECT count(*)
FROM submission
WHERE session NOT IN (SELECT id
FROM session)";
let n_submission = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "SELECT count(*)
FROM grade
WHERE session NOT IN (SELECT id
FROM session)";
let n_grade = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "SELECT count(*)
FROM participation
WHERE session NOT IN (SELECT id
FROM session)";
let n_participation = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "DELETE
FROM submission
WHERE session NOT IN (SELECT id
......@@ -1755,18 +1797,18 @@ impl MedalConnection for Connection {
self.execute(query, &[]).unwrap();
let query = "DELETE
FROM participation
FROM grade
WHERE session NOT IN (SELECT id
FROM session)";
self.execute(query, &[]).unwrap();
let query = "DELETE
FROM grade
FROM participation
WHERE session NOT IN (SELECT id
FROM session)";
self.execute(query, &[]).unwrap();
Ok(())
Ok((n_submission, n_grade, n_participation))
}
fn get_debug_information(&self) -> String {
......
......@@ -1739,7 +1739,31 @@ impl MedalConnection for Connection {
Ok((n_users, n_groups, n_teachers, n_other))
}
fn remove_unreferenced_participation_data(&self) -> Result<(), ()> {
fn remove_temporary_sessions(&self, maxage: time::Timespec) -> Result<(i32,), ()> {
// WARNING: This function could possibly be dangerous if the login possibilities change in a way
// that not every possibility is covered her …
// TODO: How can we make sure, this function is always safe, even in cases of changes elsewhere?
let query = "SELECT count(*)
FROM session
WHERE (last_activity < ?1 OR last_activity IS NULL)
AND logincode IS NULL
AND password IS NULL
AND oauth_foreign_id IS NULL";
let n_session = self.query_map_one(query, &[&maxage], |row| row.get(0)).unwrap().unwrap();
let query = "DELETE
FROM session
WHERE (last_activity < ?1 OR last_activity IS NULL)
AND logincode IS NULL
AND password IS NULL
AND oauth_foreign_id IS NULL";
self.execute(query, &[&maxage]).unwrap();
Ok((n_session,))
}
fn remove_unreferenced_participation_data(&self) -> Result<(i32, i32, i32), ()> {
// We use
// DELETE FROM submission WHERE session NOT IN (SELECT id FROM session);
// which works on Postgres as well es on Sqlite
......@@ -1748,6 +1772,24 @@ impl MedalConnection for Connection {
// and the latter might be faster on Postgres, so if we ever feel the need to speed up this function,
// it should be split up in database specific code
let query = "SELECT count(*)
FROM submission
WHERE session NOT IN (SELECT id
FROM session)";
let n_submission = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "SELECT count(*)
FROM grade
WHERE session NOT IN (SELECT id
FROM session)";
let n_grade = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "SELECT count(*)
FROM participation
WHERE session NOT IN (SELECT id
FROM session)";
let n_participation = self.query_map_one(query, &[], |row| row.get(0)).unwrap().unwrap();
let query = "DELETE
FROM submission
WHERE session NOT IN (SELECT id
......@@ -1755,18 +1797,18 @@ impl MedalConnection for Connection {
self.execute(query, &[]).unwrap();
let query = "DELETE
FROM participation
FROM grade
WHERE session NOT IN (SELECT id
FROM session)";
self.execute(query, &[]).unwrap();
let query = "DELETE
FROM grade
FROM participation
WHERE session NOT IN (SELECT id
FROM session)";
self.execute(query, &[]).unwrap();
Ok(())
Ok((n_submission, n_grade, n_participation))
}
fn get_debug_information(&self) -> String {
......
......@@ -1129,6 +1129,9 @@ fn admin_cleanup<C>(req: &mut Request) -> IronResult<Response>
match cleanup_type.as_deref() {
Some("soft") => with_conn![core::admin_do_soft_cleanup, C, req, &session_token, &csrf_token].aug(req)?,
Some("session") => {
with_conn![core::admin_do_session_cleanup, C, req, &session_token, &csrf_token].aug(req)?
}
_ => with_conn![core::admin_do_cleanup, C, req, &session_token, &csrf_token].aug(req)?,
}
} else {
......
......@@ -9,13 +9,22 @@
</form>
</p>
<h2>Temporäre Sitzungen löschen</h2>
<p>Löscht Sitzungen von Benutzern, die sich nicht eingeloggt haben, wenn diese älter als 30 Tage sind.</p>
<p>Kann jederzeit gefahrlos ausgeführt werden.</p>
<p>
<form action="cleanup/session" method="post">
<input type="hidden" name="csrf_token" value="{{csrf_token}}">
<input type="submit" value="Temporäre Sitzungen löschen!">
</form>
</p>
<h2>Verwaiste Teilnahmen löschen</h2>
<p>Löscht Teilnahmen, deren Accounts gelöscht wurden.</p>
<p>Kann jederzeit gefahrlos ausgeführt werden</p>
<p>Kann jederzeit gefahrlos ausgeführt werden.</p>
<p>
<form action="cleanup/soft" method="post">
<input type="hidden" name="csrf_token" value="{{csrf_token}}">
<input type="submit" value="Alte Daten löschen!">
<input type="submit" value="Verwaiste Teilnahmen löschen!">
</form>
</p>
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