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"
|
||||
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"
|
||||
|
@ -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"]}
|
||||
|
||||
|
23
README.md
23
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<i32> (trip_details.id)
|
||||
- planned_event_id: Option<i32> (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
|
||||
|
@ -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
|
||||
);
|
||||
|
@ -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<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;
|
||||
|
||||
pub mod planned_event;
|
||||
pub mod user;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
let mut ret = Vec::new();
|
||||
ret.append(&mut user::routes());
|
||||
ret.append(&mut planned_event::routes());
|
||||
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>")]
|
||||
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 = match 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 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<SqlitePool>, 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
|
||||
|
@ -27,6 +27,40 @@
|
||||
{% 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 %}
|
||||
|
Loading…
Reference in New Issue
Block a user