add planned_trip functionality
This commit is contained in:
parent
3dfc64071c
commit
3d907487a1
32
Cargo.lock
generated
32
Cargo.lock
generated
@ -229,8 +229,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
|
checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
"time 0.1.45",
|
||||||
|
"wasm-bindgen",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -289,7 +293,7 @@ dependencies = [
|
|||||||
"rand",
|
"rand",
|
||||||
"sha2",
|
"sha2",
|
||||||
"subtle",
|
"subtle",
|
||||||
"time",
|
"time 0.3.20",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -716,7 +720,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1203,7 +1207,7 @@ checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1732,7 +1736,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"state",
|
"state",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"time",
|
"time 0.3.20",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@ -1792,7 +1796,7 @@ dependencies = [
|
|||||||
"smallvec",
|
"smallvec",
|
||||||
"stable-pattern",
|
"stable-pattern",
|
||||||
"state",
|
"state",
|
||||||
"time",
|
"time 0.3.20",
|
||||||
"tokio",
|
"tokio",
|
||||||
"uncased",
|
"uncased",
|
||||||
]
|
]
|
||||||
@ -1802,6 +1806,7 @@ name = "rot"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2",
|
"argon2",
|
||||||
|
"chrono",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"rocket",
|
"rocket",
|
||||||
@ -2237,6 +2242,17 @@ dependencies = [
|
|||||||
"once_cell",
|
"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]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.20"
|
version = "0.3.20"
|
||||||
@ -2618,6 +2634,12 @@ dependencies = [
|
|||||||
"try-lock",
|
"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]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -14,3 +14,5 @@ sqlx = { version = "0.6", features = ["sqlite", "runtime-tokio-rustls", "macros"
|
|||||||
argon2 = "0.5"
|
argon2 = "0.5"
|
||||||
serde = { version = "1.0", features = [ "derive" ]}
|
serde = { version = "1.0", features = [ "derive" ]}
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
chrono = { version = "0.4", features = ["serde"]}
|
||||||
|
|
||||||
|
23
README.md
23
README.md
@ -17,31 +17,12 @@
|
|||||||
|
|
||||||
# DB
|
# 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
|
- trip
|
||||||
- id: i32
|
- id: i32
|
||||||
- cox_id: i32 (user.id)
|
- cox_id: i32 (user.id)
|
||||||
- trip_details: Option<i32> (trip_details.id)
|
- trip_details: Option<i32> (trip_details.id)
|
||||||
- planned_event_id: Option<i32> (planned_event.id)
|
- planned_event_id: Option<i32> (planned_event.id)
|
||||||
- created: chrono::DateTime
|
- created: chrono::DateTime
|
||||||
- trip_details
|
|
||||||
- id: i32
|
|
||||||
- planned_starting_time: String
|
|
||||||
- max_people: i32
|
|
||||||
- day: chrono::NaiveDate
|
|
||||||
- notes: String
|
|
||||||
- user_trip
|
- user_trip
|
||||||
- trip_details_id: i32 (trip_details.id)
|
- trip_details_id: i32 (trip_details.id)
|
||||||
- user_id: i32 (user.id)
|
- user_id: i32 (user.id)
|
||||||
@ -54,7 +35,7 @@
|
|||||||
- [x] User passwort zurücksetzen
|
- [x] User passwort zurücksetzen
|
||||||
- [x] Cox + admin + guest setzen
|
- [x] Cox + admin + guest setzen
|
||||||
- [ ] Ausfahrten
|
- [ ] Ausfahrten
|
||||||
- [ ] CRUD planned_event
|
- [x] CRUD planned_event
|
||||||
- [ ] CRUD trip_details
|
- [x] CRUD trip_details
|
||||||
- [ ] CRUD trip
|
- [ ] CRUD trip
|
||||||
- [ ] CRUD user_trip
|
- [ ] CRUD user_trip
|
||||||
|
@ -6,3 +6,21 @@ CREATE TABLE IF NOT EXISTS "user" (
|
|||||||
"is_admin" boolean NOT NULL DEFAULT FALSE,
|
"is_admin" boolean NOT NULL DEFAULT FALSE,
|
||||||
"is_guest" boolean NOT NULL DEFAULT TRUE
|
"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
|
||||||
|
);
|
||||||
|
@ -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 user;
|
||||||
//pub mod users;
|
//pub mod users;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Day {
|
||||||
|
day: NaiveDate,
|
||||||
|
planned_events: Vec<PlannedEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Day {
|
||||||
|
pub async fn new(db: &SqlitePool, day: NaiveDate) -> Self {
|
||||||
|
Self {
|
||||||
|
day,
|
||||||
|
planned_events: PlannedEvent::get_for_day(db, day).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
55
src/model/planned_event.rs
Normal file
55
src/model/planned_event.rs
Normal file
@ -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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlannedEvent {
|
||||||
|
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<Self> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
33
src/model/tripdetails.rs
Normal file
33
src/model/tripdetails.rs
Normal file
@ -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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TripDetails {
|
||||||
|
pub async fn new(
|
||||||
|
db: &SqlitePool,
|
||||||
|
planned_starting_time: String,
|
||||||
|
max_people: i32,
|
||||||
|
day: String,
|
||||||
|
notes: Option<String>,
|
||||||
|
) -> 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()
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
|
|
||||||
|
pub mod planned_event;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
ret.append(&mut user::routes());
|
ret.append(&mut user::routes());
|
||||||
|
ret.append(&mut planned_event::routes());
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
61
src/rest/admin/planned_event.rs
Normal file
61
src/rest/admin/planned_event.rs
Normal file
@ -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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/planned-event", data = "<data>")]
|
||||||
|
async fn create(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<AddPlannedEventForm>,
|
||||||
|
_admin: AdminUser,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
//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/<id>/delete")]
|
||||||
|
async fn delete(db: &State<SqlitePool>, id: i64, _admin: AdminUser) -> Flash<Redirect> {
|
||||||
|
PlannedEvent::delete(db, id).await;
|
||||||
|
|
||||||
|
Flash::success(Redirect::to("/"), "Successfully deleted the event")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn routes() -> Vec<Route> {
|
||||||
|
routes![create, delete]
|
||||||
|
}
|
@ -38,7 +38,11 @@ struct UserEditForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/user", data = "<data>")]
|
#[post("/user", data = "<data>")]
|
||||||
async fn update(db: &State<SqlitePool>, data: Form<UserEditForm>) -> Flash<Redirect> {
|
async fn update(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<UserEditForm>,
|
||||||
|
_admin: AdminUser,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
let user = User::find_by_id(db, data.id).await;
|
let user = User::find_by_id(db, data.id).await;
|
||||||
let user = match user {
|
let user = match user {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
|
@ -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 rocket_dyn_templates::{context, Template};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::model::user::User;
|
use crate::model::{user::User, Day};
|
||||||
|
|
||||||
mod admin;
|
mod admin;
|
||||||
mod auth;
|
mod auth;
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
fn index(user: User) -> Template {
|
async fn index(db: &State<SqlitePool>, user: User) -> Template {
|
||||||
Template::render("index", context! {loggedin_user: user})
|
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
|
#[catch(401)] //unauthorized
|
||||||
|
@ -27,6 +27,40 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1>Hi</h1>
|
<h1>Ausfahrten</h1>
|
||||||
|
|
||||||
|
{% for day in days %}
|
||||||
|
<h2>{{ day.day }}</h2>
|
||||||
|
|
||||||
|
{% for planned_event in day.planned_events %}
|
||||||
|
<h3>Planned event '{{ planned_event.name }}'</h3>
|
||||||
|
Planned amount cox: {{ planned_event.planned_amount_cox }}<br />
|
||||||
|
Allow guests: {{ planned_event.allow_guests }}<br />
|
||||||
|
Planned starting time: {{ planned_event.planned_starting_time }}<br />
|
||||||
|
Max people: {{ planned_event.max_people }}<br />
|
||||||
|
Notes: {{ planned_event.notes }}<br />
|
||||||
|
|
||||||
|
{% if loggedin_user.is_admin %}
|
||||||
|
<a href="/admin/planned-event/{{ planned_event.id }}/delete">DELETE</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if loggedin_user.is_admin %}
|
||||||
|
<h3>Add planned event</h3>
|
||||||
|
<form action="/admin/planned-event" method="post">
|
||||||
|
<input type="hidden" name="day" value="{{ day.day }}" />
|
||||||
|
<input type="text" name="name" placeholder="name (e.g. USI)" />
|
||||||
|
<input type="number" name="planned_amount_cox" placeholder="Anzahl Steuerleute" />
|
||||||
|
Gäste <input type="checkbox" name="allow_guests" />
|
||||||
|
<input type="text" name="planned_starting_time" placeholder="Startzeit" />
|
||||||
|
<input type="number" name="max_people" placeholder="Anzahl Ruderer" />
|
||||||
|
<input type="text" name="notes" placeholder="Anmerkungen" />
|
||||||
|
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
Loading…
Reference in New Issue
Block a user