db_objects.rs 10.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*  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/>.                                                                                  */

15
16
extern crate time;

Robert Czechowski's avatar
Robert Czechowski committed
17
use self::time::{Duration, Timespec};
18

19
#[derive(Clone)]
20
pub struct SessionUser {
21
    pub id: i32,
22
23
24
25
    pub session_token: Option<String>, // delete this to log out
    pub csrf_token: String,
    pub last_login: Option<Timespec>,
    pub last_activity: Option<Timespec>,
26
    pub account_created: Option<Timespec>,
Robert Czechowski's avatar
Robert Czechowski committed
27

28
29
    pub username: Option<String>,
    pub password: Option<String>,
Robert Czechowski's avatar
Robert Czechowski committed
30
    pub salt: Option<String>,
31
32
33
34
35
36
37
38
39
40
41
    pub logincode: Option<String>,
    pub email: Option<String>,
    pub email_unconfirmed: Option<String>,
    pub email_confirmationcode: Option<String>,

    pub firstname: Option<String>,
    pub lastname: Option<String>,
    pub street: Option<String>,
    pub zip: Option<String>,
    pub city: Option<String>,
    pub nation: Option<String>,
42
    pub grade: i32,
43
    pub sex: Option<i32>,
44

45
    pub is_admin: Option<bool>,
46
    pub is_teacher: bool,
47
    pub managed_by: Option<i32>,
48
49
50
51
52

    pub oauth_foreign_id: Option<String>,
    pub oauth_provider: Option<String>,
    // pub oauth_extra_data: Option<String>,

53
54
    // pub pms_id: Option<i32>,
    // pub pms_school_id: Option<i32>,
55
56
}

57
58
59
// Short version for display
#[derive(Clone, Default)]
pub struct UserInfo {
60
    pub id: i32,
61
62
63
64
    pub username: Option<String>,
    pub logincode: Option<String>,
    pub firstname: Option<String>,
    pub lastname: Option<String>,
65
    pub grade: i32,
66
67
68
}

#[derive(Clone)]
Robert Czechowski's avatar
Robert Czechowski committed
69
pub struct Group {
70
    pub id: Option<i32>,
Robert Czechowski's avatar
Robert Czechowski committed
71
72
73
    pub name: String,
    pub groupcode: String,
    pub tag: String,
74
    pub admin: i32,
Robert Czechowski's avatar
Robert Czechowski committed
75
    pub members: Vec<SessionUser>,
Robert Czechowski's avatar
Robert Czechowski committed
76
77
}

78
#[derive(Debug)]
79
pub struct Contest {
80
    pub id: Option<i32>,
81
82
83
    pub location: String,
    pub filename: String,
    pub name: String,
84
    pub duration: i32,
85
86
87
    pub public: bool,
    pub start: Option<Timespec>,
    pub end: Option<Timespec>,
88
89
    pub min_grade: Option<i32>,
    pub max_grade: Option<i32>,
90
    pub positionalnumber: Option<i32>,
91
92
    pub requires_login: Option<bool>,
    pub secret: Option<String>,
93
    pub taskgroups: Vec<Taskgroup>,
94
    pub message: Option<String>,
95
96
}

97
#[derive(Debug)]
98
pub struct Taskgroup {
99
100
    pub id: Option<i32>,
    pub contest: i32,
101
    pub name: String,
102
    pub active: bool,
103
    pub positionalnumber: Option<i32>,
104
105
106
    pub tasks: Vec<Task>,
}

107
#[derive(Debug)]
108
pub struct Task {
109
110
    pub id: Option<i32>,
    pub taskgroup: i32,
111
    pub location: String,
112
    pub stars: i32,
113
114
115
}

pub struct Submission {
116
117
118
119
    pub id: Option<i32>,
    pub session_user: i32,
    pub task: i32,
    pub grade: i32,
Robert Czechowski's avatar
Robert Czechowski committed
120
    pub validated: bool,
121
    pub nonvalidated_grade: i32,
Robert Czechowski's avatar
Robert Czechowski committed
122
123
124
125
    pub needs_validation: bool,
    pub subtask_identifier: Option<String>,
    pub value: String,
    pub date: Timespec,
126
127
}

128
#[derive(Clone, Copy, Default, Debug)]
129
pub struct Grade {
130
131
132
    pub taskgroup: i32,
    pub user: i32,
    pub grade: Option<i32>,
133
134
135
136
    pub validated: bool,
}

pub struct Participation {
137
138
    pub contest: i32,
    pub user: i32,
139
140
141
    pub start: Timespec,
}

Robert Czechowski's avatar
Robert Czechowski committed
142
pub trait HasId {
143
144
    fn get_id(&self) -> Option<i32>;
    fn set_id(&mut self, id: i32);
Robert Czechowski's avatar
Robert Czechowski committed
145
146
}
impl HasId for Submission {
147
148
    fn get_id(&self) -> Option<i32> { self.id }
    fn set_id(&mut self, id: i32) { self.id = Some(id); }
Robert Czechowski's avatar
Robert Czechowski committed
149
150
}
impl HasId for Task {
151
152
    fn get_id(&self) -> Option<i32> { self.id }
    fn set_id(&mut self, id: i32) { self.id = Some(id); }
Robert Czechowski's avatar
Robert Czechowski committed
153
154
}
impl HasId for Taskgroup {
155
156
    fn get_id(&self) -> Option<i32> { self.id }
    fn set_id(&mut self, id: i32) { self.id = Some(id); }
Robert Czechowski's avatar
Robert Czechowski committed
157
158
}
impl HasId for Contest {
159
160
    fn get_id(&self) -> Option<i32> { self.id }
    fn set_id(&mut self, id: i32) { self.id = Some(id); }
Robert Czechowski's avatar
Robert Czechowski committed
161
162
}
impl HasId for Group {
163
164
    fn get_id(&self) -> Option<i32> { self.id }
    fn set_id(&mut self, id: i32) { self.id = Some(id); }
Robert Czechowski's avatar
Robert Czechowski committed
165
}
166
167

impl Contest {
168
169
    // TODO: Rewrite, so this attribute can be removed
    #[allow(clippy::too_many_arguments)]
170
    pub fn new(location: String, filename: String, name: String, duration: i32, public: bool,
171
               start: Option<Timespec>, end: Option<Timespec>, min_grade: Option<i32>, max_grade: Option<i32>,
172
173
               positionalnumber: Option<i32>, requires_login: Option<bool>, secret: Option<String>,
               message: Option<String>)
Robert Czechowski's avatar
Robert Czechowski committed
174
175
176
               -> Self
    {
        Contest { id: None,
Robert Czechowski's avatar
Robert Czechowski committed
177
178
179
180
181
182
183
184
185
186
187
188
                  location,
                  filename,
                  name,
                  duration,
                  public,
                  start,
                  end,
                  min_grade,
                  max_grade,
                  positionalnumber,
                  requires_login,
                  secret,
189
                  message,
Robert Czechowski's avatar
Robert Czechowski committed
190
191
                  taskgroups: Vec::new() }
    }
192
193
194
}

impl SessionUser {
195
    pub fn minimal(id: i32, session_token: String, csrf_token: String) -> Self {
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
196
        SessionUser {
Robert Czechowski's avatar
Robert Czechowski committed
197
            id,
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
198
            session_token: Some(session_token),
Robert Czechowski's avatar
Robert Czechowski committed
199
            csrf_token,
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
200
            last_login: None,
201
            last_activity: None,
202
            account_created: Some(time::get_time()),
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
            // 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,
220
            sex: None,
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
221

222
            is_admin: Some(false),
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
223
224
225
226
227
228
229
230
231
            is_teacher: false,
            managed_by: None,

            oauth_foreign_id: None,
            oauth_provider: None,
            // oauth_extra_data: Option<String>,

            //pms_id: None,
            //pms_school_id: None,
232
        }
233
    }
234

235
236
237
238
239
240
    pub fn group_user_stub() -> Self {
        SessionUser { id: 0,
                      session_token: None,
                      csrf_token: "".to_string(),
                      last_login: None,
                      last_activity: None,
241
                      account_created: Some(time::get_time()),
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

                      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,
258
                      sex: None,
259

260
                      is_admin: None,
261
262
263
264
                      is_teacher: false,
                      managed_by: None,

                      oauth_foreign_id: None,
Robert Czechowski's avatar
rustfmt    
Robert Czechowski committed
265
                      oauth_provider: None }
266
267
    }

268
    pub fn is_alive(&self) -> bool {
269
        let duration = Duration::hours(9); // TODO: hardcoded value, should be moved into constant or sth
270
        let now = time::get_time();
271
272
273
274
275
276
277
278
        if let Some(last_activity) = self.last_activity {
            now - last_activity < duration
        } else {
            false
        }
    }

    pub fn is_logged_in(&self) -> bool {
279
        (self.password.is_some() || self.logincode.is_some() || self.oauth_foreign_id.is_some()) && self.is_alive()
280
281
    }

282
    pub fn is_teacher(&self) -> bool { self.is_teacher }
283

284
    pub fn is_admin(&self) -> bool { self.is_admin == Some(true) }
285

286
287
    pub fn ensure_alive(self) -> Option<Self> {
        if self.is_alive() {
288
            Some(self)
Robert Czechowski's avatar
Robert Czechowski committed
289
        } else {
290
            None
Robert Czechowski's avatar
Robert Czechowski committed
291
        }
292
293
294
    }

    pub fn ensure_logged_in(self) -> Option<Self> {
295
296
        if self.is_logged_in() {
            Some(self)
Robert Czechowski's avatar
Robert Czechowski committed
297
        } else {
298
299
300
            None
        }
    }
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

    pub fn ensure_teacher(self) -> Option<Self> {
        if self.is_logged_in() && self.is_teacher() {
            Some(self)
        } else {
            None
        }
    }

    pub fn ensure_admin(self) -> Option<Self> {
        if self.is_logged_in() && self.is_admin() {
            Some(self)
        } else {
            None
        }
    }
317
318
319
}

impl Taskgroup {
320
    pub fn new(name: String, positionalnumber: Option<i32>) -> Self {
321
        Taskgroup { id: None, contest: 0, name, active: true, positionalnumber, tasks: Vec::new() }
322
    }
323
324
325
}

impl Task {
326
    pub fn new(location: String, stars: i32) -> Self { Task { id: None, taskgroup: 0, location, stars } }
327
}
328
329
330
331

pub trait OptionSession {
    fn ensure_alive(self) -> Self;
    fn ensure_logged_in(self) -> Self;
332
333
    fn ensure_teacher(self) -> Self;
    fn ensure_admin(self) -> Self;
334
335
336
337
338
}

impl OptionSession for Option<SessionUser> {
    fn ensure_alive(self) -> Self { self?.ensure_alive() }
    fn ensure_logged_in(self) -> Self { self?.ensure_logged_in() }
339
340
    fn ensure_teacher(self) -> Self { self?.ensure_teacher() }
    fn ensure_admin(self) -> Self { self?.ensure_admin() }
341
}