forked from Ruderverein-Donau-Linz/rowt
add kiosk mode
This commit is contained in:
parent
b3349c87ff
commit
38300d826a
@ -5,6 +5,7 @@
|
|||||||
## New large features
|
## New large features
|
||||||
### Logbuch
|
### Logbuch
|
||||||
- Only layout + tests missing :-)
|
- Only layout + tests missing :-)
|
||||||
|
|
||||||
### Guest-Scheckbuch
|
### Guest-Scheckbuch
|
||||||
- guest_trip
|
- guest_trip
|
||||||
- guest_user_id
|
- guest_user_id
|
||||||
|
105
src/tera/log.rs
105
src/tera/log.rs
@ -1,9 +1,9 @@
|
|||||||
use rocket::{
|
use rocket::{
|
||||||
form::Form,
|
form::Form,
|
||||||
get, post,
|
get, post,
|
||||||
request::FlashMessage,
|
request::{FlashMessage, FromRequest, self},
|
||||||
response::{Flash, Redirect},
|
response::{Flash, Redirect},
|
||||||
routes, Route, State,
|
routes, Route, State, Request, http::{CookieJar, Cookie}, time::{OffsetDateTime, Duration},
|
||||||
};
|
};
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
@ -16,6 +16,20 @@ use crate::model::{
|
|||||||
user::{AdminUser, User},
|
user::{AdminUser, User},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct KioskCookie(String);
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromRequest<'r> for KioskCookie {
|
||||||
|
type Error = std::convert::Infallible;
|
||||||
|
|
||||||
|
async fn from_request(request: &'r Request<'_>) -> request::Outcome<KioskCookie, Self::Error> {
|
||||||
|
match request.cookies().get_private("kiosk") {
|
||||||
|
Some(cookie) => request::Outcome::Success(KioskCookie(cookie.value().to_string())),
|
||||||
|
None => request::Outcome::Forward(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn index(
|
async fn index(
|
||||||
db: &State<SqlitePool>,
|
db: &State<SqlitePool>,
|
||||||
@ -48,7 +62,46 @@ async fn index(
|
|||||||
Template::render("log", context.into_json())
|
Template::render("log", context.into_json())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/", data = "<data>")]
|
|
||||||
|
#[get("/kiosk/ekrv2019")]
|
||||||
|
fn new_kiosk(
|
||||||
|
flash: Option<FlashMessage<'_>>,
|
||||||
|
cookies: &CookieJar<'_>,
|
||||||
|
) -> Redirect {
|
||||||
|
let mut cookie = Cookie::new("kiosk", format!("yes"));
|
||||||
|
cookie.set_expires(OffsetDateTime::now_utc() + Duration::weeks(12));
|
||||||
|
cookies.add_private(cookie);
|
||||||
|
Redirect::to("/log/kiosk")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/kiosk")]
|
||||||
|
async fn kiosk(db: &State<SqlitePool>, flash: Option<FlashMessage<'_>>, _kiosk: KioskCookie) -> Template {
|
||||||
|
let boats = Boat::all(db).await;
|
||||||
|
let coxes = User::cox(db).await;
|
||||||
|
let users = User::all(db).await;
|
||||||
|
let logtypes = LogType::all(db).await;
|
||||||
|
let distances = Logbook::distances(db).await;
|
||||||
|
|
||||||
|
let on_water = Logbook::on_water(db).await;
|
||||||
|
let completed = Logbook::completed(db).await;
|
||||||
|
|
||||||
|
let mut context = Context::new();
|
||||||
|
if let Some(msg) = flash {
|
||||||
|
context.insert("flash", &msg.into_inner());
|
||||||
|
}
|
||||||
|
|
||||||
|
context.insert("boats", &boats);
|
||||||
|
context.insert("coxes", &coxes);
|
||||||
|
context.insert("users", &users);
|
||||||
|
context.insert("logtypes", &logtypes);
|
||||||
|
context.insert("on_water", &on_water);
|
||||||
|
context.insert("completed", &completed);
|
||||||
|
context.insert("distances", &distances);
|
||||||
|
|
||||||
|
Template::render("kiosk", context.into_json())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/", data = "<data>", rank=2)]
|
||||||
async fn create(
|
async fn create(
|
||||||
db: &State<SqlitePool>,
|
db: &State<SqlitePool>,
|
||||||
data: Form<LogToAdd>,
|
data: Form<LogToAdd>,
|
||||||
@ -68,7 +121,51 @@ async fn create(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/", data = "<data>")]
|
||||||
|
async fn create_kiosk(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<LogToAdd>,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
match Logbook::create(
|
||||||
|
db,
|
||||||
|
data.into_inner()
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Flash::success(Redirect::to("/log/kiosk"), "Ausfahrt erfolgreich hinzugefügt"),
|
||||||
|
Err(LogbookCreateError::BoatAlreadyOnWater) => Flash::error(Redirect::to("/log/kiosk"), format!("Boot schon am Wasser")),
|
||||||
|
Err(LogbookCreateError::BoatLocked) => Flash::error(Redirect::to("/log/kiosk"), format!("Boot gesperrt")),
|
||||||
|
Err(LogbookCreateError::BoatNotFound) => Flash::error(Redirect::to("/log/kiosk"), format!("Boot gibt's ned")),
|
||||||
|
Err(LogbookCreateError::TooManyRowers(expected, actual)) => Flash::error(Redirect::to("/log/kiosk"), format!("Zu viele Ruderer (Boot fasst maximal {expected}, es wurden jedoch {actual} Ruderer ausgewählt)")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[post("/<logbook_id>", data = "<data>")]
|
#[post("/<logbook_id>", data = "<data>")]
|
||||||
|
async fn home_kiosk(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<LogToFinalize>,
|
||||||
|
logbook_id: i32,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
let logbook = Logbook::find_by_id(db, logbook_id).await;
|
||||||
|
let Some(logbook) = logbook else {
|
||||||
|
return Flash::error(
|
||||||
|
Redirect::to("/admin/log"),
|
||||||
|
format!("Log with ID {} does not exist!", logbook_id),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
match logbook.home(db, &User::find_by_id(db, logbook.shipmaster as i32).await.unwrap(), data.into_inner()).await {
|
||||||
|
Ok(_) => Flash::success(Redirect::to("/log"), "Successfully updated log"),
|
||||||
|
Err(_) => Flash::error(
|
||||||
|
Redirect::to("/log"),
|
||||||
|
format!("Logbook with ID {} could not be updated!", logbook_id),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[post("/<logbook_id>", data = "<data>", rank=2)]
|
||||||
async fn home(
|
async fn home(
|
||||||
db: &State<SqlitePool>,
|
db: &State<SqlitePool>,
|
||||||
data: Form<LogToFinalize>,
|
data: Form<LogToFinalize>,
|
||||||
@ -93,7 +190,7 @@ async fn home(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![index, create, home]
|
routes![index, create, create_kiosk, home, kiosk, home_kiosk, new_kiosk]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{% macro new() %}
|
{% macro new(only_ones, allow_any_shipmaster, shipmaster) %}
|
||||||
<form action="/log" method="post" id="form">
|
<form action="/log" method="post" id="form">
|
||||||
{% if loggedin_user.is_cox %}
|
{% if not only_ones %}
|
||||||
{{ macros::select(data=boats, select_name='boat_id', display=["name", " (","amount_seats", " x)"], extras=["default_shipmaster_only_steering", "amount_seats"]) }}
|
{{ macros::select(data=boats, select_name='boat_id', display=["name", " (","amount_seats", " x)"], extras=["default_shipmaster_only_steering", "amount_seats"]) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% set ones = boats | filter(attribute="amount_seats", value=1) %}
|
{% set ones = boats | filter(attribute="amount_seats", value=1) %}
|
||||||
@ -18,23 +18,23 @@
|
|||||||
document.getElementById('boat_id').addEventListener('change', updateElementsBasedOnSelectedOption);
|
document.getElementById('boat_id').addEventListener('change', updateElementsBasedOnSelectedOption);
|
||||||
document.addEventListener('DOMContentLoaded', updateElementsBasedOnSelectedOption);
|
document.addEventListener('DOMContentLoaded', updateElementsBasedOnSelectedOption);
|
||||||
</script>
|
</script>
|
||||||
{% if loggedin_user.is_cox %}
|
{% if allow_any_shipmaster %}
|
||||||
<select name="shipmaster" id="shipmaster" class="input rounded-md h-10">
|
<select name="shipmaster" id="shipmaster" class="input rounded-md h-10">
|
||||||
<optgroup label="Steuerpersonen">
|
<optgroup label="Steuerpersonen">
|
||||||
{% for cox in coxes %}
|
{% for cox in coxes %}
|
||||||
<option value="{{ cox.id }}" {% if cox.id == loggedin_user.id%} selected {% endif %}>{{ cox.name }}</option>
|
<option value="{{ cox.id }}" {% if cox.id == shipmaster%} selected {% endif %}>{{ cox.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</optgroup>
|
</optgroup>
|
||||||
<optgroup label="Restliche Mitglieder">
|
<optgroup label="Restliche Mitglieder">
|
||||||
{% for user in users | filter(attribute="is_cox", value=false) %}
|
{% for user in users | filter(attribute="is_cox", value=false) %}
|
||||||
<option value="{{ user.id }}" {% if user.id == loggedin_user.id%} selected {% endif %}>{{ user.name }}</option>
|
<option value="{{ user.id }}" {% if user.id == shipmaster%} selected {% endif %}>{{ user.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="hidden" name="shipmaster" value="{{loggedin_user.id}}" />
|
<input type="hidden" name="shipmaster" value="{{shipmaster}}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if loggedin_user.is_cox %}
|
{% if only_ones %}
|
||||||
{{ macros::checkbox(label='shipmaster_only_steering', name='shipmaster_only_steering') }}
|
{{ macros::checkbox(label='shipmaster_only_steering', name='shipmaster_only_steering') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Departure: <input type="datetime-local" id="datetime-dep" name="departure" required/>
|
Departure: <input type="datetime-local" id="datetime-dep" name="departure" required/>
|
||||||
@ -57,7 +57,7 @@
|
|||||||
{{ macros::input(label="Distanz", name="distance_in_km", type="number", min=0) }}
|
{{ macros::input(label="Distanz", name="distance_in_km", type="number", min=0) }}
|
||||||
{{ macros::input(label="Kommentar", name="comments", type="text") }}
|
{{ macros::input(label="Kommentar", name="comments", type="text") }}
|
||||||
{{ macros::select(data=logtypes, select_name='logtype', default="Normal") }}
|
{{ macros::select(data=logtypes, select_name='logtype', default="Normal") }}
|
||||||
{% if loggedin_user.is_cox %}
|
{% if not only_ones %}
|
||||||
{{ log::rower_select(id="newrower", selected=[]) }}
|
{{ log::rower_select(id="newrower", selected=[]) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
@ -86,7 +86,7 @@
|
|||||||
{% endmacro new %}
|
{% endmacro new %}
|
||||||
|
|
||||||
|
|
||||||
{% macro show(log, state) %}
|
{% macro show(log, state, allowed_to_close=false, only_ones) %}
|
||||||
Bootsname: {{ log.boat.name }}<br />
|
Bootsname: {{ log.boat.name }}<br />
|
||||||
Schiffsführer: {{ log.shipmaster_user.name }}<br />
|
Schiffsführer: {{ log.shipmaster_user.name }}<br />
|
||||||
{% if log.shipmaster_only_steering %}
|
{% if log.shipmaster_only_steering %}
|
||||||
@ -98,8 +98,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% set amount_rowers = log.rowers | length %}
|
{% set amount_rowers = log.rowers | length %}
|
||||||
{% set amount_guests = log.boat.amount_seats - amount_rowers -1 %}
|
{% set amount_guests = log.boat.amount_seats - amount_rowers -1 %}
|
||||||
{% if log.shipmaster == loggedin_user.id and state == "on_water" %}
|
{% if allowed_to_close and state == "on_water" %}
|
||||||
{{ log::home(log=log) }}
|
{{ log::home(log=log, only_ones=only_ones) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
Ziel: {{ log.destination }}<br />
|
Ziel: {{ log.destination }}<br />
|
||||||
{% if state == "completed" %}
|
{% if state == "completed" %}
|
||||||
@ -123,7 +123,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro show %}
|
{% endmacro show %}
|
||||||
|
|
||||||
{% macro home(log) %}
|
{% macro home(log, only_ones) %}
|
||||||
<form action="/log/{{log.id}}" method="post">
|
<form action="/log/{{log.id}}" method="post">
|
||||||
Destination: <input type="search" list="destinations" placeholder="Destination" id="destination-home" name="destination" value="{{log.destination}}" oninput="var inputElement = document.getElementById('destination-home');
|
Destination: <input type="search" list="destinations" placeholder="Destination" id="destination-home" name="destination" value="{{log.destination}}" oninput="var inputElement = document.getElementById('destination-home');
|
||||||
var dataList = document.getElementById('destinations');
|
var dataList = document.getElementById('destinations');
|
||||||
@ -139,7 +139,7 @@
|
|||||||
{{ macros::input(label="Kommentar", name="comments", type="text", value=log.comments) }}
|
{{ macros::input(label="Kommentar", name="comments", type="text", value=log.comments) }}
|
||||||
{{ macros::select(data=logtypes, select_name='logtype', default="Normal", selected_id=log.logtype) }}
|
{{ macros::select(data=logtypes, select_name='logtype', default="Normal", selected_id=log.logtype) }}
|
||||||
|
|
||||||
{% if loggedin_user.is_cox %}
|
{% if not only_ones %}
|
||||||
{{ log::rower_select(id="rowers"~log.id, selected=log.rowers, amount_seats=log.boat.amount_seats) }}
|
{{ log::rower_select(id="rowers"~log.id, selected=log.rowers, amount_seats=log.boat.amount_seats) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<input type="submit" value="AUSFAHRT BEENDEN"/>
|
<input type="submit" value="AUSFAHRT BEENDEN"/>
|
||||||
|
25
templates/kiosk.html.tera
Normal file
25
templates/kiosk.html.tera
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{% import "includes/macros" as macros %}
|
||||||
|
{% import "includes/forms/log" as log %}
|
||||||
|
|
||||||
|
{% extends "base" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="max-w-screen-lg w-full">
|
||||||
|
<h1 class="h1">Logbuch</h1>
|
||||||
|
<h2>Neue Ausfahrt starten</h2>
|
||||||
|
{{ log::new(only_ones=false, allow_any_shipmaster=true, shipmaster=-1) }}
|
||||||
|
|
||||||
|
<h2 style="font-size: 100px">Am Wasser</h2>
|
||||||
|
{% for log in on_water %}
|
||||||
|
{{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=false) }}
|
||||||
|
<hr />
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<h2 style="font-size: 100px">Einträge</h2>
|
||||||
|
{% for log in completed %}
|
||||||
|
{{ log::show(log=log, state="completed", only_ones=false) }}
|
||||||
|
<hr />
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock content%}
|
@ -7,17 +7,21 @@
|
|||||||
<div class="max-w-screen-lg w-full">
|
<div class="max-w-screen-lg w-full">
|
||||||
<h1 class="h1">Logbuch</h1>
|
<h1 class="h1">Logbuch</h1>
|
||||||
<h2>Neue Ausfahrt starten</h2>
|
<h2>Neue Ausfahrt starten</h2>
|
||||||
{{ log::new() }}
|
{{ log::new(only_ones=loggedin_user.is_cox==false, allow_any_shipmaster=loggedin_user.is_cox, shipmaster=loggedin_user.id) }}
|
||||||
|
|
||||||
<h2 style="font-size: 100px">Am Wasser</h2>
|
<h2 style="font-size: 100px">Am Wasser</h2>
|
||||||
{% for log in on_water %}
|
{% for log in on_water %}
|
||||||
{{ log::show(log=log, state="on_water") }}
|
{% if log.shipmaster == loggedin_user.id %}
|
||||||
|
{{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=false) }}
|
||||||
|
{% else %}
|
||||||
|
{{ log::show(log=log, state="on_water", only_ones=true) }}
|
||||||
|
{% endif %}
|
||||||
<hr />
|
<hr />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<h2 style="font-size: 100px">Einträge</h2>
|
<h2 style="font-size: 100px">Einträge</h2>
|
||||||
{% for log in completed %}
|
{% for log in completed %}
|
||||||
{{ log::show(log=log, state="completed") }}
|
{{ log::show(log=log, state="completed", only_ones=false) }}
|
||||||
<hr />
|
<hr />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user