From 3d907487a1bfa9c072182c57d4578e86e45b0e1e Mon Sep 17 00:00:00 2001 From: philipp Date: Tue, 4 Apr 2023 12:19:56 +0200 Subject: [PATCH] add planned_trip functionality --- Cargo.lock | 32 ++++++++++++++--- Cargo.toml | 2 ++ README.md | 23 ++----------- migration.sql | 18 ++++++++++ src/model/mod.rs | 23 +++++++++++++ src/model/planned_event.rs | 55 +++++++++++++++++++++++++++++ src/model/tripdetails.rs | 33 ++++++++++++++++++ src/rest/admin/mod.rs | 2 ++ src/rest/admin/planned_event.rs | 61 +++++++++++++++++++++++++++++++++ src/rest/admin/user.rs | 6 +++- src/rest/mod.rs | 14 +++++--- templates/index.html.tera | 36 ++++++++++++++++++- 12 files changed, 273 insertions(+), 32 deletions(-) create mode 100644 src/model/planned_event.rs create mode 100644 src/model/tripdetails.rs create mode 100644 src/rest/admin/planned_event.rs diff --git a/Cargo.lock b/Cargo.lock index dbfa3fe..265d2cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,8 +229,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", + "js-sys", "num-integer", "num-traits", + "serde", + "time 0.1.45", + "wasm-bindgen", "winapi", ] @@ -289,7 +293,7 @@ dependencies = [ "rand", "sha2", "subtle", - "time", + "time 0.3.20", "version_check", ] @@ -716,7 +720,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -1203,7 +1207,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.45.0", ] @@ -1732,7 +1736,7 @@ dependencies = [ "serde", "state", "tempfile", - "time", + "time 0.3.20", "tokio", "tokio-stream", "tokio-util", @@ -1792,7 +1796,7 @@ dependencies = [ "smallvec", "stable-pattern", "state", - "time", + "time 0.3.20", "tokio", "uncased", ] @@ -1802,6 +1806,7 @@ name = "rot" version = "0.1.0" dependencies = [ "argon2", + "chrono", "env_logger", "log", "rocket", @@ -2237,6 +2242,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.20" @@ -2618,6 +2634,12 @@ dependencies = [ "try-lock", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index c0a90a1..798f835 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,5 @@ sqlx = { version = "0.6", features = ["sqlite", "runtime-tokio-rustls", "macros" argon2 = "0.5" serde = { version = "1.0", features = [ "derive" ]} serde_json = "1.0" +chrono = { version = "0.4", features = ["serde"]} + diff --git a/README.md b/README.md index e892525..79246f6 100644 --- a/README.md +++ b/README.md @@ -17,31 +17,12 @@ # DB -- users - - id: i32 - - name: String - - pw: String - - is_cox: bool (false) - - is_admin: bool (false) - - is_guest: bool (true) -- planned_event - - id: i32 - - name: String (e.g. "USI") - - planned_amount_cox: i32 - - trip_details_id: i32 (trip_details.id) - - allow_guests: bool (false) - trip - id: i32 - cox_id: i32 (user.id) - trip_details: Option (trip_details.id) - planned_event_id: Option (planned_event.id) - created: chrono::DateTime -- trip_details - - id: i32 - - planned_starting_time: String - - max_people: i32 - - day: chrono::NaiveDate - - notes: String - user_trip - trip_details_id: i32 (trip_details.id) - user_id: i32 (user.id) @@ -54,7 +35,7 @@ - [x] User passwort zurücksetzen - [x] Cox + admin + guest setzen - [ ] Ausfahrten - - [ ] CRUD planned_event - - [ ] CRUD trip_details + - [x] CRUD planned_event + - [x] CRUD trip_details - [ ] CRUD trip - [ ] CRUD user_trip diff --git a/migration.sql b/migration.sql index 5020307..043e83f 100644 --- a/migration.sql +++ b/migration.sql @@ -6,3 +6,21 @@ CREATE TABLE IF NOT EXISTS "user" ( "is_admin" boolean NOT NULL DEFAULT FALSE, "is_guest" boolean NOT NULL DEFAULT TRUE ); + +CREATE TABLE IF NOT EXISTS "trip_details" ( + "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, + "planned_starting_time" text NOT NULL, + "max_people" INTEGER NOT NULL, + "day" TEXT NOT NULL, + "notes" TEXT +); + +CREATE TABLE IF NOT EXISTS "planned_event" ( + "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" text NOT NULL, + "planned_amount_cox" INTEGER unsigned NOT NULL, + "allow_guests" boolean NOT NULL default false, + "trip_details_id" INTEGER NOT NULL, + "created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(trip_details_id) REFERENCES trip_details(id) ON DELETE CASCADE +); diff --git a/src/model/mod.rs b/src/model/mod.rs index 62d809a..cfb6082 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,2 +1,25 @@ +use chrono::NaiveDate; +use serde::Serialize; +use sqlx::SqlitePool; + +use self::planned_event::PlannedEvent; + +pub mod planned_event; +pub mod tripdetails; pub mod user; //pub mod users; + +#[derive(Serialize)] +pub struct Day { + day: NaiveDate, + planned_events: Vec, +} + +impl Day { + pub async fn new(db: &SqlitePool, day: NaiveDate) -> Self { + Self { + day, + planned_events: PlannedEvent::get_for_day(db, day).await, + } + } +} diff --git a/src/model/planned_event.rs b/src/model/planned_event.rs new file mode 100644 index 0000000..d41a3ab --- /dev/null +++ b/src/model/planned_event.rs @@ -0,0 +1,55 @@ +use chrono::NaiveDate; +use serde::Serialize; +use sqlx::SqlitePool; + +#[derive(Serialize)] +pub struct PlannedEvent { + id: i64, + name: String, + planned_amount_cox: i64, + allow_guests: bool, + trip_details_id: i64, + planned_starting_time: String, + max_people: i64, + day: String, + notes: Option, +} + +impl PlannedEvent { + pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec { + sqlx::query_as!( + PlannedEvent, + " +SELECT planned_event.id, name, planned_amount_cox, allow_guests, trip_details_id, planned_starting_time, max_people, day, notes +FROM planned_event +INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id + " + ) + .fetch_all(db) + .await + .unwrap() //TODO: fixme + } + + pub async fn new( + db: &SqlitePool, + name: String, + planned_amount_cox: i32, + allow_guests: bool, + trip_details_id: i64, + ) { + sqlx::query!( + "INSERT INTO planned_event(name, planned_amount_cox, allow_guests, trip_details_id) VALUES(?, ?, ?, ?)", + name, planned_amount_cox, allow_guests, trip_details_id + ) + .execute(db) + .await + .unwrap(); //TODO: fixme + } + + pub async fn delete(db: &SqlitePool, id: i64) { + sqlx::query!("DELETE FROM planned_event WHERE id = ?", id) + .execute(db) + .await + .unwrap(); //TODO: fixme + } +} diff --git a/src/model/tripdetails.rs b/src/model/tripdetails.rs new file mode 100644 index 0000000..9ea0d56 --- /dev/null +++ b/src/model/tripdetails.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; +use sqlx::{FromRow, SqlitePool}; + +#[derive(FromRow, Debug, Serialize, Deserialize)] +pub struct TripDetails { + pub id: i64, + planned_starting_time: String, + max_people: i32, + day: String, + notes: Option, +} + +impl TripDetails { + pub async fn new( + db: &SqlitePool, + planned_starting_time: String, + max_people: i32, + day: String, + notes: Option, + ) -> i64 { + let query = sqlx::query!( + "INSERT INTO trip_details(planned_starting_time, max_people, day, notes) VALUES(?, ?, ?, ?)" , + planned_starting_time, + max_people, + day, + notes + ) + .execute(db) + .await + .unwrap(); //TODO: fixme + query.last_insert_rowid() + } +} diff --git a/src/rest/admin/mod.rs b/src/rest/admin/mod.rs index 1056ce6..4733b2f 100644 --- a/src/rest/admin/mod.rs +++ b/src/rest/admin/mod.rs @@ -1,9 +1,11 @@ use rocket::Route; +pub mod planned_event; pub mod user; pub fn routes() -> Vec { let mut ret = Vec::new(); ret.append(&mut user::routes()); + ret.append(&mut planned_event::routes()); ret } diff --git a/src/rest/admin/planned_event.rs b/src/rest/admin/planned_event.rs new file mode 100644 index 0000000..941d739 --- /dev/null +++ b/src/rest/admin/planned_event.rs @@ -0,0 +1,61 @@ +use rocket::{ + form::Form, + get, post, + response::{Flash, Redirect}, + routes, FromForm, Route, State, +}; +use sqlx::SqlitePool; + +use crate::model::{planned_event::PlannedEvent, tripdetails::TripDetails, user::AdminUser}; + +//TODO: add constraints (e.g. planned_amount_cox > 0) +#[derive(FromForm)] +struct AddPlannedEventForm { + day: String, + name: String, + planned_amount_cox: i32, + allow_guests: bool, + planned_starting_time: String, + max_people: i32, + notes: Option, +} + +#[post("/planned-event", data = "")] +async fn create( + db: &State, + data: Form, + _admin: AdminUser, +) -> Flash { + //TODO: fix clones() + let trip_details_id = TripDetails::new( + db, + data.planned_starting_time.clone(), + data.max_people, + data.day.clone(), + data.notes.clone(), + ) + .await; + + //TODO: fix clone() + PlannedEvent::new( + db, + data.name.clone(), + data.planned_amount_cox, + data.allow_guests, + trip_details_id, + ) + .await; + + Flash::success(Redirect::to("/"), "Successfully planned the event") +} + +#[get("/planned-event//delete")] +async fn delete(db: &State, id: i64, _admin: AdminUser) -> Flash { + PlannedEvent::delete(db, id).await; + + Flash::success(Redirect::to("/"), "Successfully deleted the event") +} + +pub fn routes() -> Vec { + routes![create, delete] +} diff --git a/src/rest/admin/user.rs b/src/rest/admin/user.rs index 7c944d2..f345e7f 100644 --- a/src/rest/admin/user.rs +++ b/src/rest/admin/user.rs @@ -38,7 +38,11 @@ struct UserEditForm { } #[post("/user", data = "")] -async fn update(db: &State, data: Form) -> Flash { +async fn update( + db: &State, + data: Form, + _admin: AdminUser, +) -> Flash { let user = User::find_by_id(db, data.id).await; let user = match user { Ok(user) => user, diff --git a/src/rest/mod.rs b/src/rest/mod.rs index 59ef60e..6dbc05c 100644 --- a/src/rest/mod.rs +++ b/src/rest/mod.rs @@ -1,15 +1,21 @@ -use rocket::{catch, catchers, get, response::Redirect, routes, Build, Rocket}; +use chrono::{Duration, Local, NaiveDate}; +use rocket::{catch, catchers, get, response::Redirect, routes, Build, Rocket, State}; use rocket_dyn_templates::{context, Template}; use sqlx::SqlitePool; -use crate::model::user::User; +use crate::model::{user::User, Day}; mod admin; mod auth; #[get("/")] -fn index(user: User) -> Template { - Template::render("index", context! {loggedin_user: user}) +async fn index(db: &State, user: User) -> Template { + let mut days = Vec::new(); + for i in 0..6 { + let date = (Local::now() + Duration::days(i)).date_naive(); + days.push(Day::new(db, date).await); + } + Template::render("index", context! {loggedin_user: user, days}) } #[catch(401)] //unauthorized diff --git a/templates/index.html.tera b/templates/index.html.tera index 3348466..e7813c2 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -27,6 +27,40 @@ {% endif %} {% endif %} -

Hi

+

Ausfahrten

+ +{% for day in days %} +

{{ day.day }}

+ + {% for planned_event in day.planned_events %} +

Planned event '{{ planned_event.name }}'

+ Planned amount cox: {{ planned_event.planned_amount_cox }}
+ Allow guests: {{ planned_event.allow_guests }}
+ Planned starting time: {{ planned_event.planned_starting_time }}
+ Max people: {{ planned_event.max_people }}
+ Notes: {{ planned_event.notes }}
+ + {% if loggedin_user.is_admin %} + DELETE + {% endif %} + {% endfor %} + + {% if loggedin_user.is_admin %} +

Add planned event

+
+ + + + Gäste + + + + + +
+ {% endif %} + +
+{% endfor %} {% endblock content %}