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