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