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