/* 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 *
\* . */
extern crate time;
use self::time::{Duration, Timespec};
#[derive(Clone)]
pub struct SessionUser {
pub id: i32,
pub session_token: Option, // delete this to log out
pub csrf_token: String,
pub last_login: Option,
pub last_activity: Option,
pub account_created: Option,
pub username: Option,
pub password: Option,
pub salt: Option,
pub logincode: Option,
pub email: Option,
pub email_unconfirmed: Option,
pub email_confirmationcode: Option,
pub firstname: Option,
pub lastname: Option,
pub street: Option,
pub zip: Option,
pub city: Option,
pub nation: Option,
pub grade: i32,
pub sex: Option,
pub is_admin: Option,
pub is_teacher: bool,
pub managed_by: Option,
pub oauth_foreign_id: Option,
pub oauth_provider: Option,
// pub oauth_extra_data: Option,
// pub pms_id: Option,
// pub pms_school_id: Option,
}
// Short version for display
#[derive(Clone, Default)]
pub struct UserInfo {
pub id: i32,
pub username: Option,
pub logincode: Option,
pub firstname: Option,
pub lastname: Option,
pub grade: i32,
}
#[derive(Clone)]
pub struct Group {
pub id: Option,
pub name: String,
pub groupcode: String,
pub tag: String,
pub admin: i32,
pub members: Vec,
}
#[derive(Debug)]
pub struct Contest {
pub id: Option,
pub location: String,
pub filename: String,
pub name: String,
pub duration: i32,
pub public: bool,
pub start: Option,
pub end: Option,
pub min_grade: Option,
pub max_grade: Option,
pub positionalnumber: Option,
pub requires_login: Option,
pub secret: Option,
pub taskgroups: Vec,
pub message: Option,
}
#[derive(Debug)]
pub struct Taskgroup {
pub id: Option,
pub contest: i32,
pub name: String,
pub active: bool,
pub positionalnumber: Option,
pub tasks: Vec,
}
#[derive(Debug)]
pub struct Task {
pub id: Option,
pub taskgroup: i32,
pub location: String,
pub stars: i32,
}
pub struct Submission {
pub id: Option,
pub session_user: i32,
pub task: i32,
pub grade: i32,
pub validated: bool,
pub nonvalidated_grade: i32,
pub needs_validation: bool,
pub subtask_identifier: Option,
pub value: String,
pub date: Timespec,
}
#[derive(Clone, Copy, Default, Debug)]
pub struct Grade {
pub taskgroup: i32,
pub user: i32,
pub grade: Option,
pub validated: bool,
}
pub struct Participation {
pub contest: i32,
pub user: i32,
pub start: Timespec,
}
pub trait HasId {
fn get_id(&self) -> Option;
fn set_id(&mut self, id: i32);
}
impl HasId for Submission {
fn get_id(&self) -> Option { self.id }
fn set_id(&mut self, id: i32) { self.id = Some(id); }
}
impl HasId for Task {
fn get_id(&self) -> Option { self.id }
fn set_id(&mut self, id: i32) { self.id = Some(id); }
}
impl HasId for Taskgroup {
fn get_id(&self) -> Option { self.id }
fn set_id(&mut self, id: i32) { self.id = Some(id); }
}
impl HasId for Contest {
fn get_id(&self) -> Option { self.id }
fn set_id(&mut self, id: i32) { self.id = Some(id); }
}
impl HasId for Group {
fn get_id(&self) -> Option { self.id }
fn set_id(&mut self, id: i32) { self.id = Some(id); }
}
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, end: Option, min_grade: Option, max_grade: Option,
positionalnumber: Option, requires_login: Option, secret: Option,
message: Option)
-> Self
{
Contest { id: None,
location,
filename,
name,
duration,
public,
start,
end,
min_grade,
max_grade,
positionalnumber,
requires_login,
secret,
message,
taskgroups: Vec::new() }
}
}
impl SessionUser {
pub fn minimal(id: i32, session_token: String, csrf_token: String) -> Self {
SessionUser {
id,
session_token: Some(session_token),
csrf_token,
last_login: None,
last_activity: None,
account_created: Some(time::get_time()),
// müssen die überhaupt außerhalb der datenbankabstraktion sichtbar sein?
username: None,
password: None,
salt: None,
logincode: None,
email: None,
email_unconfirmed: None,
email_confirmationcode: None,
firstname: None,
lastname: None,
street: None,
zip: None,
city: None,
nation: None,
grade: 0,
sex: None,
is_admin: Some(false),
is_teacher: false,
managed_by: None,
oauth_foreign_id: None,
oauth_provider: None,
// oauth_extra_data: Option,
//pms_id: None,
//pms_school_id: None,
}
}
pub fn group_user_stub() -> Self {
SessionUser { id: 0,
session_token: None,
csrf_token: "".to_string(),
last_login: None,
last_activity: None,
account_created: Some(time::get_time()),
username: None,
password: None,
salt: None,
logincode: None,
email: None,
email_unconfirmed: None,
email_confirmationcode: None,
firstname: None,
lastname: None,
street: None,
zip: None,
city: None,
nation: None,
grade: 0,
sex: None,
is_admin: None,
is_teacher: false,
managed_by: None,
oauth_foreign_id: None,
oauth_provider: None }
}
pub fn is_alive(&self) -> bool {
let duration = Duration::hours(9); // TODO: hardcoded value, should be moved into constant or sth
let now = time::get_time();
if let Some(last_activity) = self.last_activity {
now - last_activity < duration
} else {
false
}
}
pub fn is_logged_in(&self) -> bool {
(self.password.is_some() || self.logincode.is_some() || self.oauth_foreign_id.is_some()) && self.is_alive()
}
pub fn is_teacher(&self) -> bool { self.is_teacher }
pub fn is_admin(&self) -> bool { self.is_admin == Some(true) }
pub fn ensure_alive(self) -> Option {
if self.is_alive() {
Some(self)
} else {
None
}
}
pub fn ensure_logged_in(self) -> Option {
if self.is_logged_in() {
Some(self)
} else {
None
}
}
pub fn ensure_teacher(self) -> Option {
if self.is_logged_in() && self.is_teacher() {
Some(self)
} else {
None
}
}
pub fn ensure_admin(self) -> Option {
if self.is_logged_in() && self.is_admin() {
Some(self)
} else {
None
}
}
}
impl Taskgroup {
pub fn new(name: String, positionalnumber: Option) -> Self {
Taskgroup { id: None, contest: 0, name, active: true, positionalnumber, tasks: Vec::new() }
}
}
impl Task {
pub fn new(location: String, stars: i32) -> Self { Task { id: None, taskgroup: 0, location, stars } }
}
pub trait OptionSession {
fn ensure_alive(self) -> Self;
fn ensure_logged_in(self) -> Self;
fn ensure_teacher(self) -> Self;
fn ensure_admin(self) -> Self;
}
impl OptionSession for Option {
fn ensure_alive(self) -> Self { self?.ensure_alive() }
fn ensure_logged_in(self) -> Self { self?.ensure_logged_in() }
fn ensure_teacher(self) -> Self { self?.ensure_teacher() }
fn ensure_admin(self) -> Self { self?.ensure_admin() }
}