1extern crate time;
16
17use self::time::{Duration, Timespec};
18
19#[derive(Clone, Debug)]
20pub struct SessionUser {
21 pub id: i32,
22 pub session_token: Option<String>, pub csrf_token: String,
24 pub last_login: Option<Timespec>,
25 pub last_activity: Option<Timespec>,
26 pub account_created: Option<Timespec>,
27
28 pub username: Option<String>,
29 pub password: Option<String>,
30 pub salt: Option<String>,
31 pub logincode: Option<String>,
32 pub email: Option<String>,
33 pub email_unconfirmed: Option<String>,
34 pub email_confirmationcode: Option<String>,
35
36 pub firstname: Option<String>,
37 pub lastname: Option<String>,
38 pub street: Option<String>,
39 pub zip: Option<String>,
40 pub city: Option<String>,
41 pub nation: Option<String>,
42 pub grade: i32,
43 pub sex: Option<i32>,
44 pub anonymous: bool,
45 pub additional_contest_time: Option<i32>,
46 pub data_protection_clearance: i32,
47
48 pub is_admin: Option<bool>,
49 pub is_teacher: bool,
50 pub managed_by: Option<i32>,
51 pub school_name: Option<String>,
52
53 pub oauth_foreign_id: Option<String>,
54 pub oauth_provider: Option<String>,
55}
56
57pub enum Sex {
58 #[allow(dead_code)]
59 NotStated = 0,
60 Male = 1,
61 Female = 2,
62 Diverse = 3,
63 #[allow(dead_code)]
64 Other = 4,
65}
66
67#[derive(Clone, Default)]
69pub struct UserInfo {
70 pub id: i32,
71 pub username: Option<String>,
72 pub logincode: Option<String>,
73 pub firstname: Option<String>,
74 pub lastname: Option<String>,
75 pub grade: i32,
76 pub annotation: Option<String>,
77 pub team: Option<i32>,
78}
79
80#[derive(Clone, Debug)]
81pub struct Group {
82 pub id: Option<i32>,
83 pub name: String,
84 pub groupcode: String,
85 pub tag: String,
86 pub admins: Vec<i32>,
87 pub members: Vec<SessionUser>,
88}
89
90#[derive(Debug)]
91pub struct RequiredContest {
92 pub filename: String,
93 pub required_stars: i32,
94}
95
96#[derive(Debug)]
97pub struct Contest {
98 pub id: Option<i32>,
99 pub location: String,
100 pub filename: String,
101 pub name: String,
102 pub duration: i32,
103 pub public: bool,
104 pub start: Option<Timespec>,
105 pub end: Option<Timespec>,
106 pub review_start: Option<Timespec>,
107 pub review_end: Option<Timespec>,
108 pub min_grade: Option<i32>,
109 pub max_grade: Option<i32>,
110 pub max_teamsize: Option<i32>,
111 pub positionalnumber: Option<i32>,
112 pub requires_login: Option<bool>,
113 pub requires_contests: Vec<RequiredContest>,
114 pub protected: bool,
115 pub secret: Option<String>,
116 pub message: Option<String>,
117 pub image: Option<String>,
118 pub language: Option<String>,
119 pub category: Option<String>,
120 pub colour: Option<String>,
121 pub standalone_task: Option<bool>,
122 pub tags: Vec<String>,
123 pub stickers: Vec<(String, i32)>,
124 pub taskgroups: Vec<Taskgroup>,
125}
126
127#[derive(Debug)]
128pub struct Taskgroup {
129 pub id: Option<i32>,
130 pub contest: i32,
131 pub name: String,
132 pub active: bool,
133 pub positionalnumber: Option<i32>,
134 pub tasks: Vec<Task>,
135}
136
137#[derive(Debug)]
138pub struct Task {
139 pub id: Option<i32>,
140 pub taskgroup: i32,
141 pub location: String,
142 pub language: Option<String>,
143 pub stars: i32,
144}
145
146pub struct Submission {
147 pub id: Option<i32>,
148 pub user: i32,
149 pub task: i32,
150 pub grade: i32,
151 pub validated: bool,
152 pub nonvalidated_grade: i32,
153 pub needs_validation: bool,
154 pub autosave: bool,
155 pub latest: bool,
156 pub highest_grade_latest: bool,
157 pub subtask_identifier: Option<String>,
158 pub value: String,
159 pub date: Timespec,
160}
161
162#[derive(Clone, Copy, Default, Debug)]
163pub struct Grade {
164 pub taskgroup: i32,
165 pub user: i32,
166 pub grade: Option<i32>,
167 pub validated: bool,
168}
169
170pub struct Participation {
171 pub contest: i32,
172 pub user: i32,
173 pub start: Timespec,
174 pub team: Option<i32>,
175 pub annotation: Option<String>,
176}
177
178pub trait HasId {
179 fn get_id(&self) -> Option<i32>;
180 fn set_id(&mut self, id: i32);
181}
182impl HasId for Submission {
183 fn get_id(&self) -> Option<i32> { self.id }
184 fn set_id(&mut self, id: i32) { self.id = Some(id); }
185}
186impl HasId for Task {
187 fn get_id(&self) -> Option<i32> { self.id }
188 fn set_id(&mut self, id: i32) { self.id = Some(id); }
189}
190impl HasId for Taskgroup {
191 fn get_id(&self) -> Option<i32> { self.id }
192 fn set_id(&mut self, id: i32) { self.id = Some(id); }
193}
194impl HasId for Contest {
195 fn get_id(&self) -> Option<i32> { self.id }
196 fn set_id(&mut self, id: i32) { self.id = Some(id); }
197}
198impl HasId for Group {
199 fn get_id(&self) -> Option<i32> { self.id }
200 fn set_id(&mut self, id: i32) { self.id = Some(id); }
201}
202
203impl SessionUser {
204 pub fn minimal(id: i32, session_token: String, csrf_token: String) -> Self {
205 SessionUser { id,
206 session_token: Some(session_token),
207 csrf_token,
208 last_login: None,
209 last_activity: None,
210 account_created: Some(time::get_time()),
211 username: None,
213 password: None,
214 salt: None,
215 logincode: None,
216 email: None,
217 email_unconfirmed: None,
218 email_confirmationcode: None,
219
220 firstname: None,
221 lastname: None,
222 street: None,
223 zip: None,
224 city: None,
225 nation: None,
226 grade: 0,
227 sex: None,
228 anonymous: false,
229 additional_contest_time: None,
230 data_protection_clearance: 0,
231
232 is_admin: Some(false),
233 is_teacher: false,
234 managed_by: None,
235 school_name: None,
236
237 oauth_foreign_id: None,
238 oauth_provider: None }
239 }
240
241 pub fn group_user_stub() -> Self {
242 SessionUser { id: 0,
243 session_token: None,
244 csrf_token: "".to_string(),
245 last_login: None,
246 last_activity: None,
247 account_created: Some(time::get_time()),
248
249 username: None,
250 password: None,
251 salt: None,
252 logincode: None,
253 email: None,
254 email_unconfirmed: None,
255 email_confirmationcode: None,
256
257 firstname: None,
258 lastname: None,
259 street: None,
260 zip: None,
261 city: None,
262 nation: None,
263 grade: 0,
264 sex: None,
265 anonymous: false,
266 additional_contest_time: None,
267 data_protection_clearance: 0,
268
269 is_admin: None,
270 is_teacher: false,
271 managed_by: None,
272 school_name: None,
273
274 oauth_foreign_id: None,
275 oauth_provider: None }
276 }
277
278 pub fn is_alive(&self) -> bool {
279 let duration = Duration::hours(9); let now = time::get_time();
281 if let Some(last_activity) = self.last_activity {
282 now - last_activity < duration
283 } else {
284 false
285 }
286 }
287
288 pub fn is_logged_in(&self) -> bool {
289 (self.password.is_some() || self.logincode.is_some() || self.oauth_foreign_id.is_some()) && self.is_alive()
290 }
291
292 pub fn is_teacher(&self) -> bool { self.is_teacher }
293
294 pub fn is_admin(&self) -> bool { self.is_admin == Some(true) }
295
296 pub fn ensure_alive(self) -> Option<Self> {
297 if self.is_alive() {
298 Some(self)
299 } else {
300 None
301 }
302 }
303
304 pub fn ensure_logged_in(self) -> Option<Self> {
305 if self.is_logged_in() {
306 Some(self)
307 } else {
308 None
309 }
310 }
311
312 pub fn ensure_teacher(self) -> Option<Self> {
313 if self.is_logged_in() && self.is_teacher() {
314 Some(self)
315 } else {
316 None
317 }
318 }
319
320 pub fn ensure_admin(self) -> Option<Self> {
321 if self.is_logged_in() && self.is_admin() {
322 Some(self)
323 } else {
324 None
325 }
326 }
327
328 pub fn ensure_teacher_or_admin(self) -> Option<Self> {
329 if self.is_logged_in() && (self.is_admin() || self.is_teacher()) {
330 Some(self)
331 } else {
332 None
333 }
334 }
335}
336
337impl Taskgroup {
338 pub fn new(name: String, positionalnumber: Option<i32>) -> Self {
339 Taskgroup { id: None, contest: 0, name, active: true, positionalnumber, tasks: Vec::new() }
340 }
341}
342
343impl Task {
344 pub fn new(mut location: String, mut language: Option<String>, stars: i32) -> Self {
345 if language.is_none() {
346 (language, location) = match location.chars().next() {
347 Some('B') => (Some("blockly".to_string()), (&location[1..]).to_string()),
348 Some('P') => (Some("python".to_string()), (&location[1..]).to_string()),
349 _ => (None, location),
350 };
351 }
352
353 Task { id: None, taskgroup: 0, location, language, stars }
354 }
355}
356
357pub trait OptionSession {
358 fn ensure_alive(self) -> Self;
359 fn ensure_logged_in(self) -> Self;
360 #[allow(dead_code)]
361 fn ensure_teacher(self) -> Self;
362 #[allow(dead_code)]
363 fn ensure_admin(self) -> Self;
364}
365
366impl OptionSession for Option<SessionUser> {
367 fn ensure_alive(self) -> Self { self?.ensure_alive() }
368 fn ensure_logged_in(self) -> Self { self?.ensure_logged_in() }
369 fn ensure_teacher(self) -> Self { self?.ensure_teacher() }
370 fn ensure_admin(self) -> Self { self?.ensure_admin() }
371}