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