Commit 3a75b5fe authored by Robert Czechowski's avatar Robert Czechowski
Browse files

Add login functionality

parent 86b00a4a
...@@ -6,9 +6,24 @@ authors = ["Robert Czechowski <czechowski@bwinf.de>"] ...@@ -6,9 +6,24 @@ authors = ["Robert Czechowski <czechowski@bwinf.de>"]
[dependencies] [dependencies]
rusqlite = "0.13.0" rusqlite = "0.13.0"
time = "0.1.40" time = "0.1.40"
iron = "0.5.1"
rand = "*"
mount ="0.3"
router = "0.5"
serde = "1.0"
urlencoded = "0.5"
persistent = "0.3"
staticfile = "0.4"
serde_derive = "1.0"
handlebars-iron = "0.25.1"
iron-sessionstorage = ""
linked-hash-map = "0.5.1" linked-hash-map = "0.5.1"
[dependencies.serde_json] [dependencies.serde_json]
version = "1.0.20" version = "1.0.20"
features = ["preserve_order"] features = ["preserve_order"]
\ No newline at end of file
...@@ -5,27 +5,30 @@ pub trait MedalConnection { ...@@ -5,27 +5,30 @@ pub trait MedalConnection {
fn create() -> Self; fn create() -> Self;
fn dbtype(&self) -> &'static str; fn dbtype(&self) -> &'static str;
fn migration_already_applied(&mut self, name: &str) -> bool; fn migration_already_applied(&self, name: &str) -> bool;
fn apply_migration(&mut self, name: &str, contents: String); fn apply_migration(&mut self, name: &str, contents: String);
fn get_session(&mut self, key: String) -> Option<SessionUser>; fn get_session(&self, key: String) -> Option<SessionUser>;
fn new_session(&mut self) -> SessionUser; fn new_session(&self) -> SessionUser;
fn get_session_or_new(&mut self, key: String) -> SessionUser; fn get_session_or_new(&self, key: String) -> SessionUser;
fn login(&mut self, session: &SessionUser, username: String, password: String) -> Result<SessionUser,()>; //fn login(&self, session: &SessionUser, username: String, password: String) -> Result<String,()>;
fn login_with_code(&mut self, session: &SessionUser, logincode: String) -> Result<SessionUser,()>;
fn logout(&mut self, session: &SessionUser);
fn load_submission(&mut self, session: &SessionUser, task: String, subtask: Option<String>) -> Submission; fn login(&self, session: Option<String>, username: String, password: String) -> Result<String,()>;
fn submit_submission(&mut self, session: &SessionUser, task: String, subtask: Option<String>, submission: Submission); fn login_with_code(&self, session: Option<String>, logincode: String) -> Result<SessionUser,()>;
fn logout(&self, session: String);
fn get_contest_by_id(&mut self, contest_id : u32) -> Contest; fn load_submission(&self, session: &SessionUser, task: String, subtask: Option<String>) -> Submission;
fn get_contest_by_id_complete(&mut self, contest_id : u32) -> Contest; fn submit_submission(&self, session: &SessionUser, task: String, subtask: Option<String>, submission: Submission);
fn get_task_by_id(&mut self, task_id : u32) -> Task;
fn get_task_by_id_complete(&mut self, task_id : u32) -> (Task, Taskgroup, Contest);
fn get_submission_to_validate(&mut self, tasklocation: String, subtask: Option<String>) -> u32; fn get_contest_list(&self) -> Vec<Contest>;
fn find_next_submission_to_validate(&mut self, userid: u32, taskgroupid: u32); fn get_contest_by_id(&self, contest_id : u32) -> Contest;
fn get_contest_by_id_complete(&self, contest_id : u32) -> Contest;
fn get_task_by_id(&self, task_id : u32) -> Task;
fn get_task_by_id_complete(&self, task_id : u32) -> (Task, Taskgroup, Contest);
fn get_submission_to_validate(&self, tasklocation: String, subtask: Option<String>) -> u32;
fn find_next_submission_to_validate(&self, userid: u32, taskgroupid: u32);
} }
......
...@@ -5,6 +5,12 @@ use self::rusqlite::Connection; ...@@ -5,6 +5,12 @@ use self::rusqlite::Connection;
use db_conn::{MedalConnection, MedalObject}; use db_conn::{MedalConnection, MedalObject};
use db_objects::*; use db_objects::*;
use rand::{thread_rng, Rng};
fn hash_password(password: &str, hash: &str) -> String {
password.to_string()
}
impl MedalConnection for Connection { impl MedalConnection for Connection {
fn create() -> Connection { fn create() -> Connection {
Connection::open("blub.db").unwrap() Connection::open("blub.db").unwrap()
...@@ -14,7 +20,7 @@ impl MedalConnection for Connection { ...@@ -14,7 +20,7 @@ impl MedalConnection for Connection {
return "sqlite"; return "sqlite";
} }
fn migration_already_applied(&mut self, name: &str) -> bool { fn migration_already_applied(&self, name: &str) -> bool {
let create_string = "CREATE TABLE IF NOT EXISTS migrations (name TEXT PRIMARY KEY);"; let create_string = "CREATE TABLE IF NOT EXISTS migrations (name TEXT PRIMARY KEY);";
self.execute(create_string, &[]).unwrap(); self.execute(create_string, &[]).unwrap();
...@@ -35,7 +41,7 @@ impl MedalConnection for Connection { ...@@ -35,7 +41,7 @@ impl MedalConnection for Connection {
println!("OK."); println!("OK.");
} }
fn get_session(&mut self, key: String) -> Option<SessionUser> { fn get_session(&self, key: String) -> Option<SessionUser> {
self.query_row("SELECT id, session_token, csrf_token, last_login, last_activity, permanent_login, username, password, logincode, email, email_unconfirmed, email_confirmation_code, firstname, lastname, street, zip, city, nation, grade, is_teacher, managed_by, pms_id, pms_school_id FROM session_user WHERE session_token = ?1", &[&key], |row| { self.query_row("SELECT id, session_token, csrf_token, last_login, last_activity, permanent_login, username, password, logincode, email, email_unconfirmed, email_confirmation_code, firstname, lastname, street, zip, city, nation, grade, is_teacher, managed_by, pms_id, pms_school_id FROM session_user WHERE session_token = ?1", &[&key], |row| {
SessionUser { SessionUser {
id: row.get(0), id: row.get(0),
...@@ -47,6 +53,7 @@ impl MedalConnection for Connection { ...@@ -47,6 +53,7 @@ impl MedalConnection for Connection {
username: row.get(5), username: row.get(5),
password: row.get(6), password: row.get(6),
salt: None,//"".to_string(),
logincode: row.get(7), logincode: row.get(7),
email: row.get(8), email: row.get(8),
email_unconfirmed: row.get(9), email_unconfirmed: row.get(9),
...@@ -67,7 +74,7 @@ impl MedalConnection for Connection { ...@@ -67,7 +74,7 @@ impl MedalConnection for Connection {
} }
}).ok() }).ok()
} }
fn new_session(&mut self) -> SessionUser { fn new_session(&self) -> SessionUser {
let session_token = "123".to_string(); let session_token = "123".to_string();
let csrf_token = "123".to_string(); let csrf_token = "123".to_string();
...@@ -78,22 +85,66 @@ impl MedalConnection for Connection { ...@@ -78,22 +85,66 @@ impl MedalConnection for Connection {
SessionUser::minimal(id, session_token, csrf_token) SessionUser::minimal(id, session_token, csrf_token)
} }
fn get_session_or_new(&mut self, key: String) -> SessionUser { fn get_session_or_new(&self, key: String) -> SessionUser {
self.get_session(key).unwrap_or_else(|| self.new_session()) self.get_session(key).unwrap_or_else(|| self.new_session())
} }
fn login(&mut self, session: &SessionUser, username: String, password: String) -> Result<SessionUser,()> {unimplemented!()} fn login(&self, session: Option<String>, username: String, password: String) -> Result<String,()> {
fn login_with_code(&mut self, session: &SessionUser, logincode: String) -> Result<SessionUser,()> {unimplemented!()} println!("a {} {}", username, password);
fn logout(&mut self, session: &SessionUser) { match self.query_row(
self.execute("UPDATE session_user SET session_token = NULL WHERE id = ?1", &[&session.id]).unwrap(); "SELECT id, password, salt FROM session_user WHERE username = ?1",
&[&username],
|row| -> (u32, Option<String>, Option<String>) {
(row.get(0), row.get(1), row.get(2))
}) {
Ok((id, password_hash, salt)) => {
//println!("{}, {}", password, password_hash.unwrap());
if (hash_password(&password, &salt.unwrap()) == password_hash.unwrap()) {
// Login okay, update session now!
let session_token: String = thread_rng().gen_ascii_chars().take(10).collect();
let csrf_token: String = thread_rng().gen_ascii_chars().take(10).collect();
self.execute("UPDATE session_user SET session_token = ?1, csrf_token = ?2, last_login = date('now'), last_activity = date('now') WHERE id = ?3", &[&session_token, &csrf_token, &id]).unwrap();
Ok(session_token)
}
else {println!("b");Err(()) }
},
_ => {println!("c"); Err(()) }
}
}
fn login_with_code(&self, session: Option<String>, logincode: String) -> Result<SessionUser,()> {unimplemented!()}
fn logout(&self, session: String) {
self.execute("UPDATE session_user SET session_token = NULL WHERE id = ?1", &[&session]).unwrap();
} }
fn load_submission(&mut self, session: &SessionUser, task: String, subtask: Option<String>) -> Submission {unimplemented!()} fn load_submission(&self, session: &SessionUser, task: String, subtask: Option<String>) -> Submission {unimplemented!()}
fn submit_submission(&mut self, session: &SessionUser, task: String, subtask: Option<String>, submission: Submission) {unimplemented!()} fn submit_submission(&self, session: &SessionUser, task: String, subtask: Option<String>, submission: Submission) {unimplemented!()}
fn get_contest_by_id(&mut self, contest_id : u32) -> Contest { fn get_contest_list(&self) -> Vec<Contest> {
self.query_row("SELECT location, filename, name, duration, public, start, end FROM contest WHERE id = ?1", &[&contest_id], |row| { let mut stmt = self.prepare("SELECT id, location, filename, name, duration, public, start_date, end_date FROM contest").unwrap();
let rows = stmt.query_map(&[], |row| {
Contest {
id: Some(row.get(0)),
location: row.get(1),
filename: row.get(2),
name: row.get(3),
duration: row.get(4),
public: row.get(5),
start: row.get(6),
end: row.get(7),
taskgroups: Vec::new(),
}
}).unwrap().filter_map(|row| {row.ok()}).collect();
rows
}
fn get_contest_by_id(&self, contest_id : u32) -> Contest {
self.query_row("SELECT location, filename, name, duration, public, start_date, end_date FROM contest WHERE id = ?1", &[&contest_id], |row| {
Contest { Contest {
id: Some(contest_id), id: Some(contest_id),
location: row.get(0), location: row.get(0),
...@@ -107,7 +158,8 @@ impl MedalConnection for Connection { ...@@ -107,7 +158,8 @@ impl MedalConnection for Connection {
} }
}).unwrap() }).unwrap()
} }
fn get_contest_by_id_complete(&mut self, contest_id : u32) -> Contest {
fn get_contest_by_id_complete(&self, contest_id : u32) -> Contest {
let mut stmt = self.prepare("SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public, contest.start_date, contest.end_date, taskgroup.id, taskgroup.name, task.id, task.location, task.stars FROM contest JOIN taskgroup ON contest.id = taskgroup.contest JOIN task ON taskgroup.id = task.taskgroup WHERE contest.id = ?1").unwrap(); let mut stmt = self.prepare("SELECT contest.location, contest.filename, contest.name, contest.duration, contest.public, contest.start_date, contest.end_date, taskgroup.id, taskgroup.name, task.id, task.location, task.stars FROM contest JOIN taskgroup ON contest.id = taskgroup.contest JOIN task ON taskgroup.id = task.taskgroup WHERE contest.id = ?1").unwrap();
let mut taskgroupcontest_iter = stmt.query_map(&[&contest_id], |row| { let mut taskgroupcontest_iter = stmt.query_map(&[&contest_id], |row| {
...@@ -148,9 +200,9 @@ impl MedalConnection for Connection { ...@@ -148,9 +200,9 @@ impl MedalConnection for Connection {
contest.taskgroups.push(taskgroup); contest.taskgroups.push(taskgroup);
contest contest
} }
fn get_task_by_id(&mut self, task_id : u32) -> Task { fn get_task_by_id(&self, task_id : u32) -> Task {
self.query_row( self.query_row(
"SELECT location, stars, taskgroup WHERE id = ?1", "SELECT location, stars, taskgroup FROM task WHERE id = ?1",
&[&task_id], &[&task_id],
|row| { |row| {
Task { Task {
...@@ -161,9 +213,9 @@ impl MedalConnection for Connection { ...@@ -161,9 +213,9 @@ impl MedalConnection for Connection {
} }
}).unwrap() }).unwrap()
} }
fn get_task_by_id_complete(&mut self, task_id : u32) -> (Task, Taskgroup, Contest) { fn get_task_by_id_complete(&self, task_id : u32) -> (Task, Taskgroup, Contest) {
self.query_row( self.query_row(
"SELECT task.location, task.stars, taskgroup.id, taskgroup.name, contest.id, contest.location, contest.filename, contest.name, contest.duration, contest.public, contest.start_date, contest.end_date JOIN taskgroup ON taskgroup = taskgroup.id JOIN contest ON taskgroup.contest = contest.id WHERE task.id = ?1", "SELECT task.location, task.stars, taskgroup.id, taskgroup.name, contest.id, contest.location, contest.filename, contest.name, contest.duration, contest.public, contest.start_date, contest.end_date FROM task JOIN taskgroup ON task.taskgroup = taskgroup.id JOIN contest ON taskgroup.contest = contest.id WHERE task.id = ?1",
&[&task_id], &[&task_id],
|row| { |row| {
(Task { (Task {
...@@ -190,14 +242,14 @@ impl MedalConnection for Connection { ...@@ -190,14 +242,14 @@ impl MedalConnection for Connection {
}).unwrap() }).unwrap()
} }
fn get_submission_to_validate(&mut self, tasklocation: String, subtask: Option<String>) -> u32{ fn get_submission_to_validate(&self, tasklocation: String, subtask: Option<String>) -> u32{
match subtask { match subtask {
Some(st) => self.query_row("SELECT id FROM submission JOIN task ON submission.task = task.id WHERE task.location = ?1 AND subtask_identifier = ?2 AND needs_validation = 1 LIMIT 1", &[&tasklocation, &st], |row| {row.get(0)}).unwrap(), Some(st) => self.query_row("SELECT id FROM submission JOIN task ON submission.task = task.id WHERE task.location = ?1 AND subtask_identifier = ?2 AND needs_validation = 1 LIMIT 1", &[&tasklocation, &st], |row| {row.get(0)}).unwrap(),
None => self.query_row("SELECT id FROM submission JOIN task ON submission.task = task.id WHERE task.location = ?1 AND needs_validation = 1 LIMIT 1", &[&tasklocation], |row| {row.get(0)}).unwrap(), None => self.query_row("SELECT id FROM submission JOIN task ON submission.task = task.id WHERE task.location = ?1 AND needs_validation = 1 LIMIT 1", &[&tasklocation], |row| {row.get(0)}).unwrap(),
} }
} }
fn find_next_submission_to_validate(&mut self, userid: u32, taskgroupid: u32) { fn find_next_submission_to_validate(&self, userid: u32, taskgroupid: u32) {
let (id, validated) : (u32, bool) = self.query_row("SELECT id, validated FROM submission JOIN task ON submission.task = task.id WHERE task.taskgroup = ?1 AND submission.user = ?2 ORDER BY value DESC id DESC LIMIT 1", &[&taskgroupid, &userid], |row| {(row.get(0), row.get(1))}).unwrap();; let (id, validated) : (u32, bool) = self.query_row("SELECT id, validated FROM submission JOIN task ON submission.task = task.id WHERE task.taskgroup = ?1 AND submission.user = ?2 ORDER BY value DESC id DESC LIMIT 1", &[&taskgroupid, &userid], |row| {(row.get(0), row.get(1))}).unwrap();;
if !validated { if !validated {
self.execute("UPDATE submission SET needs_validation = 1 WHERE id = ?1", &[&id]).unwrap(); self.execute("UPDATE submission SET needs_validation = 1 WHERE id = ?1", &[&id]).unwrap();
......
...@@ -13,6 +13,7 @@ pub struct SessionUser { ...@@ -13,6 +13,7 @@ pub struct SessionUser {
pub username: Option<String>, pub username: Option<String>,
pub password: Option<String>, pub password: Option<String>,
pub salt: Option<String>,
pub logincode: Option<String>, pub logincode: Option<String>,
pub email: Option<String>, pub email: Option<String>,
pub email_unconfirmed: Option<String>, pub email_unconfirmed: Option<String>,
...@@ -117,10 +118,12 @@ impl SessionUser { ...@@ -117,10 +118,12 @@ impl SessionUser {
csrf_token: csrf_token, csrf_token: csrf_token,
last_login: None, last_login: None,
last_activity: None, // now? last_activity: None, // now?
// müssen die überhaupt außerhalb der datenbankabstraktion sichtbar sein?
permanent_login: false, permanent_login: false,
username: None, username: None,
password: None, password: None,
salt: None,
logincode: None, logincode: None,
email: None, email: None,
email_unconfirmed: None, email_unconfirmed: None,
......
#![feature(extern_prelude)]
#[macro_use]
extern crate iron;
#[macro_use]
extern crate router;
#[macro_use]
extern crate serde_derive;
extern crate rusqlite; extern crate rusqlite;
extern crate iron_sessionstorage;
extern crate urlencoded;
extern crate time;
extern crate persistent;
extern crate rand;
extern crate mount;
extern crate staticfile;
extern crate handlebars_iron;
extern crate serde_json;
use rusqlite::Connection; use rusqlite::Connection;
...@@ -11,9 +29,17 @@ use db_conn::{MedalConnection, MedalObject}; ...@@ -11,9 +29,17 @@ use db_conn::{MedalConnection, MedalObject};
use db_objects::*; use db_objects::*;
fn main() { mod webfw_iron;
let mut conn = Connection::create();
db_apply_migrations::test(&mut conn); use webfw_iron::start_server;
mod functions;
use std::path;
use std::fs;
fn read_contest(p: &path::PathBuf) -> Option<Contest> {
println!("Try to read some file …");
let mut contest = Contest::new("./".to_string(), "blub.json".to_string(), "Wettbewerb IX".to_string(), 45, true, None, None); let mut contest = Contest::new("./".to_string(), "blub.json".to_string(), "Wettbewerb IX".to_string(), 45, true, None, None);
let mut taskgroup = Taskgroup::new("Lustige Aufgabe".to_string()); let mut taskgroup = Taskgroup::new("Lustige Aufgabe".to_string());
...@@ -28,7 +54,53 @@ fn main() { ...@@ -28,7 +54,53 @@ fn main() {
let mut task = Task::new("blub4".to_string(), 3); let mut task = Task::new("blub4".to_string(), 3);
taskgroup.tasks.push(task); taskgroup.tasks.push(task);
contest.taskgroups.push(taskgroup); contest.taskgroups.push(taskgroup);
contest.save(&mut conn);
Some(contest)
}
fn get_all_contest_info(task_dir: &str) -> Vec<Contest> {
fn walk_me_recursively(p: &path::PathBuf, contests: &mut Vec<Contest>) {
match fs::read_dir(p) {
Ok(paths) => for path in paths {
let p = path.unwrap().path();
walk_me_recursively(&p, contests);
},
_ => (),
}
if p.file_name().unwrap().to_string_lossy().to_string().ends_with(".json") {
match read_contest(p) {
Some(contest) => contests.push(contest),
_ => (),
}
};
};
let mut contests = Vec::new();
match fs::read_dir(task_dir) {
Err(why) => println!("Error opening tasks directory! {:?}", why.kind()),
Ok(paths) => for path in paths {
walk_me_recursively(&path.unwrap().path(), &mut contests);
},
};
contests
}
fn refresh_all_contests(conn : &mut Connection) {
let v = get_all_contest_info("tasks/");
for mut contest_info in v {
contest_info.save(conn);
}
}
fn main() {
let mut conn = Connection::create();
db_apply_migrations::test(&mut conn);
refresh_all_contests(&mut conn);
println!("Hello, world!"); println!("Hello, world!");
...@@ -43,4 +115,8 @@ fn main() { ...@@ -43,4 +115,8 @@ fn main() {
} }
println!(""); println!("");
} }
start_server(conn);
println!("Server started.");
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment