From 682e74e155d878b2eb7f840383e7b56435ded395 Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Fri, 29 Nov 2019 20:06:35 +0100 Subject: [PATCH 01/38] got rid of rgi macro --- rgi/mod.rs | 54 ------------------------------------------------------ 1 file changed, 54 deletions(-) diff --git a/rgi/mod.rs b/rgi/mod.rs index 45599de..28a0945 100644 --- a/rgi/mod.rs +++ b/rgi/mod.rs @@ -6,60 +6,6 @@ use rocket::Route; -/// makro, které vygeneruje boilerplate pro volání daného rgi -/// -/// syntaxe (hranaté závorky značí, že parametr není povinný): -/// ```no_run -/// rgi! { -/// HTTP_METODA "rgi/cesta/k/rgi/binarce" -/// [arg: identifikátor]* // argumentem se myslí parametr z URL -/// [data: ]? // někdy je potřeba obalit do závorek () -/// } -/// ``` -/// (všechny argumenty a data musí implementovat `serialize` ze `serde`) -/// -/// příklad: -/// rgi! { -/// GET "rgi/lol/lol.py" -/// arg: name -/// arg: password -/// data: (Objekt) -/// } -#[macro_export] -macro_rules! rgi { - {$method:ident $name:literal $(arg: $arg:ident),* $(data: $data:tt)? } => { - { - // we need this lint to avoid warnings caused by extra parens - // which are not extra since they help the parser - #![allow(unused_parens)] - #[allow(unused_imports)] - use std::process::{Command, Stdio}; - #[allow(unused_imports)] - use std::io::{Read, Write}; - - let mut cmd = Command::new($name) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .arg(stringify!($method)) - .spawn() - .expect("kinda gay"); - - if let Some(ref mut stdin) = &mut cmd.stdin { - let _ = writeln!(stdin, "{{"); - let _ = writeln!(stdin, "\t\"args\": {{"); - $(let _ = writeln!(stdin, "\t\t\"{}\": \"{}\",", stringify!($arg), ($arg).to_string());)* - let _ = writeln!(stdin, "\t}},"); - $(let _ = writeln!(stdin, "\t\"data\": {}", serde_json::to_string($data).unwrap());)? - let _ = writeln!(stdin, "}}"); - } - - let cmd = cmd.wait_with_output().unwrap(); - - String::from_utf8_lossy(&cmd.stdout).to_string() - } - } -} - /// modul obsahující endpointy pro CRUD na rezervaci pub mod booking; From c9797881f4a8ccdb58baf39672d5cec2aa0a6a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:04:49 +0100 Subject: [PATCH 02/38] Revert "got rid of rgi macro" This reverts commit 682e74e155d878b2eb7f840383e7b56435ded395. --- rgi/mod.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/rgi/mod.rs b/rgi/mod.rs index 28a0945..45599de 100644 --- a/rgi/mod.rs +++ b/rgi/mod.rs @@ -6,6 +6,60 @@ use rocket::Route; +/// makro, které vygeneruje boilerplate pro volání daného rgi +/// +/// syntaxe (hranaté závorky značí, že parametr není povinný): +/// ```no_run +/// rgi! { +/// HTTP_METODA "rgi/cesta/k/rgi/binarce" +/// [arg: identifikátor]* // argumentem se myslí parametr z URL +/// [data: ]? // někdy je potřeba obalit do závorek () +/// } +/// ``` +/// (všechny argumenty a data musí implementovat `serialize` ze `serde`) +/// +/// příklad: +/// rgi! { +/// GET "rgi/lol/lol.py" +/// arg: name +/// arg: password +/// data: (Objekt) +/// } +#[macro_export] +macro_rules! rgi { + {$method:ident $name:literal $(arg: $arg:ident),* $(data: $data:tt)? } => { + { + // we need this lint to avoid warnings caused by extra parens + // which are not extra since they help the parser + #![allow(unused_parens)] + #[allow(unused_imports)] + use std::process::{Command, Stdio}; + #[allow(unused_imports)] + use std::io::{Read, Write}; + + let mut cmd = Command::new($name) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .arg(stringify!($method)) + .spawn() + .expect("kinda gay"); + + if let Some(ref mut stdin) = &mut cmd.stdin { + let _ = writeln!(stdin, "{{"); + let _ = writeln!(stdin, "\t\"args\": {{"); + $(let _ = writeln!(stdin, "\t\t\"{}\": \"{}\",", stringify!($arg), ($arg).to_string());)* + let _ = writeln!(stdin, "\t}},"); + $(let _ = writeln!(stdin, "\t\"data\": {}", serde_json::to_string($data).unwrap());)? + let _ = writeln!(stdin, "}}"); + } + + let cmd = cmd.wait_with_output().unwrap(); + + String::from_utf8_lossy(&cmd.stdout).to_string() + } + } +} + /// modul obsahující endpointy pro CRUD na rezervaci pub mod booking; From 27d52080f6c395dc5c52ccb6d6980d71a3c612f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:05:05 +0100 Subject: [PATCH 03/38] Revert "sin2" This reverts commit e3395eb92d392d26318b61e3781cf4663f3d48c0. --- rgi/booking/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rgi/booking/mod.rs b/rgi/booking/mod.rs index 4473232..aea10f6 100644 --- a/rgi/booking/mod.rs +++ b/rgi/booking/mod.rs @@ -120,10 +120,10 @@ pub fn delete(r_id: i32, usr: AuthToken) -> Option { let con = db::get_con(); let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; - /*if reservation.author.trim() != usr.user.email.trim() { + if reservation.author.trim() != usr.user.email.trim() { println!("fuck"); None? // you shouldn't be able to delete others' either - }*/ + } } let id = r_id; From 158e265f68983163dcd4fcb85ae923e2e6eddf63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:05:56 +0100 Subject: [PATCH 04/38] revert and update submodule --- frontend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend b/frontend index 1644a3c..3222c4d 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit 1644a3ca57ec9c1d7662e4cff996dac7b8e3e3d6 +Subproject commit 3222c4d1624aef3271c4e7e41ac0deba09aa777e From 960069fb2a64838b75268ff4bf3c70b6f3d67d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:07:28 +0100 Subject: [PATCH 05/38] Revert "loeaddsD" This reverts commit a87a8e8549da643a8a433f08d59b71d83966db7d. --- rgi/booking/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rgi/booking/mod.rs b/rgi/booking/mod.rs index aea10f6..6d7a155 100644 --- a/rgi/booking/mod.rs +++ b/rgi/booking/mod.rs @@ -121,7 +121,6 @@ pub fn delete(r_id: i32, usr: AuthToken) -> Option { let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; if reservation.author.trim() != usr.user.email.trim() { - println!("fuck"); None? // you shouldn't be able to delete others' either } } From 82ac21ef1da7cfccbb7bf933a4ec8436e5227712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:08:02 +0100 Subject: [PATCH 06/38] Revert "lellsaf" This reverts commit a04cf3f20065f252332a6a425b93c4f90a39b42f. --- rgi/booking/mod.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/rgi/booking/mod.rs b/rgi/booking/mod.rs index 6d7a155..0ab1a41 100644 --- a/rgi/booking/mod.rs +++ b/rgi/booking/mod.rs @@ -48,14 +48,13 @@ pub fn get(id: i32, _u: AuthToken) -> Option { /// data: [`NewReservation`] #[post("/events", data = "<_input>")] pub fn post(_input: Json, usr: AuthToken) -> String { - let name = usr.user.name.clone(); - let user_id = usr.user.id.clone(); - let email = usr.user.email.clone(); + let name = usr.user.name; + let user_id = usr.user.id; + let email = usr.user.email; rgi! { POST "rgi/booking/booking.py" arg: user_id, - arg: email, arg: name data: (&_input.into_inner()) } @@ -71,10 +70,6 @@ pub fn post(_input: Json, usr: AuthToken) -> String { /// data:[`UpdateReservation`] #[patch("/events/", data = "<_input>")] pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Option { - let name = usr.user.name.clone(); - let user_id = usr.user.id.clone(); - let email = usr.user.email.clone(); - // TODO return error instead of None on invalid states if r_id < 0 { None? @@ -94,10 +89,7 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Opti let id = r_id; Some(rgi! { PATCH "rgi/booking/booking.py" - arg: id, - arg: user_id, - arg: name, - arg: email + arg: id data: (&_input.into_inner()) }) } From f77ac387355165265d29e6082b8789a2e3967516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:08:27 +0100 Subject: [PATCH 07/38] Revert "sin" This reverts commit 19e24b5f466a7593ceb97763a1abbe684ae97653. --- rgi/booking/mod.rs | 22 ++++++++++------------ src/auth.rs | 37 +++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/rgi/booking/mod.rs b/rgi/booking/mod.rs index 0ab1a41..e5e24f2 100644 --- a/rgi/booking/mod.rs +++ b/rgi/booking/mod.rs @@ -30,7 +30,7 @@ pub fn list() -> String { /// parametry: /// - `id`: identifikátor dané rezervace #[get("/events/")] -pub fn get(id: i32, _u: AuthToken) -> Option { +pub fn get(id: i32, _u: AuthToken) -> Option { if id < 0 { None? } @@ -47,7 +47,7 @@ pub fn get(id: i32, _u: AuthToken) -> Option { /// /// data: [`NewReservation`] #[post("/events", data = "<_input>")] -pub fn post(_input: Json, usr: AuthToken) -> String { +pub fn post(_input: Json, usr: AuthToken) -> String { let name = usr.user.name; let user_id = usr.user.id; let email = usr.user.email; @@ -55,7 +55,8 @@ pub fn post(_input: Json, usr: AuthToken) -> String { rgi! { POST "rgi/booking/booking.py" arg: user_id, - arg: name + arg: name, + arg: email data: (&_input.into_inner()) } } @@ -69,7 +70,7 @@ pub fn post(_input: Json, usr: AuthToken) -> String { /// /// data:[`UpdateReservation`] #[patch("/events/", data = "<_input>")] -pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Option { +pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Option { // TODO return error instead of None on invalid states if r_id < 0 { None? @@ -100,7 +101,7 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Opti /// parametry: /// - `id`: identifikátor dané rezervace #[delete("/events/")] -pub fn delete(r_id: i32, usr: AuthToken) -> Option { +pub fn delete(r_id: i32, usr: AuthToken) -> Option { // TODO return error instead of None on invalid states if r_id < 0 { None? @@ -133,7 +134,7 @@ pub fn delete(r_id: i32, usr: AuthToken) -> Option { /// - `begin_time`: počáteční čas /// - `end_time`: čas konce #[get("/events/filter///")] -pub fn date_filter(rooms: i32, begin_time: String, end_time: String, _u: AuthToken) -> String { +pub fn date_filter(rooms: i32, begin_time: String, end_time: String, _u: AuthToken) -> String { rgi! { FILTER "rgi/booking/booking.py" arg: rooms, @@ -149,14 +150,11 @@ pub fn date_filter(rooms: i32, begin_time: String, end_time: String, _u: AuthTok /// parametry: /// - `id`: id rezervace #[post("/events//approve")] -pub fn approve(id: i32, _u: AuthToken) -> Option { - if _u.user.role.to_lowercase() != Approver::name() { - None? - } - Some(rgi! { +pub fn approve(id: i32, _u: AuthToken) -> String { + rgi! { APPROVE "rgi/booking/booking.py" arg: id - }) + } } /// vrací seznam endpointů pro nabindování do Rocketu diff --git a/src/auth.rs b/src/auth.rs index b03a5df..40e03ba 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -35,15 +35,17 @@ pub struct AuthTokenRaw { /// autorizační token po vyřešení údajů s databází #[derive(Serialize, Deserialize)] -pub struct AuthToken { +pub struct AuthToken { /// nalezený uživatel pub user: User, + /// marker pro rezoluci role + pub _m: PhantomData, } -impl AuthToken { +impl AuthToken { /// sestrojí nový AuthToken z instace [`User`] pub fn from_user(user: User) -> Self { - AuthToken { user } + AuthToken { user, _m: PhantomData } } } @@ -88,7 +90,7 @@ pub mod roles { } } -impl<'a, 'r> FromRequest<'a, 'r> for AuthToken { +impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { type Error = String; fn from_request(request: &'a Request<'r>) -> Outcome { @@ -143,19 +145,18 @@ impl<'a, 'r> FromRequest<'a, 'r> for AuthToken { .unwrap_or_else(|_| unreachable!("uh oh, this shouldn't happen, is your DB okay?")) }); - //if T::name().to_lowercase() == result.role.to_lowercase() { - // Outcome::Success(AuthToken::from_user(result)) - //} else if let Some(daddy) = T::daddy() { - // println!("{}", daddy); - // match daddy.to_lowercase() == result.role.to_lowercase() { - // true => - Outcome::Success(AuthToken::from_user(result)) - // false => Outcome::Failure((Status::Forbidden, "you don't have the required role".to_string())), - // } - //} else { - // println!("yeetus that feetus?"); - // Outcome::Failure((Status::Forbidden, "you don't have the required role".to_string())) - //} + if T::name().to_lowercase() == result.role.to_lowercase() { + Outcome::Success(AuthToken::from_user(result)) + } else if let Some(daddy) = T::daddy() { + println!("{}", daddy); + match daddy.to_lowercase() == result.role.to_lowercase() { + true => Outcome::Success(AuthToken::from_user(result)), + false => Outcome::Failure((Status::Forbidden, "you don't have the required role".to_string())), + } + } else { + println!("yeetus that feetus?"); + Outcome::Failure((Status::Forbidden, "you don't have the required role".to_string())) + } } x => { println!("{:?}", x); @@ -167,6 +168,6 @@ impl<'a, 'r> FromRequest<'a, 'r> for AuthToken { /// vrací informace o uživatelu #[get("/me")] -pub fn me(_u: AuthToken) -> Json { +pub fn me(_u: AuthToken) -> Json { Json(_u.user) } From 998ecab9abfb11dc31c734e5fcbc7c677b8b69e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 16:32:23 +0100 Subject: [PATCH 08/38] rustify list and get --- rgi/booking/mod.rs | 38 +++++++++++++++++++++++--------------- src/lib.rs | 5 ++--- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/rgi/booking/mod.rs b/rgi/booking/mod.rs index e5e24f2..0f24d29 100644 --- a/rgi/booking/mod.rs +++ b/rgi/booking/mod.rs @@ -16,11 +16,16 @@ use diesel::prelude::*; /// vrací všechny rezervace /// /// GET /events "application/json" -#[get("/events")] -pub fn list() -> String { - rgi! { - LIST "rgi/booking/booking.py" - } +#[get("/events", format = "application/json")] +pub fn list() -> Option>> { + use crate::schema::booking::dsl::*; + + let conn = db::get_con(); + + booking + .load::(&conn) + .ok() + .map(Json) } /// vrátí JSON dané rezervace @@ -29,16 +34,19 @@ pub fn list() -> String { /// /// parametry: /// - `id`: identifikátor dané rezervace -#[get("/events/")] -pub fn get(id: i32, _u: AuthToken) -> Option { - if id < 0 { - None? - } - - Some(rgi! { - GET "rgi/booking/booking.py" - arg: id - }) +#[get("/events/")] +pub fn get(event_id: i32, _u: AuthToken) -> Option> { + use crate::schema::booking::dsl::*; + + let conn = db::get_con(); + + booking + .find(event_id) + .first::(&conn) + .optional() + .ok() + .flatten() + .map(Json) } /// vrátí JSON dané rezervace diff --git a/src/lib.rs b/src/lib.rs index 83e3583..845fa0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ //! └── static_server.rs - statický server //! ``` #![feature(proc_macro_hygiene, decl_macro)] +#![allow(clippy::match_bool)] #![deny(missing_docs)] #[macro_use] @@ -52,9 +53,7 @@ extern crate dotenv; use dotenv::dotenv; use rocket::http::Method; -use rocket_cors::{AllowedHeaders, AllowedOrigins, Error}; - -use std::str::FromStr; +use rocket_cors::{AllowedHeaders, AllowedOrigins}; pub mod auth; pub mod rgi; From 4f7bf8c27ae8f2dec498b41995461cd46aa4e1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 17:04:30 +0100 Subject: [PATCH 09/38] rustify delete --- rgi/booking/mod.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/rgi/booking/mod.rs b/rgi/booking/mod.rs index 0f24d29..c5f4eef 100644 --- a/rgi/booking/mod.rs +++ b/rgi/booking/mod.rs @@ -86,8 +86,8 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) - if usr.user.role.to_lowercase() != Approver::name() { use crate::schema::booking::dsl::*; - let con = db::get_con(); + let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; if reservation.author.trim() != usr.user.email.trim() { @@ -109,14 +109,14 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) - /// parametry: /// - `id`: identifikátor dané rezervace #[delete("/events/")] -pub fn delete(r_id: i32, usr: AuthToken) -> Option { +pub fn delete(r_id: i32, usr: AuthToken) -> Option<()> { + use crate::schema::booking::dsl::*; // TODO return error instead of None on invalid states if r_id < 0 { None? } if usr.user.role.to_lowercase() != Approver::name() { - use crate::schema::booking::dsl::*; let con = db::get_con(); let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; @@ -126,11 +126,12 @@ pub fn delete(r_id: i32, usr: AuthToken) -> Option { } } - let id = r_id; - Some(rgi! { - DELETE "rgi/booking/booking.py" - arg: id - }) + let conn = db::get_con(); + + diesel::delete(booking.find(r_id)) + .execute(&conn) + .ok() + .map(|_| ()) } /// filtruje podle data From 150ff822b732d938fa7f5cb9456e30e52862054b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 17:18:59 +0100 Subject: [PATCH 10/38] more appropriate rename --- {rgi => api}/booking/booking.py | 0 {rgi => api}/booking/curltest | 0 {rgi => api}/booking/mail.py | 0 {rgi => api}/booking/mod.rs | 0 {rgi => api}/mod.rs | 0 src/api | 1 + src/lib.rs | 4 ++-- src/rgi | 1 - 8 files changed, 3 insertions(+), 3 deletions(-) rename {rgi => api}/booking/booking.py (100%) rename {rgi => api}/booking/curltest (100%) rename {rgi => api}/booking/mail.py (100%) rename {rgi => api}/booking/mod.rs (100%) rename {rgi => api}/mod.rs (100%) create mode 120000 src/api delete mode 120000 src/rgi diff --git a/rgi/booking/booking.py b/api/booking/booking.py similarity index 100% rename from rgi/booking/booking.py rename to api/booking/booking.py diff --git a/rgi/booking/curltest b/api/booking/curltest similarity index 100% rename from rgi/booking/curltest rename to api/booking/curltest diff --git a/rgi/booking/mail.py b/api/booking/mail.py similarity index 100% rename from rgi/booking/mail.py rename to api/booking/mail.py diff --git a/rgi/booking/mod.rs b/api/booking/mod.rs similarity index 100% rename from rgi/booking/mod.rs rename to api/booking/mod.rs diff --git a/rgi/mod.rs b/api/mod.rs similarity index 100% rename from rgi/mod.rs rename to api/mod.rs diff --git a/src/api b/src/api new file mode 120000 index 0000000..4bb0f50 --- /dev/null +++ b/src/api @@ -0,0 +1 @@ +../api/ \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 845fa0e..9fd58d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ use rocket::http::Method; use rocket_cors::{AllowedHeaders, AllowedOrigins}; pub mod auth; -pub mod rgi; +pub mod api; pub mod db; pub mod static_server; @@ -88,7 +88,7 @@ pub fn init() -> rocket::Rocket { rocket::ignite() .register(catchers![static_server::not_found]) .mount("/", routes![static_server::index, static_server::frontend, static_server::favicon, auth::me]) - .mount("/rgi/", rgi::routes()) + .mount("/api/", api::routes()) .attach(cors) .attach(DbConn::fairing()) } diff --git a/src/rgi b/src/rgi deleted file mode 120000 index e3ab9e5..0000000 --- a/src/rgi +++ /dev/null @@ -1 +0,0 @@ -../rgi/ \ No newline at end of file From 6ca68df11db28116c01f4436bf9ca986982a26ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 17:31:35 +0100 Subject: [PATCH 11/38] yeet deprecated code --- api/booking/booking.py | 44 +----------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/api/booking/booking.py b/api/booking/booking.py index 6fb75c5..3bd47f8 100755 --- a/api/booking/booking.py +++ b/api/booking/booking.py @@ -41,33 +41,6 @@ def default(self, obj): return json.JSONEncoder.default(self, obj) - -def get(data): - """ - Get data from the database - :param data: {id} - :return: Booking dictionary or {result: number} - """ - results = session.query(Booking).filter(Booking.id == data["args"]["id"]).all() - if len(results) == 1: - result = results[0] - user = session.query(Booking).filter(User.email == result.author).all() - setattr(result, "author_name", user[0].name) - return json.dumps(result, cls=AlchemyEncoder) - else: - return json.dumps({"result": 1}) - - -def list_(data): - """ - List all the data - :param data: - :return: {results: array of result} - """ - results = session.query(Booking).all() - return json.dumps(results, cls=AlchemyEncoder) - - def post(data): """ Adds new data to db @@ -132,21 +105,6 @@ def patch(data): else: return json.dumps({"result": 1}) # no result found by the id -def delete(data): - """ - Deletes event by it's id - :param data: {id} - :return: {result: number} - """ - - results = session.query(Booking).filter(Booking.id == data["args"]["id"]).all() - if len(results) == 1: - session.delete(results[0]) - session.commit() - return json.dumps({"result": 0}) - else: - return json.dumps({"result": 1}) # no result found by the id - def approve(data): """ Approvs event by it's id @@ -175,7 +133,7 @@ def approve(data): return json.dumps({"result": 1}) # no result found by the id -methods = {"list": list_, "get": get, "post": post, "patch": patch, "delete": delete, "approve" : approve} +methods = {"patch": patch, "approve" : approve} txt = sys.stdin.read() txt = re.sub(",[ \t\r\n]+}", "}", txt) txt = re.sub(",[ \t\r\n]+\]", "]", txt) From a3c2d57d6d0e013b9c23377f76ce45ea235a4d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 18:29:11 +0100 Subject: [PATCH 12/38] use sqlite connection pool --- api/booking/mod.rs | 20 ++++++++------------ src/db.rs | 2 ++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index c5f4eef..3a85b74 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -5,7 +5,7 @@ use crate::auth::AuthToken; use crate::auth::roles::{Noob, Approver, Role}; use crate::db; -use crate::db::{NewReservation, UpdateReservation, Reservation}; +use crate::db::{NewReservation, UpdateReservation, Reservation, DbConn}; use diesel::prelude::*; @@ -17,13 +17,11 @@ use diesel::prelude::*; /// /// GET /events "application/json" #[get("/events", format = "application/json")] -pub fn list() -> Option>> { +pub fn list(conn: DbConn) -> Option>> { use crate::schema::booking::dsl::*; - - let conn = db::get_con(); booking - .load::(&conn) + .load::((&*conn) as &diesel::SqliteConnection) .ok() .map(Json) } @@ -35,14 +33,12 @@ pub fn list() -> Option>> { /// parametry: /// - `id`: identifikátor dané rezervace #[get("/events/")] -pub fn get(event_id: i32, _u: AuthToken) -> Option> { +pub fn get(event_id: i32, conn: DbConn, _u: AuthToken) -> Option> { use crate::schema::booking::dsl::*; - let conn = db::get_con(); - booking .find(event_id) - .first::(&conn) + .first::((&*conn) as &diesel::SqliteConnection) .optional() .ok() .flatten() @@ -105,11 +101,11 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) - /// vymaže danou rezervaci /// -/// DEL/// +/// DELETE /events// /// parametry: /// - `id`: identifikátor dané rezervace #[delete("/events/")] -pub fn delete(r_id: i32, usr: AuthToken) -> Option<()> { +pub fn delete(r_id: i32, conn: DbConn, usr: AuthToken) -> Option<()> { use crate::schema::booking::dsl::*; // TODO return error instead of None on invalid states if r_id < 0 { @@ -167,6 +163,6 @@ pub fn approve(id: i32, _u: AuthToken) -> String { } /// vrací seznam endpointů pro nabindování do Rocketu -pub fn routes() -> Vec { +pub fn routes()conn: DbConn, -> Vec { routes![date_filter, list, approve, get, post, patch, delete,] } diff --git a/src/db.rs b/src/db.rs index a9f8b0d..e19af59 100644 --- a/src/db.rs +++ b/src/db.rs @@ -6,6 +6,8 @@ use serde::{Serialize, Deserialize}; use diesel::Connection; use std::env; +use std::ops::Deref; + use crate::schema::*; #[database("postgres_db")] From 4ebe7935b10129360e2628e094a0d77e5b9595c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 19:54:12 +0100 Subject: [PATCH 13/38] evil broken commit, inb4 committing heinous acts --- api/booking/booking.py | 1 - api/booking/mod.rs | 32 ++++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/api/booking/booking.py b/api/booking/booking.py index 3bd47f8..2577710 100755 --- a/api/booking/booking.py +++ b/api/booking/booking.py @@ -20,7 +20,6 @@ approver = "xsicp01@gjk.cz" - class AlchemyEncoder(json.JSONEncoder): def default(self, obj): diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 3a85b74..79ec86d 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -50,19 +50,27 @@ pub fn get(event_id: i32, conn: DbConn, _u: AuthToken) -> Option, usr: AuthToken) -> String { - let name = usr.user.name; - let user_id = usr.user.id; - let email = usr.user.email; +#[post("/events", data = "")] +pub fn post(input: Json, conn: DbConn, usr: AuthToken) -> Option<()> { + use crate::schema::booking::dsl::*; - rgi! { - POST "rgi/booking/booking.py" - arg: user_id, - arg: name, - arg: email - data: (&_input.into_inner()) + if booking + .filter(approved.eq(true)) + .filter(begin_time.le(input.end_time)) + .filter(end_time.ge(input.begin_time)) + .filter(rooms.eq(3).or(rooms.eq(input.rooms))) + .select(id) + .first::((&*conn) as &diesel::SqliteConnection) + .optional() + .is_some() + { + None? // TODO return propper error } + + diesel::insert_into(booking) + .values(input.into_inner()) + .execute((&*conn) as &diesel::SqliteConnection) + .ok()? } /// upraví danou rezervaci @@ -163,6 +171,6 @@ pub fn approve(id: i32, _u: AuthToken) -> String { } /// vrací seznam endpointů pro nabindování do Rocketu -pub fn routes()conn: DbConn, -> Vec { +pub fn routes() -> Vec { routes![date_filter, list, approve, get, post, patch, delete,] } From 86f5b69d3b1eec74c5871a10bdc20f4c48903338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 21:37:16 +0100 Subject: [PATCH 14/38] i am the magic man - remove diesel & sqlite - delete all migrations - delete schema - move models - use sled DB now - write own database access guard - declarative table access - other magic shit --- .env | 2 +- Cargo.lock | 258 ++++++++++++------ Cargo.toml | 6 +- Rocket.toml | 3 - api/booking/mod.rs | 61 +++-- diesel.toml | 5 - migrations/.gitkeep | 0 .../2019-11-26-164900_reservations/down.sql | 1 - .../2019-11-26-164900_reservations/up.sql | 12 - migrations/2019-11-28-112102_users/down.sql | 2 - migrations/2019-11-28-112102_users/up.sql | 8 - .../2019-11-28-120105_people_amount/down.sql | 1 - .../2019-11-28-120105_people_amount/up.sql | 3 - src/auth.rs | 9 +- src/db.rs | 198 ++++++-------- src/lib.rs | 20 +- src/models.rs | 118 ++++++++ src/schema.rs | 25 -- 18 files changed, 428 insertions(+), 304 deletions(-) delete mode 100644 diesel.toml delete mode 100644 migrations/.gitkeep delete mode 100644 migrations/2019-11-26-164900_reservations/down.sql delete mode 100644 migrations/2019-11-26-164900_reservations/up.sql delete mode 100644 migrations/2019-11-28-112102_users/down.sql delete mode 100644 migrations/2019-11-28-112102_users/up.sql delete mode 100644 migrations/2019-11-28-120105_people_amount/down.sql delete mode 100644 migrations/2019-11-28-120105_people_amount/up.sql create mode 100644 src/models.rs delete mode 100644 src/schema.rs diff --git a/.env b/.env index 073a82a..ac8dadb 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -DATABASE_URL="auditorium_booking.sqlite3" +DATABASE_URL="auditorium__booking.sled.db" diff --git a/Cargo.lock b/Cargo.lock index 151dfc9..609e034 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,14 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.13" @@ -27,13 +35,15 @@ name = "backend" version = "0.1.0" dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "diesel 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket_cors 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "sled 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -58,6 +68,16 @@ name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bincode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -97,6 +117,44 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "devise" version = "0.2.0" @@ -126,27 +184,6 @@ dependencies = [ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "diesel" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "diesel_derives 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dotenv" version = "0.15.0" @@ -163,6 +200,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fsevent" version = "0.4.0" @@ -194,6 +240,19 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "half" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "hermit-abi" version = "0.1.3" @@ -303,15 +362,6 @@ name = "libc" version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libsqlite3-sys" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lock_api" version = "0.3.2" @@ -351,6 +401,14 @@ name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memoffset" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mime" version = "0.2.6" @@ -409,6 +467,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "notify" version = "4.0.14" @@ -438,23 +501,25 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.10.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.7.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -483,11 +548,6 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pkg-config" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc-macro2" version = "0.4.30" @@ -520,16 +580,6 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "r2d2" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scheduled-thread-pool 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" version = "0.1.56" @@ -600,27 +650,13 @@ name = "rocket_contrib" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diesel 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)", - "r2d2 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket_contrib_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rocket_contrib_codegen" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rocket_cors" version = "0.5.1" @@ -652,6 +688,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ryu" version = "1.0.2" @@ -671,16 +715,21 @@ dependencies = [ ] [[package]] -name = "scheduled-thread-pool" -version = "0.2.3" +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "scopeguard" -version = "1.0.0" +name = "semver-parser" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -691,6 +740,24 @@ dependencies = [ "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_bytes" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_cbor" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_derive" version = "1.0.103" @@ -716,6 +783,25 @@ name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "sled" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "smallvec" version = "0.6.13" @@ -856,11 +942,6 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "vcpkg" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "version_check" version = "0.1.5" @@ -939,28 +1020,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cookie 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99be24cfcf40d56ed37fd11c2123be833959bbc5bddecb46e1c2e442e15fa3e0" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3" "checksum devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7" "checksum devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487" -"checksum diesel 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d7cc03b910de9935007861dce440881f69102aaaedfd4bc5a6f40340ca5840c" -"checksum diesel_derives 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" "checksum dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" +"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" "checksum fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +"checksum half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ff54597ea139063f4225f1ec47011b03c9de4a486957ff3fc506881dac951d0" "checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" @@ -975,31 +1063,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25" "checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" "checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "199628fc33b21bc767baa057490b00b382ecbae030803a7b36292422d15b778b" "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" -"checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" -"checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c26d2b92e47063ffce70d3e3b1bd097af121a9e0db07ca38a6cc1cf0cc85ff25" "checksum pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "336db4a192cc7f54efeb0c4e11a9245394824cc3bcbd37ba3ff51240c35d7a6e" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum r2d2 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "22b5c5fc5fba064373f03887337b412e0e1562d63023393db77251146cb75553" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" @@ -1007,18 +1094,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "42c1e9deb3ef4fa430d307bfccd4231434b707ca1328fae339c43ad1201cc6f7" "checksum rocket_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "79aa1366f9b2eccddc05971e17c5de7bb75a5431eb12c2b5c66545fd348647f4" "checksum rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e0fa5c1392135adc0f96a02ba150ac4c765e27c58dbfd32aa40678e948f6e56f" -"checksum rocket_contrib_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "343da6694fc3cfd901242fd6efafc823e7a3a7f4948017a7dda7311775055092" "checksum rocket_cors 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "270a960cba5a0b7928ad74268db7773ce932da6b550478383cefebe9f46c4e13" "checksum rocket_http 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1391457ee4e80b40d4b57fa5765c0f2836b20d73bcbee4e3f35d93cf3b80817" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" -"checksum scheduled-thread-pool 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f5de7bc31f28f8e6c28df5e1bf3d10610f5fdc14cc95f272853512c70a2bd779" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" +"checksum serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45af0182ff64abaeea290235eb67da3825a576c5d53e642c4d5b652e12e6effc" +"checksum serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7081ed758ec726a6ed8ee7e92f5d3f6e6f8c3901b1f972e3a4a2f2599fad14f" "checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" "checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum sled 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d7c3453de0f6a77abdd17cc9f68d6650214abd088b052b13302f86fa9a5b286e" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" "checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028" @@ -1038,7 +1129,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" diff --git a/Cargo.toml b/Cargo.toml index 5099664..3e7e3f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,15 @@ edition = "2018" [dependencies] rocket = "0.4.2" dotenv = "0.15.0" -diesel = "1.4.3" serde = { version = "1.0.103", features = ["derive"] } serde_json = "1.0.42" rocket_cors = "0.5.1" base64 = "0.11.0" +sled = "0.29" +lazy_static = "1.4" +serde_cbor = "0.10.2" [dependencies.rocket_contrib] version = "0.4.2" default-features = false -features = ["diesel_sqlite_pool", "json"] +features = ["json"] diff --git a/Rocket.toml b/Rocket.toml index 64d6599..337b8f2 100644 --- a/Rocket.toml +++ b/Rocket.toml @@ -1,5 +1,2 @@ -[global.databases] -postgres_db = { url = "auditorium_booking.sqlite3" } - [production] port = 8000 diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 79ec86d..5fe9d03 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -1,13 +1,19 @@ use rocket::Route; use rocket_contrib::json::Json; +use serde_cbor; + use crate::auth::AuthToken; use crate::auth::roles::{Noob, Approver, Role}; -use crate::db; -use crate::db::{NewReservation, UpdateReservation, Reservation, DbConn}; -use diesel::prelude::*; +use crate::db::{ + Database, + table::Reservations, + table::Users, +}; + +use crate::models::{NewReservation, UpdateReservation, Reservation}; /* ** TODO proper type for response, handle RGI responses @@ -17,13 +23,16 @@ use diesel::prelude::*; /// /// GET /events "application/json" #[get("/events", format = "application/json")] -pub fn list(conn: DbConn) -> Option>> { - use crate::schema::booking::dsl::*; - - booking - .load::((&*conn) as &diesel::SqliteConnection) - .ok() - .map(Json) +pub fn list(db: Database) -> Json> { + Json( + db.read().iter() + .filter_map(|r| r.ok()) + .map(|(k, v)| (serde_cbor::from_slice(&k), (serde_cbor::from_slice(&v)))) + // omit invalid data + .filter(|(a, b)| a.is_ok() && b.is_ok()) + .map(|(a, b)| (a.unwrap(), b.unwrap())) + .collect::>() + ) } /// vrátí JSON dané rezervace @@ -33,15 +42,11 @@ pub fn list(conn: DbConn) -> Option>> { /// parametry: /// - `id`: identifikátor dané rezervace #[get("/events/")] -pub fn get(event_id: i32, conn: DbConn, _u: AuthToken) -> Option> { - use crate::schema::booking::dsl::*; - - booking - .find(event_id) - .first::((&*conn) as &diesel::SqliteConnection) - .optional() - .ok() - .flatten() +pub fn get(event_id: u64, db: Database, _u: AuthToken) -> Option> { + db.read() + .get(serde_cbor::to_vec(&event_id).unwrap()) // can't fail + .ok()? + .map(|x| serde_cbor::from_slice(&x).ok())? .map(Json) } @@ -51,8 +56,8 @@ pub fn get(event_id: i32, conn: DbConn, _u: AuthToken) -> Option, conn: DbConn, usr: AuthToken) -> Option<()> { - use crate::schema::booking::dsl::*; +pub fn post(input: Json, usr: AuthToken) -> Option<()> { + /*use crate::schema::booking::dsl::*; if booking .filter(approved.eq(true)) @@ -70,7 +75,8 @@ pub fn post(input: Json, conn: DbConn, usr: AuthToken) -> diesel::insert_into(booking) .values(input.into_inner()) .execute((&*conn) as &diesel::SqliteConnection) - .ok()? + .ok()?*/ + unimplemented!() } /// upraví danou rezervaci @@ -83,6 +89,7 @@ pub fn post(input: Json, conn: DbConn, usr: AuthToken) -> /// data:[`UpdateReservation`] #[patch("/events/", data = "<_input>")] pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Option { +/* // TODO return error instead of None on invalid states if r_id < 0 { None? @@ -105,6 +112,8 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) - arg: id data: (&_input.into_inner()) }) +*/ + unimplemented!() } /// vymaže danou rezervaci @@ -113,8 +122,8 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) - /// parametry: /// - `id`: identifikátor dané rezervace #[delete("/events/")] -pub fn delete(r_id: i32, conn: DbConn, usr: AuthToken) -> Option<()> { - use crate::schema::booking::dsl::*; +pub fn delete(r_id: i32, usr: AuthToken) -> Option<()> { +/* use crate::schema::booking::dsl::*; // TODO return error instead of None on invalid states if r_id < 0 { None? @@ -126,7 +135,7 @@ pub fn delete(r_id: i32, conn: DbConn, usr: AuthToken) -> Option<()> { let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; if reservation.author.trim() != usr.user.email.trim() { - None? // you shouldn't be able to delete others' either + None? // you shouldn't be able to delete others' either } } @@ -136,6 +145,8 @@ pub fn delete(r_id: i32, conn: DbConn, usr: AuthToken) -> Option<()> { .execute(&conn) .ok() .map(|_| ()) +*/ + unimplemented!() } /// filtruje podle data diff --git a/diesel.toml b/diesel.toml deleted file mode 100644 index 92267c8..0000000 --- a/diesel.toml +++ /dev/null @@ -1,5 +0,0 @@ -# For documentation on how to configure this file, -# see diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schema.rs" diff --git a/migrations/.gitkeep b/migrations/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/migrations/2019-11-26-164900_reservations/down.sql b/migrations/2019-11-26-164900_reservations/down.sql deleted file mode 100644 index 8b807d3..0000000 --- a/migrations/2019-11-26-164900_reservations/down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE "booking" diff --git a/migrations/2019-11-26-164900_reservations/up.sql b/migrations/2019-11-26-164900_reservations/up.sql deleted file mode 100644 index 71a07a0..0000000 --- a/migrations/2019-11-26-164900_reservations/up.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE "booking" ( - "id" INTEGER NOT NULL UNIQUE, - "name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "author" TEXT NOT NULL, - "rooms" INTEGER NOT NULL, - "begin_time" TEXT NOT NULL, - "end_time" TEXT NOT NULL, - "layout" INTEGER NOT NULL, - "approved" INTEGER NOT NULL, - PRIMARY KEY("id") -); diff --git a/migrations/2019-11-28-112102_users/down.sql b/migrations/2019-11-28-112102_users/down.sql deleted file mode 100644 index e60ba1b..0000000 --- a/migrations/2019-11-28-112102_users/down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- This file should undo anything in `up.sql` -DROP TABLE "users" diff --git a/migrations/2019-11-28-112102_users/up.sql b/migrations/2019-11-28-112102_users/up.sql deleted file mode 100644 index 2fd6966..0000000 --- a/migrations/2019-11-28-112102_users/up.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Your SQL goes here -CREATE TABLE "users" ( - "id" INTEGER NOT NULL UNIQUE, - "name" TEXT NOT NULL, - "email" TEXT NOT NULL, - "role" TEXT NOT NULL, - PRIMARY KEY("id") -) diff --git a/migrations/2019-11-28-120105_people_amount/down.sql b/migrations/2019-11-28-120105_people_amount/down.sql deleted file mode 100644 index 291a97c..0000000 --- a/migrations/2019-11-28-120105_people_amount/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/migrations/2019-11-28-120105_people_amount/up.sql b/migrations/2019-11-28-120105_people_amount/up.sql deleted file mode 100644 index 12b8a6a..0000000 --- a/migrations/2019-11-28-120105_people_amount/up.sql +++ /dev/null @@ -1,3 +0,0 @@ --- Your SQL goes here -ALTER TABLE "booking" - ADD COLUMN "people" UNSIGNED INT NOT NULL DEFAULT '0'; diff --git a/src/auth.rs b/src/auth.rs index 40e03ba..2c06af7 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -17,12 +17,10 @@ use rocket::http::Status; use base64::decode; -use diesel::prelude::*; - use std::marker::PhantomData; use crate::db; -use crate::db::{NewUser, User}; +use crate::models::{NewUser, User}; /// autorizační token, tak jak je přijat #[derive(Serialize, Deserialize)] @@ -94,7 +92,7 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { type Error = String; fn from_request(request: &'a Request<'r>) -> Outcome { - use crate::schema::users::dsl::*; + /*use crate::schema::users::dsl::*; let keys: Vec<_> = request.headers().get("Authorization").collect(); match keys.get(0).unwrap_or(&"").split(' ').nth(1) { @@ -162,7 +160,8 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { println!("{:?}", x); Outcome::Failure((Status::BadRequest, "invalid authorization header".to_string())) } - } + }*/ + unimplemented!() } } diff --git a/src/db.rs b/src/db.rs index e19af59..96f1a01 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,136 +1,100 @@ //! obsahuje modely //! pro přidávání nového modelu viz [dokumentace Diesel ORM](https://diesel.rs) -use rocket_contrib::databases::diesel; +use rocket::request::{FromRequest, Request, Outcome}; +use rocket::http::Status; + use serde::{Serialize, Deserialize}; -use diesel::Connection; +use sled::{Db, Tree}; use std::env; use std::ops::Deref; +use std::sync::RwLock; +use std::marker::PhantomData; -use crate::schema::*; +lazy_static! { + /// a global handle to the Sled database + pub static ref DB: RwLock = RwLock::new({ + let db = Db::open(&env::var("DATABASE_URL").expect("failed to read DATABASE_URL environment variable")) + .expect("failed to open database"); + db + }); +} -#[database("postgres_db")] -pub struct DbConn(diesel::SqliteConnection); +/// wraps the database +/// +/// the reasons are two: +/// 1. to allow FromRequest implementation +/// 2. declarative table access +pub struct Database(Tree, PhantomData); -/// vrací připojení k databázi -pub fn get_con() -> diesel::SqliteConnection { - diesel::SqliteConnection::establish(&env::var("DATABASE_URL").expect("DATABASE_URL not in env")) - .expect("error connecting to db") +impl Database { + /// read-only access to tree + pub fn read(&self) -> &Tree { &self.0 } + /// read and write access to tree + pub fn write(&mut self) -> &mut Tree { &mut self.0 } } -/// Model rezervace, tak jak je uložena v databázi -#[derive(Queryable, Debug, Clone, Serialize, Deserialize)] -pub struct Reservation { - /// primární klíč - pub id: i32, - /// název události - pub name: String, - /// popis události - pub description: String, - /// "rezervujitel" události :^) - pub author: String, - /// místnosti, které si "rezervujitel" přeje zarezervovat - /// - /// funguje na bázi bitflagů: - /// ``` - /// 0b00 -> žádná místnosti (nemělo by se stát :D) - /// 0b01 -> north - /// 0b10 -> south - /// 0b11 -> celé auditorium - /// ``` - pub rooms: i32, - /// počáteční čas rezervace - pub begin_time: String, - /// čas, kdy rezervace končí - pub end_time: String, - /// rozložení nábytku v audioriu - pub layout: i32, - /// zda byla rezervace schválena - pub approved: i32, - /// počet lidí - pub people: i32, -} +/// trait for the Table marker types +pub trait Table { + /// opening a table might not always work, + /// this type should explain what's the issue + type TableError = sled::Error; -/// Model rezervace pro přidání do databáze -#[derive(Serialize, Deserialize, Debug, Clone)] -#[allow(dead_code)] -pub struct NewReservation { - /// název události - pub name: String, - /// popis události - pub description: String, - /// místnosti, které si "rezervujitel" přeje zarezervovat - /// - /// funguje na bázi bitflagů: - /// ``` - /// 0b00 -> žádná místnosti (nemělo by se stát :D) - /// 0b01 -> north - /// 0b10 -> south - /// 0b11 -> celé auditorium - /// ``` - pub rooms: u8, - /// počáteční čas rezervace - pub begin_time: String, - /// čas, kdy rezervace končí - pub end_time: String, - /// rozložení nábytku v audioriu - pub layout: u16, - /// počet lidí - pub people: u16, -} + /// name (actually prefix) of the table + fn name() -> &'static str; + /// gets the actual tree, should do it using the global DB handle + fn get_tree_naive() -> Result { + let lock = DB.read() + .expect("the database rwlock has been poisoned"); + // ^ this usually implies a deeper underlying problem, + // so it's probably okay to hard crash + + lock.open_tree(&Self::name()) + } -/// Weird quick models -#[derive(Serialize, Deserialize, Debug, Clone)] -#[allow(dead_code)] -pub struct UpdateReservation { - /// název události - pub name: Option, - /// popis události - pub description: Option, - /// místnosti, které si "rezervujitel" přeje zarezervovat - /// - /// funguje na bázi bitflagů: - /// ``` - /// 0b00 -> žádná místnosti (nemělo by se stát :D) - /// 0b01 -> north - /// 0b10 -> south - /// 0b11 -> celé auditorium - /// ``` - pub rooms: Option, - /// počáteční čas rezervace - pub begin_time: Option, - /// čas, kdy rezervace končí - pub end_time: Option, - /// rozložení nábytku v audioriu - pub layout: Option, - /// počet lidí - pub people: Option, + /// should return true if a custom get tree function is available + fn has_get_tree() -> bool { false } + + /// optional custom function for fetching a tree, + /// can call [`Table::get_tree_naive`] + fn get_tree() -> Result { unimplemented!() } } -/// Model usera -#[derive(Serialize, Deserialize, Debug, Clone, Queryable)] -#[allow(dead_code)] -pub struct User { - /// identifikátor - pub id: i32, - /// jméno uživatele - pub name: String, - /// email - pub email: String, - /// role - pub role: String, +/// module containing table markers +pub mod table { + use super::Table; + + /// Reservation database table marker + pub struct Reservations; + + impl Table for Reservations { + fn name() -> &'static str { "reservation" } + } + + /// Users database table marker + pub struct Users; + + impl Table for Users { + fn name() -> &'static str { "user" } + } } -/// Model usera pro vložení do databáze -#[derive(Serialize, Deserialize, Debug, Clone, Insertable)] -#[table_name = "users"] -#[allow(dead_code)] -pub struct NewUser { - /// jmeno - pub name: String, - /// email - pub email: String, - /// role - pub role: String, +impl<'a, 'r, T: Table> FromRequest<'a, 'r> for Database { + type Error = String; + + fn from_request(_: &'a Request<'r>) -> Outcome { + if T::has_get_tree() { + match T::get_tree() { + Ok(tree) => Outcome::Success(Database(tree, PhantomData)), + Err(_) => Outcome::Failure((Status::InternalServerError, "failed to run custom database function and acquire tree".to_string())), + } + } else { + match T::get_tree_naive() { + Ok(tree) => Outcome::Success(Database(tree, PhantomData)), + Err(_) => Outcome::Failure((Status::InternalServerError, "failed to acquire tree".to_string())), + } + } + } } + diff --git a/src/lib.rs b/src/lib.rs index 9fd58d3..f3edfa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ //! └── static_server.rs - statický server //! ``` #![feature(proc_macro_hygiene, decl_macro)] +#![feature(associated_type_defaults)] #![allow(clippy::match_bool)] #![deny(missing_docs)] @@ -47,25 +48,25 @@ extern crate rocket; #[macro_use] extern crate rocket_contrib; + #[macro_use] -extern crate diesel; +extern crate lazy_static; + +extern crate serde_cbor; extern crate dotenv; +extern crate serde; +extern crate sled; use dotenv::dotenv; use rocket::http::Method; use rocket_cors::{AllowedHeaders, AllowedOrigins}; +pub mod static_server; pub mod auth; pub mod api; -pub mod db; -pub mod static_server; - -/// schéma databáze (vygenerováno Dieselem) -#[allow(missing_docs)] -pub mod schema; - -use db::DbConn; +pub mod db; +pub mod models; /// Vrací instanci Rocketu pub fn init() -> rocket::Rocket { dotenv().ok(); @@ -90,5 +91,4 @@ pub fn init() -> rocket::Rocket { .mount("/", routes![static_server::index, static_server::frontend, static_server::favicon, auth::me]) .mount("/api/", api::routes()) .attach(cors) - .attach(DbConn::fairing()) } diff --git a/src/models.rs b/src/models.rs new file mode 100644 index 0000000..5ae7384 --- /dev/null +++ b/src/models.rs @@ -0,0 +1,118 @@ +//! contains database models and helper structs + +use serde::{Serialize, Deserialize}; + +/// Model rezervace, tak jak je uložena v databázi +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Reservation { + /// primární klíč + pub id: i32, + /// název události + pub name: String, + /// popis události + pub description: String, + /// "rezervujitel" události :^) + pub author: String, + /// místnosti, které si "rezervujitel" přeje zarezervovat + /// + /// funguje na bázi bitflagů: + /// ``` + /// 0b00 -> žádná místnosti (nemělo by se stát :D) + /// 0b01 -> north + /// 0b10 -> south + /// 0b11 -> celé auditorium + /// ``` + pub rooms: i32, + /// počáteční čas rezervace + pub begin_time: String, + /// čas, kdy rezervace končí + pub end_time: String, + /// rozložení nábytku v audioriu + pub layout: i32, + /// zda byla rezervace schválena + pub approved: i32, + /// počet lidí + pub people: i32, +} + +/// Model rezervace pro přidání do databáze +#[derive(Serialize, Deserialize, Debug, Clone)] +#[allow(dead_code)] +pub struct NewReservation { + /// název události + pub name: String, + /// popis události + pub description: String, + /// místnosti, které si "rezervujitel" přeje zarezervovat + /// + /// funguje na bázi bitflagů: + /// ``` + /// 0b00 -> žádná místnosti (nemělo by se stát :D) + /// 0b01 -> north + /// 0b10 -> south + /// 0b11 -> celé auditorium + /// ``` + pub rooms: u8, + /// počáteční čas rezervace + pub begin_time: String, + /// čas, kdy rezervace končí + pub end_time: String, + /// rozložení nábytku v audioriu + pub layout: u16, + /// počet lidí + pub people: u16, +} + +/// Weird quick models +#[derive(Serialize, Deserialize, Debug, Clone)] +#[allow(dead_code)] +pub struct UpdateReservation { + /// název události + pub name: Option, + /// popis události + pub description: Option, + /// místnosti, které si "rezervujitel" přeje zarezervovat + /// + /// funguje na bázi bitflagů: + /// ``` + /// 0b00 -> žádná místnosti (nemělo by se stát :D) + /// 0b01 -> north + /// 0b10 -> south + /// 0b11 -> celé auditorium + /// ``` + pub rooms: Option, + /// počáteční čas rezervace + pub begin_time: Option, + /// čas, kdy rezervace končí + pub end_time: Option, + /// rozložení nábytku v audioriu + pub layout: Option, + /// počet lidí + pub people: Option, +} + +/// Model usera +#[derive(Serialize, Deserialize, Debug, Clone)] +#[allow(dead_code)] +pub struct User { + /// identifikátor + pub id: i32, + /// jméno uživatele + pub name: String, + /// email + pub email: String, + /// role + pub role: String, +} + +/// Model usera pro vložení do databáze +#[derive(Serialize, Deserialize, Debug, Clone)] +#[allow(dead_code)] +pub struct NewUser { + /// jmeno + pub name: String, + /// email + pub email: String, + /// role + pub role: String, +} diff --git a/src/schema.rs b/src/schema.rs deleted file mode 100644 index df1ed25..0000000 --- a/src/schema.rs +++ /dev/null @@ -1,25 +0,0 @@ -table! { - booking (id) { - id -> Integer, - name -> Text, - description -> Text, - author -> Text, - rooms -> Integer, - begin_time -> Text, - end_time -> Text, - layout -> Integer, - approved -> Integer, - people -> Integer, - } -} - -table! { - users (id) { - id -> Integer, - name -> Text, - email -> Text, - role -> Text, - } -} - -allow_tables_to_appear_in_same_query!(booking, users,); From 514e50f1b968d97d4a5f91d24675ba0ba5c58187 Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Sat, 30 Nov 2019 21:53:29 +0100 Subject: [PATCH 15/38] typo --- src/auth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth.rs b/src/auth.rs index 2c06af7..d45573b 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -63,7 +63,7 @@ pub mod roles { pub trait Role { /// jméno role jako string fn name() -> &'static str; - /// jméno rodiše jako string + /// jméno rodiče jako string fn daddy() -> Option<&'static str> { None } From 7bf34015c2578571bab334ec155e3986eee64dad Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Sat, 30 Nov 2019 21:58:25 +0100 Subject: [PATCH 16/38] types --- src/models.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/models.rs b/src/models.rs index 5ae7384..9807c19 100644 --- a/src/models.rs +++ b/src/models.rs @@ -6,7 +6,7 @@ use serde::{Serialize, Deserialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Reservation { /// primární klíč - pub id: i32, + pub id: u64, /// název události pub name: String, /// popis události @@ -22,17 +22,17 @@ pub struct Reservation { /// 0b10 -> south /// 0b11 -> celé auditorium /// ``` - pub rooms: i32, + pub rooms: u8, /// počáteční čas rezervace pub begin_time: String, /// čas, kdy rezervace končí pub end_time: String, /// rozložení nábytku v audioriu - pub layout: i32, + pub layout: u8, /// zda byla rezervace schválena - pub approved: i32, + pub approved: bool, /// počet lidí - pub people: i32, + pub people: i8, } /// Model rezervace pro přidání do databáze @@ -58,9 +58,9 @@ pub struct NewReservation { /// čas, kdy rezervace končí pub end_time: String, /// rozložení nábytku v audioriu - pub layout: u16, + pub layout: u8, /// počet lidí - pub people: u16, + pub people: u8, } /// Weird quick models @@ -86,9 +86,9 @@ pub struct UpdateReservation { /// čas, kdy rezervace končí pub end_time: Option, /// rozložení nábytku v audioriu - pub layout: Option, + pub layout: Option, /// počet lidí - pub people: Option, + pub people: Option, } /// Model usera @@ -96,7 +96,7 @@ pub struct UpdateReservation { #[allow(dead_code)] pub struct User { /// identifikátor - pub id: i32, + pub id: u64, /// jméno uživatele pub name: String, /// email From 464d90895dd85b36b32d009c6794bdf00785bad0 Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Sat, 30 Nov 2019 22:12:42 +0100 Subject: [PATCH 17/38] authtoken --- src/models.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/models.rs b/src/models.rs index 9807c19..815e09a 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,6 +1,7 @@ //! contains database models and helper structs use serde::{Serialize, Deserialize}; +use auth::AuthToken; /// Model rezervace, tak jak je uložena v databázi #[derive(Debug, Clone, Serialize, Deserialize)] @@ -102,7 +103,7 @@ pub struct User { /// email pub email: String, /// role - pub role: String, + pub role: AuthToken, } /// Model usera pro vložení do databáze @@ -114,5 +115,5 @@ pub struct NewUser { /// email pub email: String, /// role - pub role: String, + pub role: AuthToken, } From fc6a80021169bcae2986779ec2c6310566c7668c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 23:08:05 +0100 Subject: [PATCH 18/38] fully typesafe DB access --- Cargo.lock | 31 +++++++++++++++++++ Cargo.toml | 1 + api/booking/mod.rs | 25 ++++++++++------ src/db.rs | 75 ++++++++++++++++++++++++++++++++++++++++++---- src/lib.rs | 1 + 5 files changed, 118 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 609e034..9314843 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,7 @@ name = "backend" version = "0.1.0" dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -98,6 +99,16 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -490,6 +501,23 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num_cpus" version = "1.11.1" @@ -1031,6 +1059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cookie 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99be24cfcf40d56ed37fd11c2123be833959bbc5bddecb46e1c2e442e15fa3e0" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" @@ -1077,6 +1106,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "199628fc33b21bc767baa057490b00b382ecbae030803a7b36292422d15b778b" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" diff --git a/Cargo.toml b/Cargo.toml index 3e7e3f8..28d1da8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ base64 = "0.11.0" sled = "0.29" lazy_static = "1.4" serde_cbor = "0.10.2" +chrono = "0.4.10" [dependencies.rocket_contrib] version = "0.4.2" diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 5fe9d03..8d3f575 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -2,6 +2,7 @@ use rocket::Route; use rocket_contrib::json::Json; use serde_cbor; +use chrono::DateTime; use crate::auth::AuthToken; use crate::auth::roles::{Noob, Approver, Role}; @@ -26,11 +27,6 @@ use crate::models::{NewReservation, UpdateReservation, Reservation}; pub fn list(db: Database) -> Json> { Json( db.read().iter() - .filter_map(|r| r.ok()) - .map(|(k, v)| (serde_cbor::from_slice(&k), (serde_cbor::from_slice(&v)))) - // omit invalid data - .filter(|(a, b)| a.is_ok() && b.is_ok()) - .map(|(a, b)| (a.unwrap(), b.unwrap())) .collect::>() ) } @@ -44,9 +40,7 @@ pub fn list(db: Database) -> Json> { #[get("/events/")] pub fn get(event_id: u64, db: Database, _u: AuthToken) -> Option> { db.read() - .get(serde_cbor::to_vec(&event_id).unwrap()) // can't fail - .ok()? - .map(|x| serde_cbor::from_slice(&x).ok())? + .get(event_id) // can't fail .map(Json) } @@ -56,7 +50,20 @@ pub fn get(event_id: u64, db: Database, _u: AuthToken) -> Op /// /// data: [`NewReservation`] #[post("/events", data = "")] -pub fn post(input: Json, usr: AuthToken) -> Option<()> { +pub fn post(input: Json, db: Database, usr: AuthToken) -> Option<()> { + if db.read() + .iter() + .filter(|(_, x)| x.approved == 1) + // todo time-checking + //&& (x.rooms == 3 || x.rooms == input.rooms)) + .count() != 0 + { + None? + } + + //db.write() + // .insert + /*use crate::schema::booking::dsl::*; if booking diff --git a/src/db.rs b/src/db.rs index 96f1a01..a9a4cef 100644 --- a/src/db.rs +++ b/src/db.rs @@ -6,12 +6,16 @@ use rocket::http::Status; use serde::{Serialize, Deserialize}; use sled::{Db, Tree}; +use serde_cbor; use std::env; -use std::ops::Deref; use std::sync::RwLock; +use std::borrow::Borrow; +use std::iter::Iterator; +use std::iter::FilterMap; use std::marker::PhantomData; + lazy_static! { /// a global handle to the Sled database pub static ref DB: RwLock = RwLock::new({ @@ -21,18 +25,68 @@ lazy_static! { }); } +/// manages a tree and ensures it's type safety +/// also allows automatic type conversions +pub struct TreeMan +where + for <'a> K: Serialize + Deserialize<'a>, + for <'b> V: Serialize + Deserialize<'b>, +{ + tree: Tree, + _k: PhantomData, + _v: PhantomData, +} + +impl TreeMan +where + for <'a> K: Serialize + Deserialize<'a>, + for <'b> V: Serialize + Deserialize<'b>, +{ + /// create a new tree manager from a tree + pub fn from_tree(tree: Tree) -> Self { + Self { tree, _k: PhantomData, _v: PhantomData } + } + + /// creates an iterator over (K, V) + pub fn iter(&self) -> impl Iterator { + self.tree + .iter() + .filter_map(|res| { + if let Ok((k, v)) = res { + Some((serde_cbor::from_slice::(&k).ok()?, serde_cbor::from_slice::(&v).ok()?)) + } else { None } + }) + } + + /// try to get a value from the database + pub fn get>(&self, k: Key) -> Option { + self.tree + .get(serde_cbor::to_vec(k.borrow()).unwrap()) // can't fail + .ok() + .flatten() + .and_then(|v| Some(serde_cbor::from_slice::(&*v).ok())) + .flatten() + } + + /// try to insert into database + pub fn insert, Value: Borrow>(&mut self, k: Key, v: Value) -> sled::Result> { + self.tree + .insert(serde_cbor::to_vec(k.borrow()).unwrap(), serde_cbor::to_vec(v.borrow()).unwrap()) // can't fail + } +} + /// wraps the database /// /// the reasons are two: /// 1. to allow FromRequest implementation /// 2. declarative table access -pub struct Database(Tree, PhantomData); +pub struct Database(TreeMan, PhantomData); impl Database { /// read-only access to tree - pub fn read(&self) -> &Tree { &self.0 } + pub fn read(&self) -> &TreeMan { &self.0 } /// read and write access to tree - pub fn write(&mut self) -> &mut Tree { &mut self.0 } + pub fn write(&mut self) -> &mut TreeMan { &mut self.0 } } /// trait for the Table marker types @@ -40,6 +94,10 @@ pub trait Table { /// opening a table might not always work, /// this type should explain what's the issue type TableError = sled::Error; + /// type of the key/ID + type Key: Serialize + for<'a> Deserialize<'a>; + /// type of the value + type Value: Serialize + for<'b> Deserialize<'b>; /// name (actually prefix) of the table fn name() -> &'static str; @@ -64,11 +122,14 @@ pub trait Table { /// module containing table markers pub mod table { use super::Table; + use crate::models::{Reservation, User}; /// Reservation database table marker pub struct Reservations; impl Table for Reservations { + type Key = u64; + type Value = Reservation; fn name() -> &'static str { "reservation" } } @@ -76,6 +137,8 @@ pub mod table { pub struct Users; impl Table for Users { + type Key = u64; + type Value = User; fn name() -> &'static str { "user" } } } @@ -86,12 +149,12 @@ impl<'a, 'r, T: Table> FromRequest<'a, 'r> for Database { fn from_request(_: &'a Request<'r>) -> Outcome { if T::has_get_tree() { match T::get_tree() { - Ok(tree) => Outcome::Success(Database(tree, PhantomData)), + Ok(t) => Outcome::Success(Database(TreeMan::from_tree(t), PhantomData)), Err(_) => Outcome::Failure((Status::InternalServerError, "failed to run custom database function and acquire tree".to_string())), } } else { match T::get_tree_naive() { - Ok(tree) => Outcome::Success(Database(tree, PhantomData)), + Ok(t) => Outcome::Success(Database(TreeMan::from_tree(t), PhantomData)), Err(_) => Outcome::Failure((Status::InternalServerError, "failed to acquire tree".to_string())), } } diff --git a/src/lib.rs b/src/lib.rs index f3edfa2..c3e4746 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,7 @@ extern crate lazy_static; extern crate serde_cbor; extern crate dotenv; +extern crate chrono; extern crate serde; extern crate sled; From 3133e7cd9115cff633fdd379ce45d9bcd4976060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 23:10:50 +0100 Subject: [PATCH 19/38] dawidfix --- api/booking/mod.rs | 2 +- src/models.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 8d3f575..6c3a574 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -53,7 +53,7 @@ pub fn get(event_id: u64, db: Database, _u: AuthToken) -> Op pub fn post(input: Json, db: Database, usr: AuthToken) -> Option<()> { if db.read() .iter() - .filter(|(_, x)| x.approved == 1) + .filter(|(_, x)| x.approved == true) // todo time-checking //&& (x.rooms == 3 || x.rooms == input.rooms)) .count() != 0 diff --git a/src/models.rs b/src/models.rs index 815e09a..25a2c05 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,7 +1,7 @@ //! contains database models and helper structs use serde::{Serialize, Deserialize}; -use auth::AuthToken; +use crate::auth::AuthToken; /// Model rezervace, tak jak je uložena v databázi #[derive(Debug, Clone, Serialize, Deserialize)] From 37eee5ddef8218ab30d6f7ce1fdef2fb588a5c9f Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Sat, 30 Nov 2019 23:17:27 +0100 Subject: [PATCH 20/38] database usage --- api/booking/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 6c3a574..8acc96b 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -95,7 +95,8 @@ pub fn post(input: Json, db: Database, usr: AuthTo /// /// data:[`UpdateReservation`] #[patch("/events/", data = "<_input>")] -pub fn patch(r_id: i32, _input: Json, usr: AuthToken) -> Option { +pub fn patch(r_id: i32, _input: Json, db: Database, usr: AuthToken) -> Option { + /* // TODO return error instead of None on invalid states if r_id < 0 { @@ -129,7 +130,7 @@ pub fn patch(r_id: i32, _input: Json, usr: AuthToken) - /// parametry: /// - `id`: identifikátor dané rezervace #[delete("/events/")] -pub fn delete(r_id: i32, usr: AuthToken) -> Option<()> { +pub fn delete(r_id: i32, db: Database, usr: AuthToken) -> Option<()> { /* use crate::schema::booking::dsl::*; // TODO return error instead of None on invalid states if r_id < 0 { @@ -165,7 +166,7 @@ pub fn delete(r_id: i32, usr: AuthToken) -> Option<()> { /// - `begin_time`: počáteční čas /// - `end_time`: čas konce #[get("/events/filter///")] -pub fn date_filter(rooms: i32, begin_time: String, end_time: String, _u: AuthToken) -> String { +pub fn date_filter(rooms: i32, begin_time: String, end_time: String, db: Database, _u: AuthToken) -> String { rgi! { FILTER "rgi/booking/booking.py" arg: rooms, @@ -181,7 +182,7 @@ pub fn date_filter(rooms: i32, begin_time: String, end_time: String, _u: AuthTok /// parametry: /// - `id`: id rezervace #[post("/events//approve")] -pub fn approve(id: i32, _u: AuthToken) -> String { +pub fn approve(id: i32, db: Database, _u: AuthToken) -> String { rgi! { APPROVE "rgi/booking/booking.py" arg: id From 33f86ebf2b47e0c3a74ac3c0049de3573f9fecf1 Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Sat, 30 Nov 2019 23:32:12 +0100 Subject: [PATCH 21/38] bang - it compiles --- api/booking/mod.rs | 11 ++++---- src/models.rs | 69 +++++++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 8acc96b..f5e4618 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -14,7 +14,7 @@ use crate::db::{ table::Users, }; -use crate::models::{NewReservation, UpdateReservation, Reservation}; +use crate::models::{NewReservation, UpdateReservation, Reservation, ID, TEXT, NUMBER}; /* ** TODO proper type for response, handle RGI responses @@ -95,7 +95,7 @@ pub fn post(input: Json, db: Database, usr: AuthTo /// /// data:[`UpdateReservation`] #[patch("/events/", data = "<_input>")] -pub fn patch(r_id: i32, _input: Json, db: Database, usr: AuthToken) -> Option { +pub fn patch(r_id: u64, _input: Json, db: Database, usr: AuthToken) -> Option { /* // TODO return error instead of None on invalid states @@ -130,7 +130,8 @@ pub fn patch(r_id: i32, _input: Json, db: Database")] -pub fn delete(r_id: i32, db: Database, usr: AuthToken) -> Option<()> { +pub fn delete(r_id: u64, db: Database, usr: AuthToken) -> Option<()> { + /* use crate::schema::booking::dsl::*; // TODO return error instead of None on invalid states if r_id < 0 { @@ -166,7 +167,7 @@ pub fn delete(r_id: i32, db: Database, usr: AuthToken) -> Op /// - `begin_time`: počáteční čas /// - `end_time`: čas konce #[get("/events/filter///")] -pub fn date_filter(rooms: i32, begin_time: String, end_time: String, db: Database, _u: AuthToken) -> String { +pub fn date_filter(rooms: u8, begin_time: String, end_time: String, db: Database, _u: AuthToken) -> String { rgi! { FILTER "rgi/booking/booking.py" arg: rooms, @@ -182,7 +183,7 @@ pub fn date_filter(rooms: i32, begin_time: String, end_time: String, db: Databas /// parametry: /// - `id`: id rezervace #[post("/events//approve")] -pub fn approve(id: i32, db: Database, _u: AuthToken) -> String { +pub fn approve(id: u64, db: Database, _u: AuthToken) -> String { rgi! { APPROVE "rgi/booking/booking.py" arg: id diff --git a/src/models.rs b/src/models.rs index 25a2c05..824af22 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,19 +1,26 @@ //! contains database models and helper structs use serde::{Serialize, Deserialize}; -use crate::auth::AuthToken; +use crate::auth::{AuthToken, roles::Role}; + +/// TYP ID!!! +pub type ID = u64; +/// DEFAULTNI CISELNY TYP!!! +pub type NUMBER = u8; +/// DEFAULTNI TEXTOVY TYP!!! +pub type TEXT = String; /// Model rezervace, tak jak je uložena v databázi #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Reservation { /// primární klíč - pub id: u64, + pub id: ID, /// název události - pub name: String, + pub name: TEXT, /// popis události - pub description: String, + pub description: TEXT, /// "rezervujitel" události :^) - pub author: String, + pub author: TEXT, /// místnosti, které si "rezervujitel" přeje zarezervovat /// /// funguje na bázi bitflagů: @@ -23,17 +30,17 @@ pub struct Reservation { /// 0b10 -> south /// 0b11 -> celé auditorium /// ``` - pub rooms: u8, + pub rooms: NUMBER, /// počáteční čas rezervace - pub begin_time: String, + pub begin_time: TEXT, /// čas, kdy rezervace končí - pub end_time: String, + pub end_time: TEXT, /// rozložení nábytku v audioriu - pub layout: u8, + pub layout: NUMBER, /// zda byla rezervace schválena pub approved: bool, /// počet lidí - pub people: i8, + pub people: NUMBER, } /// Model rezervace pro přidání do databáze @@ -41,9 +48,9 @@ pub struct Reservation { #[allow(dead_code)] pub struct NewReservation { /// název události - pub name: String, + pub name: TEXT, /// popis události - pub description: String, + pub description: TEXT, /// místnosti, které si "rezervujitel" přeje zarezervovat /// /// funguje na bázi bitflagů: @@ -53,15 +60,15 @@ pub struct NewReservation { /// 0b10 -> south /// 0b11 -> celé auditorium /// ``` - pub rooms: u8, + pub rooms: NUMBER, /// počáteční čas rezervace - pub begin_time: String, + pub begin_time: TEXT, /// čas, kdy rezervace končí - pub end_time: String, + pub end_time: TEXT, /// rozložení nábytku v audioriu - pub layout: u8, + pub layout: NUMBER, /// počet lidí - pub people: u8, + pub people: NUMBER, } /// Weird quick models @@ -69,9 +76,9 @@ pub struct NewReservation { #[allow(dead_code)] pub struct UpdateReservation { /// název události - pub name: Option, + pub name: Option, /// popis události - pub description: Option, + pub description: Option, /// místnosti, které si "rezervujitel" přeje zarezervovat /// /// funguje na bázi bitflagů: @@ -81,15 +88,15 @@ pub struct UpdateReservation { /// 0b10 -> south /// 0b11 -> celé auditorium /// ``` - pub rooms: Option, + pub rooms: Option, /// počáteční čas rezervace - pub begin_time: Option, + pub begin_time: Option, /// čas, kdy rezervace končí - pub end_time: Option, + pub end_time: Option, /// rozložení nábytku v audioriu - pub layout: Option, + pub layout: Option, /// počet lidí - pub people: Option, + pub people: Option, } /// Model usera @@ -97,13 +104,13 @@ pub struct UpdateReservation { #[allow(dead_code)] pub struct User { /// identifikátor - pub id: u64, + pub id: ID, /// jméno uživatele - pub name: String, + pub name: TEXT, /// email - pub email: String, + pub email: TEXT, /// role - pub role: AuthToken, + pub role: TEXT, } /// Model usera pro vložení do databáze @@ -111,9 +118,9 @@ pub struct User { #[allow(dead_code)] pub struct NewUser { /// jmeno - pub name: String, + pub name: TEXT, /// email - pub email: String, + pub email: TEXT, /// role - pub role: AuthToken, + pub role: TEXT, } From 6a66ad96869435a5d7836203f82559b16b3d92d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sat, 30 Nov 2019 23:36:06 +0100 Subject: [PATCH 22/38] smarter db, models and implement post --- Cargo.lock | 1 + Cargo.toml | 5 ++++- api/booking/mod.rs | 38 ++++++++++++-------------------------- src/db.rs | 5 +++++ src/models.rs | 34 ++++++++++++++++++++++++++-------- 5 files changed, 48 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9314843..3a89d77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 28d1da8..4a23350 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,10 @@ base64 = "0.11.0" sled = "0.29" lazy_static = "1.4" serde_cbor = "0.10.2" -chrono = "0.4.10" + +[dependencies.chrono] +version = "0.4.10" +features = ["serde"] [dependencies.rocket_contrib] version = "0.4.2" diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 6c3a574..4951d11 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -53,37 +53,23 @@ pub fn get(event_id: u64, db: Database, _u: AuthToken) -> Op pub fn post(input: Json, db: Database, usr: AuthToken) -> Option<()> { if db.read() .iter() - .filter(|(_, x)| x.approved == true) - // todo time-checking - //&& (x.rooms == 3 || x.rooms == input.rooms)) - .count() != 0 + .filter(|(_, x)| + x.approved == true + && x.begin_time <= input.end_time + && x.end_time >= input.begin_time + && (x.rooms == 3 || x.rooms == input.rooms) + ) + .any() { - None? + return None; // todo proper errors } - //db.write() - // .insert + let mut new_res = input.into_inner().into(); - /*use crate::schema::booking::dsl::*; + new_res.author = usr.email; - if booking - .filter(approved.eq(true)) - .filter(begin_time.le(input.end_time)) - .filter(end_time.ge(input.begin_time)) - .filter(rooms.eq(3).or(rooms.eq(input.rooms))) - .select(id) - .first::((&*conn) as &diesel::SqliteConnection) - .optional() - .is_some() - { - None? // TODO return propper error - } - - diesel::insert_into(booking) - .values(input.into_inner()) - .execute((&*conn) as &diesel::SqliteConnection) - .ok()?*/ - unimplemented!() + db.write() + .insert(Database::get_key().unwrap(), new_res) } /// upraví danou rezervaci diff --git a/src/db.rs b/src/db.rs index a9a4cef..7257907 100644 --- a/src/db.rs +++ b/src/db.rs @@ -87,6 +87,11 @@ impl Database { pub fn read(&self) -> &TreeMan { &self.0 } /// read and write access to tree pub fn write(&mut self) -> &mut TreeMan { &mut self.0 } + /// procures a new random u64 key + pub fn get_key() -> sled::Result { + let lock = DB.read(); + lock.generate_id() + } } /// trait for the Table marker types diff --git a/src/models.rs b/src/models.rs index 25a2c05..8375bc1 100644 --- a/src/models.rs +++ b/src/models.rs @@ -2,12 +2,13 @@ use serde::{Serialize, Deserialize}; use crate::auth::AuthToken; +use chrono::{DateTime, offset::Utc}; + +use std::convert::From; /// Model rezervace, tak jak je uložena v databázi #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Reservation { - /// primární klíč - pub id: u64, /// název události pub name: String, /// popis události @@ -25,9 +26,9 @@ pub struct Reservation { /// ``` pub rooms: u8, /// počáteční čas rezervace - pub begin_time: String, + pub begin_time: DateTime, /// čas, kdy rezervace končí - pub end_time: String, + pub end_time: DateTime, /// rozložení nábytku v audioriu pub layout: u8, /// zda byla rezervace schválena @@ -55,15 +56,32 @@ pub struct NewReservation { /// ``` pub rooms: u8, /// počáteční čas rezervace - pub begin_time: String, + pub begin_time: DateTime, /// čas, kdy rezervace končí - pub end_time: String, + pub end_time: DateTime, /// rozložení nábytku v audioriu pub layout: u8, /// počet lidí pub people: u8, } +impl From for Reservation { + pub fn from(src: NewReservation) -> Reservation { + Reservation { + name: src.name, + description: src.description, + author: String::new(), + rooms: src.rooms, + begin_time: src.begin_time, + end_time: src.end_time, + layout: src.layout, + approved: false, + people: src.people, + } + } +} + + /// Weird quick models #[derive(Serialize, Deserialize, Debug, Clone)] #[allow(dead_code)] @@ -83,9 +101,9 @@ pub struct UpdateReservation { /// ``` pub rooms: Option, /// počáteční čas rezervace - pub begin_time: Option, + pub begin_time: Option>, /// čas, kdy rezervace končí - pub end_time: Option, + pub end_time: Option>, /// rozložení nábytku v audioriu pub layout: Option, /// počet lidí From 33b048df2191686fa179e830b8870cfba0a50bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 00:33:28 +0100 Subject: [PATCH 23/38] update function --- src/db.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/db.rs b/src/db.rs index 7e699c8..046506d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -72,6 +72,24 @@ where self.tree .insert(serde_cbor::to_vec(k.borrow()).unwrap(), serde_cbor::to_vec(v.borrow()).unwrap()) // can't fail } + + /// update a key + pub fn update(&mut self, k: Key, fun: F) -> sled::Result> + where + Key: Borrow, + Value: Borrow, + F: Fn(Option) -> Option, + { + self.tree + .update_and_fetch( + serde_cbor::to_vec(k.borrow()).unwrap(), + |value| { + let value = value.and_then(|val| serde_cbor::from_slice(val.borrow()).ok()); + let res = fun(value); + res.and_then(|v| serde_cbor::to_vec(v.borrow()).ok()) + } + ) + } } /// wraps the database From 29d42adfd4a29a243ecba0df1feb52ef5e34bf3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 01:04:19 +0100 Subject: [PATCH 24/38] convert patch (partially), post and date_filter, remove legacy code --- api/booking/booking.py | 63 ---------------------------- api/booking/mod.rs | 93 ++++++++++++++++-------------------------- src/db.rs | 6 +++ 3 files changed, 42 insertions(+), 120 deletions(-) diff --git a/api/booking/booking.py b/api/booking/booking.py index 2577710..6e1b609 100755 --- a/api/booking/booking.py +++ b/api/booking/booking.py @@ -40,69 +40,6 @@ def default(self, obj): return json.JSONEncoder.default(self, obj) -def post(data): - """ - Adds new data to db - :param data: Booking dictionary by it's id - :return: {result: number} - """ - - result = Booking() - for key, value in data["data"].items(): - if value is None: - continue - setattr(result, key, value) - setattr(result, "approved", False) - setattr(result, "author", data["args"]["email"]) - - events = session.query(Booking).filter(Booking.approved == 1).\ - filter(Booking.begin_time <= result.end_time).\ - filter(Booking.end_time >= result.begin_time) - for event in events: - if event.rooms == 3: - return json.dumps({"result": 2}) - elif event.rooms == result.rooms: - return json.dumps({"result": 2}) - - session.add(result) - session.commit() - return json.dumps({"result": 0, "id": result.id}) - - -def filter(data): - """ - filer data by room flag, begin_time and start_time - :param data: roomflag(0/1/2/3), begin_time and start_time - :return: {results: array of result} - """ - - reservations = session.query(Booking).filter(Booking.begin_time <= data["args"]["end_time"]).\ - filter(Booking.end_time >= data["args"]["begin_time"]) - if data["args"]["rooms"] != 3: - reservations.filter(Booking.rooms == data["args"]["rooms"]) - - results = reservations.all() - return json.dumps({"results": results}, cls=AlchemyEncoder) - - - -def patch(data): - """ - Update data in the database - :param data: Booking dictionary - :return: {result: number} - """ - - results = session.query(Booking).filter(Booking.id == data["args"]["id"]).all() - if len(results) == 1: - result = results[0] - for key, value in data["data"].items(): - setattr(result, key, value) - session.add(result) - session.commit() - return json.dumps({"result": 0}) - else: - return json.dumps({"result": 1}) # no result found by the id def approve(data): """ diff --git a/api/booking/mod.rs b/api/booking/mod.rs index a414880..360c543 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -35,10 +35,10 @@ pub fn list(db: Database) -> Json> { /// /// parametry: /// - `id`: identifikátor dané rezervace -#[get("/events/")] -pub fn get(event_id: u64, db: Database, _u: AuthToken) -> Option> { +#[get("/events/")] +pub fn get(id: u64, db: Database, _u: AuthToken) -> Option> { db.read() - .get(event_id) // can't fail + .get(id) // can't fail .map(Json) } @@ -79,34 +79,19 @@ pub fn post(input: Json, mut db: Database, usr: Au /// - `id`: identifikátor dané rezervace /// /// data:[`UpdateReservation`] -#[patch("/events/", data = "<_input>")] -pub fn patch(r_id: u64, _input: Json, db: Database, usr: AuthToken) -> Option { +#[patch("/events/", data = "<_input>")] +pub fn patch(id: u64, _input: Json, mut db: Database, usr: AuthToken) -> Option<()> { + let event = db.read() + .get(id)?; -/* - // TODO return error instead of None on invalid states - if r_id < 0 { + // TODO roles are uggly + if event.author != usr.user.email || usr.user.role != "approver" { None? } - if usr.user.role.to_lowercase() != Approver::name() { - use crate::schema::booking::dsl::*; - let con = db::get_con(); - - let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; - - if reservation.author.trim() != usr.user.email.trim() { - None? // you shouldn't be able to edit others' events - } - } - - let id = r_id; - Some(rgi! { - PATCH "rgi/booking/booking.py" - arg: id - data: (&_input.into_inner()) - }) -*/ - unimplemented!() + // TODO actual patching + + Some(()) } /// vymaže danou rezervaci @@ -114,33 +99,22 @@ pub fn patch(r_id: u64, _input: Json, db: Database/ /// parametry: /// - `id`: identifikátor dané rezervace -#[delete("/events/")] -pub fn delete(r_id: u64, db: Database, usr: AuthToken) -> Option<()> { +#[delete("/events/")] +pub fn delete(id: u64, mut db: Database, usr: AuthToken) -> Option<()> { + let event = db.read() + .get(id)?; -/* use crate::schema::booking::dsl::*; - // TODO return error instead of None on invalid states - if r_id < 0 { + // TODO roles are uggly + if event.author != usr.user.email || usr.user.role != "approver" { None? } - if usr.user.role.to_lowercase() != Approver::name() { - - let con = db::get_con(); - let reservation = booking.filter(id.eq(r_id)).first::(&con).ok()?; - - if reservation.author.trim() != usr.user.email.trim() { - None? // you shouldn't be able to delete others' either - } - } - - let conn = db::get_con(); - - diesel::delete(booking.find(r_id)) - .execute(&conn) - .ok() - .map(|_| ()) -*/ - unimplemented!() + db + .write() + .delete(id) + .ok()?; + + Some(()) } /// filtruje podle data @@ -152,13 +126,18 @@ pub fn delete(r_id: u64, db: Database, usr: AuthToken) -> Op /// - `begin_time`: počáteční čas /// - `end_time`: čas konce #[get("/events/filter///")] -pub fn date_filter(rooms: u8, begin_time: String, end_time: String, db: Database, _u: AuthToken) -> String { - rgi! { - FILTER "rgi/booking/booking.py" - arg: rooms, - arg: begin_time, - arg: end_time - } +pub fn date_filter(rooms: u8, begin_time: String, end_time: String, db: Database, _u: AuthToken) -> Option>> { + use chrono::{DateTime, offset::Utc}; + let begin_time = DateTime::::from(DateTime::parse_from_rfc3339(&begin_time).ok()?); + let end_time = DateTime::::from(DateTime::parse_from_rfc3339(&end_time).ok()?); + + Some(Json( + db.read() + .iter() + .filter(|(_, v)| v.begin_time >= begin_time && v.begin_time <= end_time) + .filter(|(_, v)| v.rooms == rooms) + .collect::>() + )) } /// schválí endpoint diff --git a/src/db.rs b/src/db.rs index 046506d..e5b3f40 100644 --- a/src/db.rs +++ b/src/db.rs @@ -90,6 +90,12 @@ where } ) } + + /// remove a value + pub fn delete>(&mut self, k: Key) -> sled::Result> { + self.tree + .remove(serde_cbor::to_vec(k.borrow()).unwrap()) + } } /// wraps the database From 6eeb268087f4db8f4d4c91f78d12e969502f245e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 12:58:16 +0100 Subject: [PATCH 25/38] rustify patch, fix some warnings --- api/booking/mod.rs | 34 ++++++++++++++++++++++++++++------ src/models.rs | 2 +- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 360c543..e75ae49 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -2,13 +2,12 @@ use rocket::Route; use rocket_contrib::json::Json; use crate::auth::AuthToken; -use crate::auth::roles::{Noob, Approver, Role}; +use crate::auth::roles::{Noob, Approver}; use crate::db::{ Database, table::Reservations, - table::Users, }; use crate::models::{NewReservation, UpdateReservation, Reservation}; @@ -79,17 +78,40 @@ pub fn post(input: Json, mut db: Database, usr: Au /// - `id`: identifikátor dané rezervace /// /// data:[`UpdateReservation`] -#[patch("/events/", data = "<_input>")] -pub fn patch(id: u64, _input: Json, mut db: Database, usr: AuthToken) -> Option<()> { +#[patch("/events/", data = "")] +pub fn patch(id: u64, input: Json, mut db: Database, usr: AuthToken) -> Option<()> { let event = db.read() .get(id)?; // TODO roles are uggly if event.author != usr.user.email || usr.user.role != "approver" { - None? + return None } - // TODO actual patching + if db + .write() + .update::<_, Reservation, _>(id, |val: Option| if let Some(mut val) = val { + match input.clone() { + UpdateReservation { name, description, rooms, begin_time, end_time, layout, people } => { + name.and_then(|x| Some({ val.name = x })); + description.and_then(|x| Some({ val.description = x })); + rooms.and_then(|x| Some({ val.rooms = x })); + begin_time.and_then(|x| Some({ val.begin_time = x })); + end_time.and_then(|x| Some({ val.end_time = x })); + layout.and_then(|x| Some({ val.layout = x })); + people.and_then(|x| Some({ val.people = x })); + } + } + + val.approved = false; + + Some(val.clone()) + } else { + None + }).is_err() + { + return None + } Some(()) } diff --git a/src/models.rs b/src/models.rs index b381af5..2a84fa3 100644 --- a/src/models.rs +++ b/src/models.rs @@ -98,7 +98,7 @@ pub struct UpdateReservation { /// 0b10 -> south /// 0b11 -> celé auditorium /// ``` - pub rooms: Option, + pub rooms: Option, /// počáteční čas rezervace pub begin_time: Option>, /// čas, kdy rezervace končí From f2c15c45233d3a929f5a6fbc0fa471b08ff6251b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 13:06:48 +0100 Subject: [PATCH 26/38] formatting --- api/booking/mod.rs | 97 ++++++++++++++++++++++------------------------ src/auth.rs | 2 +- src/db.rs | 96 +++++++++++++++++++++++---------------------- src/models.rs | 17 ++++---- 4 files changed, 105 insertions(+), 107 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index e75ae49..b64bb54 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -4,11 +4,7 @@ use rocket_contrib::json::Json; use crate::auth::AuthToken; use crate::auth::roles::{Noob, Approver}; - -use crate::db::{ - Database, - table::Reservations, -}; +use crate::db::{Database, table::Reservations}; use crate::models::{NewReservation, UpdateReservation, Reservation}; @@ -21,11 +17,7 @@ use crate::models::{NewReservation, UpdateReservation, Reservation}; /// GET /events "application/json" #[get("/events", format = "application/json")] pub fn list(db: Database) -> Json> { - Json( - db.read() - .iter() - .collect::>() - ) + Json(db.read().iter().collect::>()) } /// vrátí JSON dané rezervace @@ -48,15 +40,12 @@ pub fn get(id: u64, db: Database, _u: AuthToken) -> Option, mut db: Database, usr: AuthToken) -> Option<()> { - if db.read() - .iter() - .any(|(_, x)| - x.approved == true + if db.read().iter().any(|(_, x)| { + x.approved == true && x.begin_time <= input.end_time && x.end_time >= input.begin_time && (x.rooms == 3 || x.rooms == input.rooms) - ) - { + }) { return None; // todo proper errors } @@ -64,10 +53,7 @@ pub fn post(input: Json, mut db: Database, usr: Au new_res.author = usr.user.email; - db.write() - .insert(Database::::get_key().unwrap(), new_res) - .ok()? - .and_then(|_| Some(())) + db.write().insert(Database::::get_key().unwrap(), new_res).ok()?.and_then(|_| Some(())) } /// upraví danou rezervaci @@ -79,40 +65,47 @@ pub fn post(input: Json, mut db: Database, usr: Au /// /// data:[`UpdateReservation`] #[patch("/events/", data = "")] -pub fn patch(id: u64, input: Json, mut db: Database, usr: AuthToken) -> Option<()> { - let event = db.read() - .get(id)?; +pub fn patch( + id: u64, + input: Json, + mut db: Database, + usr: AuthToken, +) -> Option<()> { + let event = db.read().get(id)?; // TODO roles are uggly if event.author != usr.user.email || usr.user.role != "approver" { - return None + return None; } if db .write() - .update::<_, Reservation, _>(id, |val: Option| if let Some(mut val) = val { - match input.clone() { - UpdateReservation { name, description, rooms, begin_time, end_time, layout, people } => { - name.and_then(|x| Some({ val.name = x })); - description.and_then(|x| Some({ val.description = x })); - rooms.and_then(|x| Some({ val.rooms = x })); - begin_time.and_then(|x| Some({ val.begin_time = x })); - end_time.and_then(|x| Some({ val.end_time = x })); - layout.and_then(|x| Some({ val.layout = x })); - people.and_then(|x| Some({ val.people = x })); + .update::<_, Reservation, _>(id, |val| { + if let Some(mut val) = val { + match input.clone() { + UpdateReservation { name, description, rooms, begin_time, end_time, layout, people } => { + name.and_then(|x| Some({ val.name = x })); + description.and_then(|x| Some({ val.description = x })); + rooms.and_then(|x| Some({ val.rooms = x })); + begin_time.and_then(|x| Some({ val.begin_time = x })); + end_time.and_then(|x| Some({ val.end_time = x })); + layout.and_then(|x| Some({ val.layout = x })); + people.and_then(|x| Some({ val.people = x })); + } } - } - val.approved = false; + val.approved = false; - Some(val.clone()) - } else { - None - }).is_err() + Some(val.clone()) + } else { + None + } + }) + .is_err() { - return None + return None; } - + Some(()) } @@ -123,19 +116,15 @@ pub fn patch(id: u64, input: Json, mut db: Database")] pub fn delete(id: u64, mut db: Database, usr: AuthToken) -> Option<()> { - let event = db.read() - .get(id)?; + let event = db.read().get(id)?; // TODO roles are uggly if event.author != usr.user.email || usr.user.role != "approver" { None? } - db - .write() - .delete(id) - .ok()?; - + db.write().delete(id).ok()?; + Some(()) } @@ -148,7 +137,13 @@ pub fn delete(id: u64, mut db: Database, usr: AuthToken) -> /// - `begin_time`: počáteční čas /// - `end_time`: čas konce #[get("/events/filter///")] -pub fn date_filter(rooms: u8, begin_time: String, end_time: String, db: Database, _u: AuthToken) -> Option>> { +pub fn date_filter( + rooms: u8, + begin_time: String, + end_time: String, + db: Database, + _u: AuthToken, +) -> Option>> { use chrono::{DateTime, offset::Utc}; let begin_time = DateTime::::from(DateTime::parse_from_rfc3339(&begin_time).ok()?); let end_time = DateTime::::from(DateTime::parse_from_rfc3339(&end_time).ok()?); @@ -158,7 +153,7 @@ pub fn date_filter(rooms: u8, begin_time: String, end_time: String, db: Database .iter() .filter(|(_, v)| v.begin_time >= begin_time && v.begin_time <= end_time) .filter(|(_, v)| v.rooms == rooms) - .collect::>() + .collect::>(), )) } diff --git a/src/auth.rs b/src/auth.rs index d45573b..4e746cc 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -168,5 +168,5 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { /// vrací informace o uživatelu #[get("/me")] pub fn me(_u: AuthToken) -> Json { - Json(_u.user) + Json(_u.user) } diff --git a/src/db.rs b/src/db.rs index e5b3f40..939622a 100644 --- a/src/db.rs +++ b/src/db.rs @@ -14,7 +14,6 @@ use std::borrow::Borrow; use std::iter::Iterator; use std::marker::PhantomData; - lazy_static! { /// a global handle to the Sled database pub static ref DB: RwLock = RwLock::new({ @@ -28,18 +27,18 @@ lazy_static! { /// also allows automatic type conversions pub struct TreeMan where - for <'a> K: Serialize + Deserialize<'a>, - for <'b> V: Serialize + Deserialize<'b>, + for<'a> K: Serialize + Deserialize<'a>, + for<'b> V: Serialize + Deserialize<'b>, { tree: Tree, - _k: PhantomData, - _v: PhantomData, + _k: PhantomData, + _v: PhantomData, } impl TreeMan where - for <'a> K: Serialize + Deserialize<'a>, - for <'b> V: Serialize + Deserialize<'b>, + for<'a> K: Serialize + Deserialize<'a>, + for<'b> V: Serialize + Deserialize<'b>, { /// create a new tree manager from a tree pub fn from_tree(tree: Tree) -> Self { @@ -47,14 +46,14 @@ where } /// creates an iterator over (K, V) - pub fn iter(&self) -> impl Iterator { - self.tree - .iter() - .filter_map(|res| { - if let Ok((k, v)) = res { - Some((serde_cbor::from_slice::(&k).ok()?, serde_cbor::from_slice::(&v).ok()?)) - } else { None } - }) + pub fn iter(&self) -> impl Iterator { + self.tree.iter().filter_map(|res| { + if let Ok((k, v)) = res { + Some((serde_cbor::from_slice::(&k).ok()?, serde_cbor::from_slice::(&v).ok()?)) + } else { + None + } + }) } /// try to get a value from the database @@ -69,8 +68,8 @@ where /// try to insert into database pub fn insert, Value: Borrow>(&mut self, k: Key, v: Value) -> sled::Result> { - self.tree - .insert(serde_cbor::to_vec(k.borrow()).unwrap(), serde_cbor::to_vec(v.borrow()).unwrap()) // can't fail + self.tree.insert(serde_cbor::to_vec(k.borrow()).unwrap(), serde_cbor::to_vec(v.borrow()).unwrap()) + // can't fail } /// update a key @@ -80,21 +79,16 @@ where Value: Borrow, F: Fn(Option) -> Option, { - self.tree - .update_and_fetch( - serde_cbor::to_vec(k.borrow()).unwrap(), - |value| { - let value = value.and_then(|val| serde_cbor::from_slice(val.borrow()).ok()); - let res = fun(value); - res.and_then(|v| serde_cbor::to_vec(v.borrow()).ok()) - } - ) + self.tree.update_and_fetch(serde_cbor::to_vec(k.borrow()).unwrap(), |value| { + let value = value.and_then(|val| serde_cbor::from_slice(val.borrow()).ok()); + let res = fun(value); + res.and_then(|v| serde_cbor::to_vec(v.borrow()).ok()) + }) } /// remove a value pub fn delete>(&mut self, k: Key) -> sled::Result> { - self.tree - .remove(serde_cbor::to_vec(k.borrow()).unwrap()) + self.tree.remove(serde_cbor::to_vec(k.borrow()).unwrap()) } } @@ -107,10 +101,14 @@ pub struct Database(TreeMan, PhantomData); impl Database { /// read-only access to tree - pub fn read(&self) -> &TreeMan { &self.0 } + pub fn read(&self) -> &TreeMan { + &self.0 + } /// read and write access to tree - pub fn write(&mut self) -> &mut TreeMan { &mut self.0 } + pub fn write(&mut self) -> &mut TreeMan { + &mut self.0 + } /// procures a new random u64 key pub fn get_key() -> sled::Result { @@ -148,20 +146,23 @@ pub trait Table { fn name() -> &'static str; /// gets the actual tree, should do it using the global DB handle fn get_tree_naive() -> Result { - let lock = DB.read() - .expect("the database rwlock has been poisoned"); - // ^ this usually implies a deeper underlying problem, - // so it's probably okay to hard crash + let lock = DB.read().expect("the database rwlock has been poisoned"); + // ^ this usually implies a deeper underlying problem, + // so it's probably okay to hard crash lock.open_tree(&Self::name()) } /// should return true if a custom get tree function is available - fn has_get_tree() -> bool { false } - + fn has_get_tree() -> bool { + false + } + /// optional custom function for fetching a tree, /// can call [`Table::get_tree_naive`] - fn get_tree() -> Result { unimplemented!() } + fn get_tree() -> Result { + unimplemented!() + } } /// module containing table markers @@ -175,7 +176,10 @@ pub mod table { impl Table for Reservations { type Key = u64; type Value = Reservation; - fn name() -> &'static str { "reservation" } + + fn name() -> &'static str { + "reservation" + } } /// Users database table marker @@ -184,7 +188,10 @@ pub mod table { impl Table for Users { type Key = u64; type Value = User; - fn name() -> &'static str { "user" } + + fn name() -> &'static str { + "user" + } } } @@ -195,13 +202,10 @@ impl<'a, 'r, T: Table> FromRequest<'a, 'r> for Database { if let Some(db) = Database::::open() { Outcome::Success(db) } else { - Outcome::Failure((Status::InternalServerError, - match T::has_get_tree() { - true => "failed to run custom db-loading function", - false => "failed to load database", - } - )) + Outcome::Failure((Status::InternalServerError, match T::has_get_tree() { + true => "failed to run custom db-loading function", + false => "failed to load database", + })) } } } - diff --git a/src/models.rs b/src/models.rs index 2a84fa3..125a9d5 100644 --- a/src/models.rs +++ b/src/models.rs @@ -67,20 +67,19 @@ pub struct NewReservation { impl From for Reservation { fn from(src: NewReservation) -> Reservation { Reservation { - name: src.name, + name: src.name, description: src.description, - author: String::new(), - rooms: src.rooms, - begin_time: src.begin_time, - end_time: src.end_time, - layout: src.layout, - approved: false, - people: src.people, + author: String::new(), + rooms: src.rooms, + begin_time: src.begin_time, + end_time: src.end_time, + layout: src.layout, + approved: false, + people: src.people, } } } - /// Weird quick models #[derive(Serialize, Deserialize, Debug, Clone)] #[allow(dead_code)] From e8aac2f39b4280e6891280e399ee96d4cfd25f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 16:19:42 +0100 Subject: [PATCH 27/38] deretardify --- api/booking/mod.rs | 34 ++++++++++++++++++---------------- src/db.rs | 9 ++++----- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index b64bb54..4f4347f 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -40,12 +40,14 @@ pub fn get(id: u64, db: Database, _u: AuthToken) -> Option, mut db: Database, usr: AuthToken) -> Option<()> { - if db.read().iter().any(|(_, x)| { - x.approved == true + let has_conflict = db.read().iter().any(|(_, x)| { + x.approved && x.begin_time <= input.end_time && x.end_time >= input.begin_time && (x.rooms == 3 || x.rooms == input.rooms) - }) { + }); + + if has_conflict { return None; // todo proper errors } @@ -53,7 +55,7 @@ pub fn post(input: Json, mut db: Database, usr: Au new_res.author = usr.user.email; - db.write().insert(Database::::get_key().unwrap(), new_res).ok()?.and_then(|_| Some(())) + db.write().insert(Database::::get_key().unwrap(), new_res).ok()?.map(|_| ()) } /// upraví danou rezervaci @@ -78,31 +80,31 @@ pub fn patch( return None; } - if db + let update_result = db .write() .update::<_, Reservation, _>(id, |val| { if let Some(mut val) = val { match input.clone() { UpdateReservation { name, description, rooms, begin_time, end_time, layout, people } => { - name.and_then(|x| Some({ val.name = x })); - description.and_then(|x| Some({ val.description = x })); - rooms.and_then(|x| Some({ val.rooms = x })); - begin_time.and_then(|x| Some({ val.begin_time = x })); - end_time.and_then(|x| Some({ val.end_time = x })); - layout.and_then(|x| Some({ val.layout = x })); - people.and_then(|x| Some({ val.people = x })); + name.map(|x| { val.name = x }); + description.map(|x| { val.description = x }); + rooms.map(|x| { val.rooms = x }); + begin_time.map(|x| { val.begin_time = x }); + end_time.map(|x| { val.end_time = x }); + layout.map(|x| { val.layout = x }); + people.map(|x| { val.people = x }); } } val.approved = false; - Some(val.clone()) + Some(val) } else { None } - }) - .is_err() - { + }); + + if update_result.is_err() { return None; } diff --git a/src/db.rs b/src/db.rs index 939622a..5511d92 100644 --- a/src/db.rs +++ b/src/db.rs @@ -17,9 +17,8 @@ use std::marker::PhantomData; lazy_static! { /// a global handle to the Sled database pub static ref DB: RwLock = RwLock::new({ - let db = Db::open(&env::var("DATABASE_URL").expect("failed to read DATABASE_URL environment variable")) - .expect("failed to open database"); - db + Db::open(&env::var("DATABASE_URL").expect("failed to read DATABASE_URL environment variable")) + .expect("failed to open database") }); } @@ -62,7 +61,7 @@ where .get(serde_cbor::to_vec(k.borrow()).unwrap()) // can't fail .ok() .flatten() - .and_then(|v| Some(serde_cbor::from_slice::(&*v).ok())) + .map(|v| serde_cbor::from_slice::(&*v).ok()) .flatten() } @@ -112,7 +111,7 @@ impl Database { /// procures a new random u64 key pub fn get_key() -> sled::Result { - let ref lock = DB.read().expect("the rwlock has been poisoned"); + let lock = DB.read().expect("the rwlock has been poisoned"); lock.generate_id() } From bf71e3f790ae6ab3d9f4ad16571a22f2b0d057fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 18:07:12 +0100 Subject: [PATCH 28/38] rewrite roles and sledify authentication --- src/auth.rs | 122 +++++++++++++++++++++++++++++--------------------- src/db.rs | 2 +- src/lib.rs | 2 +- src/models.rs | 10 ----- 4 files changed, 72 insertions(+), 64 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index 4e746cc..fd23f4b 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -19,11 +19,14 @@ use base64::decode; use std::marker::PhantomData; -use crate::db; -use crate::models::{NewUser, User}; +use crate::db::{ + Database, + table::Users, +}; +use crate::models::User; /// autorizační token, tak jak je přijat -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct AuthTokenRaw { /// jméno uživatele pub name: String, @@ -31,8 +34,21 @@ pub struct AuthTokenRaw { pub email: String, } +impl AuthTokenRaw { + /// converts a raw AuthToken into user + pub fn into_user(self) -> User { + use self::roles::Role; + + User { + name: self.name, + email: self.email, + role: roles::Noob::name().to_string(), + } + } +} + /// autorizační token po vyřešení údajů s databází -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct AuthToken { /// nalezený uživatel pub user: User, @@ -58,33 +74,47 @@ impl AuthToken { pub mod roles { #![allow(dead_code, missing_docs)] - /// sdílený trait pro role - /// velmi rudimentárním způsobem reprezentuje hierarchii + /// common trait for roles + /// comes with basic compile-time hierarchy pub trait Role { - /// jméno role jako string + /// this role's daddy, can be set to self if role is root + type Daddy: Role; + + /// name of role as str fn name() -> &'static str; + + /// whether the role is root role + fn is_root() -> bool { false } + /// jméno rodiče jako string - fn daddy() -> Option<&'static str> { - None + fn resolve_daddy() -> Vec<&'static str> { + if Self::is_root() { + vec![] + } else { + let mut v = vec![Self::name()]; + v.append(&mut Self::Daddy::resolve_daddy()); + v + } } } macro_rules! role_gen { - {$(($role:ident -> $daddy:expr))*} => { + {$($role:ident [$daddy:ident] $(-> $is_root:literal)? ),*} => { $( pub struct $role; impl Role for $role { + type Daddy = $daddy; fn name() -> &'static str { stringify!($role) } - fn daddy() -> Option<&'static str> { $daddy } + $(fn is_root() -> bool { $is_root })? } )* } } role_gen! { - (Noob -> None) - (Approver -> Some("noob")) - (FacilityManager -> Some("noob")) + Noob[Noob] -> true, + Approver[Noob] -> false, + FacilityManager[Noob] -> false } } @@ -92,12 +122,14 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { type Error = String; fn from_request(request: &'a Request<'r>) -> Outcome { - /*use crate::schema::users::dsl::*; + let mut db = match Database::::open() { + Some(d) => d, + None => return Outcome::Failure((Status::InternalServerError, "failed to connect to db".to_string())), + }; let keys: Vec<_> = request.headers().get("Authorization").collect(); match keys.get(0).unwrap_or(&"").split(' ').nth(1) { Some(ref token) => { - eprintln!("decoding"); let body = match decode(token) { Ok(bod) => bod, Err(_) => @@ -107,7 +139,6 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { )), }; - eprintln!("parsing"); let token: AuthTokenRaw = match serde_json::from_str(&String::from_utf8_lossy(&body).to_string()) { Ok(tok) => tok, Err(e) => @@ -119,40 +150,28 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { //... pošéfit databázi zde - let connection = db::get_con(); - - let result = users - .filter(email.eq(&token.email)) - .first::(&connection) - .optional() - .expect("failed to connect to db") - .unwrap_or_else(|| { - // unfortunately, SQLite does not support the RETURNING clause, so one has to do this atrocity - diesel::insert_into(users) - .values(NewUser { - name: token.name.clone(), - email: token.email.clone(), - role: "noob".to_string(), - }) - .execute(&connection) - .expect("failed to connect to db or insert item"); - - users - .filter(email.eq(&token.email)) - .first::(&connection) - .unwrap_or_else(|_| unreachable!("uh oh, this shouldn't happen, is your DB okay?")) - }); - - if T::name().to_lowercase() == result.role.to_lowercase() { - Outcome::Success(AuthToken::from_user(result)) - } else if let Some(daddy) = T::daddy() { - println!("{}", daddy); - match daddy.to_lowercase() == result.role.to_lowercase() { - true => Outcome::Success(AuthToken::from_user(result)), - false => Outcome::Failure((Status::Forbidden, "you don't have the required role".to_string())), + let result = if let Some((_, u)) = db.read() + .iter() + .find(|(_, u)| u.email == token.email) + { u } else { + let new_u = token.clone().into_user(); + + if db.write() + .insert(token.email, &new_u) + .is_err() + { + return Outcome::Failure(( + Status::InternalServerError, + "failed to insert user into DB".to_string(), + )) } + + new_u + }; + + if T::name() == result.role || T::resolve_daddy().contains(&result.role.as_str()) { + Outcome::Success(AuthToken::from_user(result)) } else { - println!("yeetus that feetus?"); Outcome::Failure((Status::Forbidden, "you don't have the required role".to_string())) } } @@ -160,13 +179,12 @@ impl<'a, 'r, T: roles::Role> FromRequest<'a, 'r> for AuthToken { println!("{:?}", x); Outcome::Failure((Status::BadRequest, "invalid authorization header".to_string())) } - }*/ - unimplemented!() + } } } /// vrací informace o uživatelu #[get("/me")] -pub fn me(_u: AuthToken) -> Json { +pub fn me(_u: AuthToken) -> Json { Json(_u.user) } diff --git a/src/db.rs b/src/db.rs index 5511d92..805a944 100644 --- a/src/db.rs +++ b/src/db.rs @@ -185,7 +185,7 @@ pub mod table { pub struct Users; impl Table for Users { - type Key = u64; + type Key = String; type Value = User; fn name() -> &'static str { diff --git a/src/lib.rs b/src/lib.rs index ca807bc..bb68f7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ //! ``` #![feature(proc_macro_hygiene, decl_macro)] #![feature(associated_type_defaults)] -#![allow(clippy::match_bool)] +#![allow(clippy::match_bool, clippy::option_map_unit_fn)] #![deny(missing_docs)] #[macro_use] diff --git a/src/models.rs b/src/models.rs index 125a9d5..90afd2d 100644 --- a/src/models.rs +++ b/src/models.rs @@ -119,13 +119,3 @@ pub struct User { /// role pub role: String, } - -/// Model usera pro vložení do databáze -#[derive(Serialize, Deserialize, Debug, Clone)] -#[allow(dead_code)] -pub struct NewUser { - /// jmeno - pub name: String, - /// email - pub email: String, -} From a95a749eeef30326bd7babf765cff860f3f76086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 18:30:25 +0100 Subject: [PATCH 29/38] convert approve --- api/booking/mod.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/api/booking/mod.rs b/api/booking/mod.rs index 4f4347f..c813208 100644 --- a/api/booking/mod.rs +++ b/api/booking/mod.rs @@ -118,10 +118,12 @@ pub fn patch( /// - `id`: identifikátor dané rezervace #[delete("/events/")] pub fn delete(id: u64, mut db: Database, usr: AuthToken) -> Option<()> { + use crate::auth::roles::Role; + let event = db.read().get(id)?; // TODO roles are uggly - if event.author != usr.user.email || usr.user.role != "approver" { + if event.author != usr.user.email || usr.user.role != Approver::name() { None? } @@ -166,11 +168,26 @@ pub fn date_filter( /// parametry: /// - `id`: id rezervace #[post("/events//approve")] -pub fn approve(id: u64, db: Database, _u: AuthToken) -> String { - rgi! { - APPROVE "rgi/booking/booking.py" - arg: id +pub fn approve(id: u64, mut db: Database, _u: AuthToken) -> Option<()> { + let event = db.read().get(id)?; + + // TODO maybe also delete conflicting events + let has_conflict = db.read().iter().any(|(_, x)| { + x.approved + && x.begin_time <= event.end_time + && x.end_time >= event.begin_time + && (x.rooms == 3 || x.rooms == event.rooms) + }); + + if !has_conflict { + db.write() + .update::<_, Reservation, _>(id, |x| if let Some(mut x) = x { + x.approved = true; + Some(x) + } else {None}).ok()?; } + + Some(()) } /// vrací seznam endpointů pro nabindování do Rocketu From b57f35343d757c2f9b218a2bcebee77cbaecd05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 18:50:16 +0100 Subject: [PATCH 30/38] restructure --- api/{booking/mod.rs => booking.rs} | 0 api/booking/booking.py | 82 ------------------------------ api/booking/curltest | 2 - api/{booking => }/mail.py | 0 4 files changed, 84 deletions(-) rename api/{booking/mod.rs => booking.rs} (100%) delete mode 100755 api/booking/booking.py delete mode 100755 api/booking/curltest rename api/{booking => }/mail.py (100%) diff --git a/api/booking/mod.rs b/api/booking.rs similarity index 100% rename from api/booking/mod.rs rename to api/booking.rs diff --git a/api/booking/booking.py b/api/booking/booking.py deleted file mode 100755 index 6e1b609..0000000 --- a/api/booking/booking.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 - -from sqlalchemy.ext.declarative import DeclarativeMeta -from sqlalchemy.ext.automap import automap_base -from sqlalchemy.orm import Session -from sqlalchemy import create_engine -from mail import send_request, send_approval, send_denial -import sys -import json -import os -import re - - -Base = automap_base() -engine = create_engine("sqlite:///" + os.getenv("DATABASE_URL")) -Base.prepare(engine, reflect=True) -Booking = Base.classes.booking -User = Base.classes.users -session = Session(engine) - -approver = "xsicp01@gjk.cz" - -class AlchemyEncoder(json.JSONEncoder): - - def default(self, obj): - if isinstance(obj.__class__, DeclarativeMeta): - # an SQLAlchemy class - fields = {} - for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']: - if field == "classes" or field == "prepare": - continue - data = obj.__getattribute__(field) - try: - json.dumps(data) # this will fail on non-encodable values, like other classes - fields[field] = data - except TypeError: - fields[field] = None - # a json-encodable dict - return fields - - return json.JSONEncoder.default(self, obj) - - -def approve(data): - """ - Approvs event by it's id - :param data: {id} - :return: ? - """ - - results = session.query(Booking).filter(Booking.id == data["args"]["id"]).all() - if len(results) == 1: - result = results[0] - events = session.query(Booking).filter(Booking.approved == 1).\ - filter(Booking.begin_time <= result.end_time).\ - filter(Booking.end_time >= result.begin_time) - for event in events: - if event.rooms == 3: - return json.dumps({"result": 2}) - elif event.rooms == result.rooms: - return json.dumps({"result": 2}) - - #send_approval("xsicp01@gjk.cz", "xsicp01@gjk.cz", result.rooms, result.begin_time, result.end_time) - result.approved = 1 - session.add(result) - session.commit() - return json.dumps({"result": 0}) - else: - return json.dumps({"result": 1}) # no result found by the id - - -methods = {"patch": patch, "approve" : approve} -txt = sys.stdin.read() -txt = re.sub(",[ \t\r\n]+}", "}", txt) -txt = re.sub(",[ \t\r\n]+\]", "]", txt) -print(txt, file=sys.stderr) -data = json.loads(txt) -if len(sys.argv) < 2: - sys.stdout.write(methods["get"](data)) -else: - sys.stdout.write(methods[sys.argv[1].lower()](data)) -sys.stdout.flush() diff --git a/api/booking/curltest b/api/booking/curltest deleted file mode 100755 index fa3cb1f..0000000 --- a/api/booking/curltest +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -curl -H application/json localhost:8000/rgi/events/1 diff --git a/api/booking/mail.py b/api/mail.py similarity index 100% rename from api/booking/mail.py rename to api/mail.py From d1d5436188e6a13ad19529842eb7c28605916eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 20:45:16 +0100 Subject: [PATCH 31/38] restructure pt.2 --- api/mail.py | 172 ---------------------------------------- api/mod.rs | 83 ------------------- src/admin.rs | 39 +++++++++ src/api | 1 - {api => src}/booking.rs | 1 + 5 files changed, 40 insertions(+), 256 deletions(-) delete mode 100755 api/mail.py delete mode 100644 api/mod.rs create mode 100644 src/admin.rs delete mode 120000 src/api rename {api => src}/booking.rs (99%) diff --git a/api/mail.py b/api/mail.py deleted file mode 100755 index fc31ad8..0000000 --- a/api/mail.py +++ /dev/null @@ -1,172 +0,0 @@ -import base64 -import logging -import mimetypes -import os -import os.path -import pickle -from email.mime.text import MIMEText -from google_auth_oauthlib.flow import InstalledAppFlow -from google.auth.transport.requests import Request -from googleapiclient import errors -from googleapiclient.discovery import build - -def get_service(): - """Get an authorized Gmail API service instance. - - Return: - An authorized Gmail API service instance.. - """ - - # If modifying these scopes, delete the file token.pickle. - SCOPES = [ - 'https://www.googleapis.com/auth/gmail.readonly', - 'https://www.googleapis.com/auth/gmail.send', - ] - - creds = None - # The file token.pickle stores the user's access and refresh tokens, and is - # created automatically when the authorization flow completes for the first - # time. - if os.path.exists('token.pickle'): - with open('token.pickle', 'rb') as token: - creds = pickle.load(token) - # If there are no (valid) credentials available, let the user log in. - if not creds or not creds.valid: - if creds and creds.expired and creds.refresh_token: - creds.refresh(Request()) - else: - flow = InstalledAppFlow.from_client_secrets_file( - 'credentials.json', SCOPES) - creds = flow.run_local_server(port=0) - # Save the credentials for the next run - with open('token.pickle', 'wb') as token: - pickle.dump(creds, token) - - service = build('gmail', 'v1', credentials=creds) - return service - - -def send_message(service, sender, message): - """Send an email message. - - Args: - service: Authorized Gmail API service instance. - user_id: User's email address. The special value "me" - can be used to indicate the authenticated user. - message: Message to be sent. - - Return: - Sent Message. - """ - try: - sent_message = (service.users().messages().send(userId=sender, body=message).execute()) - logging.info('Message Id: %s', sent_message['id']) - return sent_message - except errors.HttpError as error: - logging.error('An HTTP error occurred: %s', error) - -def create_message(sender, to, subject, message_text): - """Create a message for an email. - - Args: - sender: Email address of the sender. - to: Email address of the receiver. - subject: The subject of the email message. - message_text: The text of the email message. - http://docs.python.org/lib/module-smtplib.html - Return: - An object containing a base64url encoded email object. - """ - message = MIMEText(message_text) - message['to'] = to - message['from'] = sender - message['subject'] = subject - s = message.as_string() - b = base64.urlsafe_b64encode(s.encode('utf-8')) - return {'raw': b.decode('utf-8')} - -def send_approval(sender, to, auditorium, time_start, time_end): - - """ - Pošle email o schválení rezervace na základě zadaných parametrů - :param sender: adresa odesílatele - :param to: adresa příjemce - :param auditorium: - 1 - Auditorium South - 2 - Auditorium North - 3 - Both - :param time_start: string ve kterém je čas začátku rezervace - :param time_end: string ve kterém je čas konce rezervace - """ - - subject = "Approval of your booking of auditorium" - - if auditorium == 1: - text_auditorium = "Auditorium North" - elif auditorium == 2: - text_auditorium = "Auditorium South" - else: - text_auditorium = "Auditorium South and Auditorium North" - - text = "Your reservation of {} from {} to {} has been approved!".format(text_auditorium, time_start, time_end) - - service = get_service() - message = create_message(sender, to, subject, text) - send_message(service, sender, message) - - -def send_denial(sender, to, auditorium, time_start, time_end): - """ - Pošle email o zamítnutí rezervace na základě zadaných parametrů - :param sender: adresa odesílatele - :param to: adresa příjemce - :param auditorium: - 1 - Auditorium South - 2 - Auditorium North - 3 - Both - :param time_start: string ve kterém je čas začátku rezervace - :param time_end: string ve kterém je čas konce rezervace - """ - - subject = "Denial of your booking of auditorium" - - if auditorium == 1: - text_auditorium = "Auditorium North" - elif auditorium == 2: - text_auditorium = "Auditorium South" - else: - text_auditorium = "Auditorium South and Auditorium North" - - text = "Your reservation of {} from {} to {} has been approved!".format(text_auditorium, time_start, time_end) - - service = get_service() - message = create_message(sender, to, subject, text) - send_message(service, sender, message) - -def send_request(booker, approver, auditorium, time_start, time_end): - """ - Send request for the approval of booking. - Args: - sender: Email address of the booker (sender) - to: Email address of the approver (administrator) - time_start: Starting time of reservation - time_end: Ending time of reservation - Return: - None(Sends request.) - """ - if auditorium == 1: - text_auditorium = "North" - - elif auditorium == 2: - text_auditorium = "South" - else: - text_auditorium = "North and South" - - sub_request = "Approval Request" - text_request = "I would like to reserve {} from {} to {}, please.". format(text_auditorium, time_start, time_end) - - service = get_service() - message = create_message(booker, approver, sub_request, text_request) - send_message(service, booker, message) - - diff --git a/api/mod.rs b/api/mod.rs deleted file mode 100644 index 45599de..0000000 --- a/api/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! kořenový rgi modul (endpointy jsou tady, yee-haw) -//! -//! _"je to jako CGI, ale s Rustem"_ -//! -//! - -use rocket::Route; - -/// makro, které vygeneruje boilerplate pro volání daného rgi -/// -/// syntaxe (hranaté závorky značí, že parametr není povinný): -/// ```no_run -/// rgi! { -/// HTTP_METODA "rgi/cesta/k/rgi/binarce" -/// [arg: identifikátor]* // argumentem se myslí parametr z URL -/// [data: ]? // někdy je potřeba obalit do závorek () -/// } -/// ``` -/// (všechny argumenty a data musí implementovat `serialize` ze `serde`) -/// -/// příklad: -/// rgi! { -/// GET "rgi/lol/lol.py" -/// arg: name -/// arg: password -/// data: (Objekt) -/// } -#[macro_export] -macro_rules! rgi { - {$method:ident $name:literal $(arg: $arg:ident),* $(data: $data:tt)? } => { - { - // we need this lint to avoid warnings caused by extra parens - // which are not extra since they help the parser - #![allow(unused_parens)] - #[allow(unused_imports)] - use std::process::{Command, Stdio}; - #[allow(unused_imports)] - use std::io::{Read, Write}; - - let mut cmd = Command::new($name) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .arg(stringify!($method)) - .spawn() - .expect("kinda gay"); - - if let Some(ref mut stdin) = &mut cmd.stdin { - let _ = writeln!(stdin, "{{"); - let _ = writeln!(stdin, "\t\"args\": {{"); - $(let _ = writeln!(stdin, "\t\t\"{}\": \"{}\",", stringify!($arg), ($arg).to_string());)* - let _ = writeln!(stdin, "\t}},"); - $(let _ = writeln!(stdin, "\t\"data\": {}", serde_json::to_string($data).unwrap());)? - let _ = writeln!(stdin, "}}"); - } - - let cmd = cmd.wait_with_output().unwrap(); - - String::from_utf8_lossy(&cmd.stdout).to_string() - } - } -} - -/// modul obsahující endpointy pro CRUD na rezervaci -pub mod booking; - -/// sbírá jednotlivé endpointy -/// -/// přidání nového rgi -/// ```no_run -/// // deklarace modulu -/// mod muj_modul; -/// -/// // v routes.. -/// routes.extend(self::muj_modul::routes()); -/// ``` -pub fn routes() -> Vec { - let mut routes = vec![]; - - /*routes() funkce volat tady*/ - routes.extend(self::booking::routes()); - - routes -} diff --git a/src/admin.rs b/src/admin.rs new file mode 100644 index 0000000..5731fbf --- /dev/null +++ b/src/admin.rs @@ -0,0 +1,39 @@ +//! a module containing admin functions +use rocket::Route; +use rocket_contrib::json::Json; + +use std::env; + +use crate::auth::AuthToken; +use crate::auth::roles::{Role, Superadmin}; + +use crate::db::{ + Database, + table::Reservations, + table::Users, +}; + +use crate::models::{User, Reservation}; + +/// geenrates a superadmin +#[post("/generate_sa//", format = "application/json")] +pub fn generate_superadmin(email: String, password: String, mut db: Database) -> Option<()> { + if password != env::var("SECRET_PASSWORD").unwrap() { return None } + + db.write() + .insert(&email, User { email: email.clone(), name: "Superadmin".to_string(), role: Superadmin::name().to_string() }) + .ok()? + .map(|_| ()) +} + +/// get all users +#[get("/users", format = "application/json")] +pub fn users(db: Database, _u: AuthToken) -> Json> { + Json(db.read().iter().collect::>()) +} + + +/// vrací seznam endpointů pro nabindování do Rocketu +pub fn routes() -> Vec { + routes![users] +} diff --git a/src/api b/src/api deleted file mode 120000 index 4bb0f50..0000000 --- a/src/api +++ /dev/null @@ -1 +0,0 @@ -../api/ \ No newline at end of file diff --git a/api/booking.rs b/src/booking.rs similarity index 99% rename from api/booking.rs rename to src/booking.rs index c813208..99427bf 100644 --- a/api/booking.rs +++ b/src/booking.rs @@ -1,3 +1,4 @@ +//! a module containing booking functionality use rocket::Route; use rocket_contrib::json::Json; From ea3602f262afc8a64f27d0b35b81cea76e66411f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 20:46:03 +0100 Subject: [PATCH 32/38] start admin endpoints --- mail.py | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/auth.rs | 9 +-- src/lib.rs | 6 +- 3 files changed, 181 insertions(+), 6 deletions(-) create mode 100755 mail.py diff --git a/mail.py b/mail.py new file mode 100755 index 0000000..fc31ad8 --- /dev/null +++ b/mail.py @@ -0,0 +1,172 @@ +import base64 +import logging +import mimetypes +import os +import os.path +import pickle +from email.mime.text import MIMEText +from google_auth_oauthlib.flow import InstalledAppFlow +from google.auth.transport.requests import Request +from googleapiclient import errors +from googleapiclient.discovery import build + +def get_service(): + """Get an authorized Gmail API service instance. + + Return: + An authorized Gmail API service instance.. + """ + + # If modifying these scopes, delete the file token.pickle. + SCOPES = [ + 'https://www.googleapis.com/auth/gmail.readonly', + 'https://www.googleapis.com/auth/gmail.send', + ] + + creds = None + # The file token.pickle stores the user's access and refresh tokens, and is + # created automatically when the authorization flow completes for the first + # time. + if os.path.exists('token.pickle'): + with open('token.pickle', 'rb') as token: + creds = pickle.load(token) + # If there are no (valid) credentials available, let the user log in. + if not creds or not creds.valid: + if creds and creds.expired and creds.refresh_token: + creds.refresh(Request()) + else: + flow = InstalledAppFlow.from_client_secrets_file( + 'credentials.json', SCOPES) + creds = flow.run_local_server(port=0) + # Save the credentials for the next run + with open('token.pickle', 'wb') as token: + pickle.dump(creds, token) + + service = build('gmail', 'v1', credentials=creds) + return service + + +def send_message(service, sender, message): + """Send an email message. + + Args: + service: Authorized Gmail API service instance. + user_id: User's email address. The special value "me" + can be used to indicate the authenticated user. + message: Message to be sent. + + Return: + Sent Message. + """ + try: + sent_message = (service.users().messages().send(userId=sender, body=message).execute()) + logging.info('Message Id: %s', sent_message['id']) + return sent_message + except errors.HttpError as error: + logging.error('An HTTP error occurred: %s', error) + +def create_message(sender, to, subject, message_text): + """Create a message for an email. + + Args: + sender: Email address of the sender. + to: Email address of the receiver. + subject: The subject of the email message. + message_text: The text of the email message. + http://docs.python.org/lib/module-smtplib.html + Return: + An object containing a base64url encoded email object. + """ + message = MIMEText(message_text) + message['to'] = to + message['from'] = sender + message['subject'] = subject + s = message.as_string() + b = base64.urlsafe_b64encode(s.encode('utf-8')) + return {'raw': b.decode('utf-8')} + +def send_approval(sender, to, auditorium, time_start, time_end): + + """ + Pošle email o schválení rezervace na základě zadaných parametrů + :param sender: adresa odesílatele + :param to: adresa příjemce + :param auditorium: + 1 - Auditorium South + 2 - Auditorium North + 3 - Both + :param time_start: string ve kterém je čas začátku rezervace + :param time_end: string ve kterém je čas konce rezervace + """ + + subject = "Approval of your booking of auditorium" + + if auditorium == 1: + text_auditorium = "Auditorium North" + elif auditorium == 2: + text_auditorium = "Auditorium South" + else: + text_auditorium = "Auditorium South and Auditorium North" + + text = "Your reservation of {} from {} to {} has been approved!".format(text_auditorium, time_start, time_end) + + service = get_service() + message = create_message(sender, to, subject, text) + send_message(service, sender, message) + + +def send_denial(sender, to, auditorium, time_start, time_end): + """ + Pošle email o zamítnutí rezervace na základě zadaných parametrů + :param sender: adresa odesílatele + :param to: adresa příjemce + :param auditorium: + 1 - Auditorium South + 2 - Auditorium North + 3 - Both + :param time_start: string ve kterém je čas začátku rezervace + :param time_end: string ve kterém je čas konce rezervace + """ + + subject = "Denial of your booking of auditorium" + + if auditorium == 1: + text_auditorium = "Auditorium North" + elif auditorium == 2: + text_auditorium = "Auditorium South" + else: + text_auditorium = "Auditorium South and Auditorium North" + + text = "Your reservation of {} from {} to {} has been approved!".format(text_auditorium, time_start, time_end) + + service = get_service() + message = create_message(sender, to, subject, text) + send_message(service, sender, message) + +def send_request(booker, approver, auditorium, time_start, time_end): + """ + Send request for the approval of booking. + Args: + sender: Email address of the booker (sender) + to: Email address of the approver (administrator) + time_start: Starting time of reservation + time_end: Ending time of reservation + Return: + None(Sends request.) + """ + if auditorium == 1: + text_auditorium = "North" + + elif auditorium == 2: + text_auditorium = "South" + else: + text_auditorium = "North and South" + + sub_request = "Approval Request" + text_request = "I would like to reserve {} from {} to {}, please.". format(text_auditorium, time_start, time_end) + + service = get_service() + message = create_message(booker, approver, sub_request, text_request) + send_message(service, booker, message) + + diff --git a/src/auth.rs b/src/auth.rs index fd23f4b..f8082cf 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -99,7 +99,7 @@ pub mod roles { } macro_rules! role_gen { - {$($role:ident [$daddy:ident] $(-> $is_root:literal)? ),*} => { + {$($role:ident [$daddy:ident] $(-> $is_root:literal)? ),* $(,)?} => { $( pub struct $role; impl Role for $role { @@ -112,9 +112,10 @@ pub mod roles { } role_gen! { - Noob[Noob] -> true, - Approver[Noob] -> false, - FacilityManager[Noob] -> false + Noob[Noob] -> true, + Approver[Noob] -> false, + FacilityManager[Noob] -> false, + Superadmin[Approver] -> false, } } diff --git a/src/lib.rs b/src/lib.rs index bb68f7f..34fc14b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,8 +62,9 @@ use rocket::http::Method; use rocket_cors::{AllowedHeaders, AllowedOrigins}; pub mod static_server; +pub mod booking; +pub mod admin; pub mod auth; -pub mod api; pub mod db; pub mod models; @@ -89,6 +90,7 @@ pub fn init() -> rocket::Rocket { rocket::ignite() .register(catchers![static_server::not_found]) .mount("/", routes![static_server::index, static_server::frontend, static_server::favicon, auth::me]) - .mount("/api/", api::routes()) + .mount("/api/", booking::routes()) + .mount("/admin/", admin::routes()) .attach(cors) } From 410921671596745f804c08ee73c6635a4092059c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 20:46:21 +0100 Subject: [PATCH 33/38] superadmin generator --- Cargo.lock | 123 ++++++++++++++++++++++++++++++++ Cargo.toml | 3 + src/bin/superadmin_generator.rs | 39 ++++++++++ 3 files changed, 165 insertions(+) create mode 100644 src/bin/superadmin_generator.rs diff --git a/Cargo.lock b/Cargo.lock index 3a89d77..92f46c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,14 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayvec" version = "0.4.12" @@ -37,14 +45,37 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ferris_print 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rocket_cors 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scanln 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "serde_cbor 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "sled 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", + "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,6 +141,20 @@ dependencies = [ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -201,6 +246,32 @@ name = "dotenv" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "error-chain" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ferris-says" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ferris_print" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ferris-says 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "filetime" version = "0.2.8" @@ -717,6 +788,11 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -743,6 +819,11 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scanln" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "1.0.0" @@ -831,6 +912,11 @@ dependencies = [ "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "smallvec" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smallvec" version = "0.6.13" @@ -849,6 +935,11 @@ name = "state" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.15.44" @@ -869,6 +960,14 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -946,6 +1045,11 @@ dependencies = [ "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -971,6 +1075,11 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.5" @@ -1049,9 +1158,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" @@ -1061,6 +1173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cookie 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99be24cfcf40d56ed37fd11c2123be833959bbc5bddecb46e1c2e442e15fa3e0" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" @@ -1071,6 +1184,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7" "checksum devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487" "checksum dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" +"checksum ferris-says 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07a21339b4ddc37834c200a769f0fa58919bfda64950abcc1b6438e8b50b32fd" +"checksum ferris_print 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "551b7de36d95eed82a45ccf641a5bb1d78ceb488dec4f1ecd17b3906d8cd8a23" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" "checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" @@ -1128,10 +1244,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e0fa5c1392135adc0f96a02ba150ac4c765e27c58dbfd32aa40678e948f6e56f" "checksum rocket_cors 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "270a960cba5a0b7928ad74268db7773ce932da6b550478383cefebe9f46c4e13" "checksum rocket_http 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1391457ee4e80b40d4b57fa5765c0f2836b20d73bcbee4e3f35d93cf3b80817" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" +"checksum scanln 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b44c6898b219e294163a3c23916596b2c6225b1fefe468824d4c0c002c0a8bc6" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -1142,11 +1260,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum sled 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d7c3453de0f6a77abdd17cc9f68d6650214abd088b052b13302f86fa9a5b286e" +"checksum smallvec 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f90c5e5fe535e48807ab94fc611d323935f39d4660c52b26b96446a7b33aef10" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" "checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" @@ -1157,10 +1278,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicase_serde 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ef53697679d874d69f3160af80bc28de12730a985d57bdf2b47456ccb8b11f1" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" diff --git a/Cargo.toml b/Cargo.toml index 4a23350..cb4cbd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,9 @@ base64 = "0.11.0" sled = "0.29" lazy_static = "1.4" serde_cbor = "0.10.2" +ferris_print = "0.1" +scanln = "0.1" +yansi = "0.5" [dependencies.chrono] version = "0.4.10" diff --git a/src/bin/superadmin_generator.rs b/src/bin/superadmin_generator.rs new file mode 100644 index 0000000..bc480eb --- /dev/null +++ b/src/bin/superadmin_generator.rs @@ -0,0 +1,39 @@ +extern crate backend; + +#[macro_use] +extern crate ferris_print; +#[macro_use] +extern crate scanln; + +extern crate rocket; +extern crate yansi; + +use yansi::Paint; +use backend::init; + +use rocket::http::Status; +use rocket::local::Client; + +use std::env; + +fn main() { + let rocket = init(); + let client = Client::new(rocket).expect("rocket instance is not valid"); + + ferrisprint!("Superadmin generation tool v1.0"); + + let admin_email = scanln!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("please insert superadmin login email:")); + + println!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("reading super secret password")); + + let password = env::var("SA_SECRET").unwrap(); + + println!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("generating superadmin")); + let req = client.post(format!("/generate_sa/{}/{}", admin_email, password)).dispatch(); + + if req.status() != Status::NotFound { + println!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("failed to generate superadmin account")) + } else { + println!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("successfully generated superadmin account")) + } +} From 6ad08f0f86f2158a5e8c4976ba6e2261d3bd2f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 21:14:19 +0100 Subject: [PATCH 34/38] superadmin generator working, update .env, update .gitignore, implement Drop for Database --- .env | 1 + .gitignore | 2 +- src/admin.rs | 6 +++--- src/bin/superadmin_generator.rs | 5 +++-- src/db.rs | 12 +++++++++++- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.env b/.env index ac8dadb..4877cfb 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ DATABASE_URL="auditorium__booking.sled.db" +SA_SECRET="epsteindidintkillhimself" diff --git a/.gitignore b/.gitignore index 55c8a99..c940294 100644 --- a/.gitignore +++ b/.gitignore @@ -155,4 +155,4 @@ dmypy.json .pyre/ # database -auditorium_booking.sqlite3 +auditorium__booking.sled.db/ diff --git a/src/admin.rs b/src/admin.rs index 5731fbf..021de2b 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -16,9 +16,9 @@ use crate::db::{ use crate::models::{User, Reservation}; /// geenrates a superadmin -#[post("/generate_sa//", format = "application/json")] +#[post("/generate_sa//")] pub fn generate_superadmin(email: String, password: String, mut db: Database) -> Option<()> { - if password != env::var("SECRET_PASSWORD").unwrap() { return None } + if password != env::var("SA_SECRET").unwrap() { return None } db.write() .insert(&email, User { email: email.clone(), name: "Superadmin".to_string(), role: Superadmin::name().to_string() }) @@ -35,5 +35,5 @@ pub fn users(db: Database, _u: AuthToken) -> Json Vec { - routes![users] + routes![users, generate_superadmin] } diff --git a/src/bin/superadmin_generator.rs b/src/bin/superadmin_generator.rs index bc480eb..b65a72c 100644 --- a/src/bin/superadmin_generator.rs +++ b/src/bin/superadmin_generator.rs @@ -20,7 +20,8 @@ fn main() { let rocket = init(); let client = Client::new(rocket).expect("rocket instance is not valid"); - ferrisprint!("Superadmin generation tool v1.0"); + println!(); + ferrisprint!("Superadmin generator v1"); let admin_email = scanln!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("please insert superadmin login email:")); @@ -29,7 +30,7 @@ fn main() { let password = env::var("SA_SECRET").unwrap(); println!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("generating superadmin")); - let req = client.post(format!("/generate_sa/{}/{}", admin_email, password)).dispatch(); + let req = client.post(format!("/admin/generate_sa/{}/{}", admin_email, password)).dispatch(); if req.status() != Status::NotFound { println!("[{}] {}", Paint::magenta("rust booking"), Paint::yellow("failed to generate superadmin account")) diff --git a/src/db.rs b/src/db.rs index 805a944..aab4fa5 100644 --- a/src/db.rs +++ b/src/db.rs @@ -9,6 +9,7 @@ use sled::{Db, Tree}; use serde_cbor; use std::env; +use std::ops::Drop; use std::sync::RwLock; use std::borrow::Borrow; use std::iter::Iterator; @@ -67,7 +68,9 @@ where /// try to insert into database pub fn insert, Value: Borrow>(&mut self, k: Key, v: Value) -> sled::Result> { - self.tree.insert(serde_cbor::to_vec(k.borrow()).unwrap(), serde_cbor::to_vec(v.borrow()).unwrap()) + let tmp = self.tree.insert(serde_cbor::to_vec(k.borrow()).unwrap(), serde_cbor::to_vec(v.borrow()).unwrap()); + println!("{:?}", tmp); + tmp // can't fail } @@ -208,3 +211,10 @@ impl<'a, 'r, T: Table> FromRequest<'a, 'r> for Database { } } } + +impl Drop for Database { + fn drop(&mut self) { + self.0.tree.flush(); + println!("tree {}: {}", String::from_utf8_lossy(&self.0.tree.name()), self.0.tree.len()) + } +} From 6a00b75f2ff41f1d422fc7e0d5dd886d79de68a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 21:33:37 +0100 Subject: [PATCH 35/38] change role, add default-run manifest key --- Cargo.toml | 1 + src/admin.rs | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cb4cbd5..6d8929d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "backend" version = "0.1.0" authors = ["Dawid J. Kubis ", "Lukáš Hozda ", "Lukáš Veškrna "] edition = "2018" +default-run = "backend" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/admin.rs b/src/admin.rs index 021de2b..cb4d337 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -32,8 +32,24 @@ pub fn users(db: Database, _u: AuthToken) -> Json>()) } +/// change user role +#[patch("/users//", format = "application/json")] +pub fn change_role(email: String, new_role: String, mut db: Database, _u: AuthToken) -> Option<()> { + if !["Noob", "Superadmin", "Approver", "FacilityManager"].contains(&new_role.as_str()) { + return None; + } + + db.write() + .update::<_, User, _>(email, |x| if let Some(mut x) = x { + x.role = new_role.clone(); + Some(x) + } else {None}).ok()?; + + Some(()) +} + /// vrací seznam endpointů pro nabindování do Rocketu pub fn routes() -> Vec { - routes![users, generate_superadmin] + routes![users, generate_superadmin, change_role] } From afca1cf6465dd840f68e4f492256bc6c6271a511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Sun, 1 Dec 2019 21:58:13 +0100 Subject: [PATCH 36/38] add feature flag --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 34fc14b..422cfd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,7 @@ //! ``` #![feature(proc_macro_hygiene, decl_macro)] #![feature(associated_type_defaults)] +#![feature(option_flattening)] #![allow(clippy::match_bool, clippy::option_map_unit_fn)] #![deny(missing_docs)] From 2780bc12c9a67c840a753755a29ff721fffda934 Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Wed, 4 Dec 2019 22:33:14 +0100 Subject: [PATCH 37/38] Dockerfile update --- Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 10adc14..77909f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,8 @@ FROM archlinux/base # dependencies -RUN pacman -Suy --noconfirm rustup make gcc pkgconf sqlite \ -python python-sqlalchemy yarn python-google-api-python-client python-pip -RUN pip install google_auth_oauthlib && rustup install nightly +RUN pacman -Suy --noconfirm rustup make gcc pkgconf yarn +RUN rustup install nightly # workdir WORKDIR /cw From 59d472f0543e94e89a5a260a4f63149e322c7fbb Mon Sep 17 00:00:00 2001 From: "Dawid J. Kubis" Date: Fri, 6 Dec 2019 01:26:38 +0100 Subject: [PATCH 38/38] zip file --- src/response.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/response.rs diff --git a/src/response.rs b/src/response.rs new file mode 100644 index 0000000..236cc0b --- /dev/null +++ b/src/response.rs @@ -0,0 +1,6 @@ + +use rocket::response; + +// dodelam + +pub enum Response {}