/* 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() } }