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 autosave: bool,
144 pub latest: bool,
145 pub highest_grade_latest: bool,
146 pub subtask_identifier: Option<String>,
147 pub value: String,
148 pub date: Timespec,
149}
150
151#[derive(Clone, Copy, Default, Debug)]
152pub struct Grade {
153 pub taskgroup: i32,
154 pub user: i32,
155 pub grade: Option<i32>,
156 pub validated: bool,
157}
158
159pub struct Participation {
160 pub contest: i32,
161 pub user: i32,
162 pub start: Timespec,
163 pub team: Option<i32>,
164 pub annotation: Option<String>,
165}
166
167pub trait HasId {
168 fn get_id(&self) -> Option<i32>;
169 fn set_id(&mut self, id: i32);
170}
171impl HasId for Submission {
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 Task {
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 Taskgroup {
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 Contest {
184 fn get_id(&self) -> Option<i32> { self.id }
185 fn set_id(&mut self, id: i32) { self.id = Some(id); }
186}
187impl HasId for Group {
188 fn get_id(&self) -> Option<i32> { self.id }
189 fn set_id(&mut self, id: i32) { self.id = Some(id); }
190}
191
192impl SessionUser {
193 pub fn minimal(id: i32, session_token: String, csrf_token: String) -> Self {
194 SessionUser { id,
195 session_token: Some(session_token),
196 csrf_token,
197 last_login: None,
198 last_activity: None,
199 account_created: Some(time::get_time()),
200 username: None,
202 password: None,
203 salt: None,
204 logincode: None,
205 email: None,
206 email_unconfirmed: None,
207 email_confirmationcode: None,
208
209 firstname: None,
210 lastname: None,
211 street: None,
212 zip: None,
213 city: None,
214 nation: None,
215 grade: 0,
216 sex: None,
217 anonymous: false,
218
219 is_admin: Some(false),
220 is_teacher: false,
221 managed_by: None,
222 school_name: None,
223
224 oauth_foreign_id: None,
225 oauth_provider: None }
226 }
227
228 pub fn group_user_stub() -> Self {
229 SessionUser { id: 0,
230 session_token: None,
231 csrf_token: "".to_string(),
232 last_login: None,
233 last_activity: None,
234 account_created: Some(time::get_time()),
235
236 username: None,
237 password: None,
238 salt: None,
239 logincode: None,
240 email: None,
241 email_unconfirmed: None,
242 email_confirmationcode: None,
243
244 firstname: None,
245 lastname: None,
246 street: None,
247 zip: None,
248 city: None,
249 nation: None,
250 grade: 0,
251 sex: None,
252 anonymous: false,
253
254 is_admin: None,
255 is_teacher: false,
256 managed_by: None,
257 school_name: None,
258
259 oauth_foreign_id: None,
260 oauth_provider: None }
261 }
262
263 pub fn is_alive(&self) -> bool {
264 let duration = Duration::hours(9); let now = time::get_time();
266 if let Some(last_activity) = self.last_activity {
267 now - last_activity < duration
268 } else {
269 false
270 }
271 }
272
273 pub fn is_logged_in(&self) -> bool {
274 (self.password.is_some() || self.logincode.is_some() || self.oauth_foreign_id.is_some()) && self.is_alive()
275 }
276
277 pub fn is_teacher(&self) -> bool { self.is_teacher }
278
279 pub fn is_admin(&self) -> bool { self.is_admin == Some(true) }
280
281 pub fn ensure_alive(self) -> Option<Self> {
282 if self.is_alive() {
283 Some(self)
284 } else {
285 None
286 }
287 }
288
289 pub fn ensure_logged_in(self) -> Option<Self> {
290 if self.is_logged_in() {
291 Some(self)
292 } else {
293 None
294 }
295 }
296
297 pub fn ensure_teacher(self) -> Option<Self> {
298 if self.is_logged_in() && self.is_teacher() {
299 Some(self)
300 } else {
301 None
302 }
303 }
304
305 pub fn ensure_admin(self) -> Option<Self> {
306 if self.is_logged_in() && self.is_admin() {
307 Some(self)
308 } else {
309 None
310 }
311 }
312
313 pub fn ensure_teacher_or_admin(self) -> Option<Self> {
314 if self.is_logged_in() && (self.is_admin() || self.is_teacher()) {
315 Some(self)
316 } else {
317 None
318 }
319 }
320}
321
322impl Taskgroup {
323 pub fn new(name: String, positionalnumber: Option<i32>) -> Self {
324 Taskgroup { id: None, contest: 0, name, active: true, positionalnumber, tasks: Vec::new() }
325 }
326}
327
328impl Task {
329 pub fn new(mut location: String, mut language: Option<String>, stars: i32) -> Self {
330 if language.is_none() {
331 (language, location) = match location.chars().next() {
332 Some('B') => (Some("blockly".to_string()), (&location[1..]).to_string()),
333 Some('P') => (Some("python".to_string()), (&location[1..]).to_string()),
334 _ => (None, location),
335 };
336 }
337
338 Task { id: None, taskgroup: 0, location, language, stars }
339 }
340}
341
342pub trait OptionSession {
343 fn ensure_alive(self) -> Self;
344 fn ensure_logged_in(self) -> Self;
345 #[allow(dead_code)]
346 fn ensure_teacher(self) -> Self;
347 #[allow(dead_code)]
348 fn ensure_admin(self) -> Self;
349}
350
351impl OptionSession for Option<SessionUser> {
352 fn ensure_alive(self) -> Self { self?.ensure_alive() }
353 fn ensure_logged_in(self) -> Self { self?.ensure_logged_in() }
354 fn ensure_teacher(self) -> Self { self?.ensure_teacher() }
355 fn ensure_admin(self) -> Self { self?.ensure_admin() }
356}