Merge branch 'main' of gitlab.com:PhilippHofer/rot

This commit is contained in:
Philipp 2023-07-23 18:18:29 +02:00
commit e601630e9d
6 changed files with 150 additions and 72 deletions

View File

@ -4,8 +4,7 @@
## New large features ## New large features
### Logbuch ### Logbuch
Next: - Next: add rower to logbook
- Start with CREATE for logbook
### Guest-Scheckbuch ### Guest-Scheckbuch
- guest_trip - guest_trip

View File

@ -2,6 +2,8 @@ use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool}; use sqlx::{FromRow, SqlitePool};
use super::user::User;
#[derive(FromRow, Debug, Serialize, Deserialize)] #[derive(FromRow, Debug, Serialize, Deserialize)]
pub struct Logbook { pub struct Logbook {
pub id: i64, pub id: i64,
@ -34,22 +36,31 @@ pub struct LogbookWithBoatAndUsers {
pub shipmaster_name: String, pub shipmaster_name: String,
} }
pub enum LogbookUpdateError {
NotYourEntry,
}
pub enum LogbookCreateError {
BoatAlreadyOnWater,
BoatLocked
}
impl Logbook { impl Logbook {
//pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> { pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
// sqlx::query_as!( sqlx::query_as!(
// Self, Self,
// " "
//SELECT id, name, amount_seats, location_id, owner, year_built, boatbuilder, default_shipmaster_only_steering, skull, external SELECT id,boat_id,shipmaster,shipmaster_only_steering,departure,arrival,destination,distance_in_km,comments,logtype
//FROM boat FROM logbook
//WHERE id like ? WHERE id like ?
// ", ",
// id id
// ) )
// .fetch_one(db) .fetch_one(db)
// .await .await
// .ok() .ok()
//} }
//
// pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option<Self> { // pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option<Self> {
// sqlx::query_as!( // sqlx::query_as!(
// User, // User,
@ -110,46 +121,48 @@ impl Logbook {
distance_in_km: Option<i64>, distance_in_km: Option<i64>,
comments: Option<String>, comments: Option<String>,
logtype: Option<i64>, logtype: Option<i64>,
) -> bool { ) -> Result<(), LogbookCreateError> {
//Check if boat is not locked
//Check if boat is already on water
sqlx::query!( sqlx::query!(
"INSERT INTO logbook(boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?)", "INSERT INTO logbook(boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype) VALUES (?,?,?,?,?,?,?,?,?)",
boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype boat_id, shipmaster, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype
) )
.execute(db) .execute(db)
.await.is_ok() .await;
Ok(())
} }
//
// pub async fn update( pub async fn home(
// &self, &self,
// db: &SqlitePool, db: &SqlitePool,
// name: &str, user: &User,
// amount_seats: i64, destination: String,
// year_built: Option<i64>, distance_in_km: i64,
// boatbuilder: Option<&str>, comments: Option<String>,
// default_shipmaster_only_steering: bool, logtype: Option<i64>,
// skull: bool, ) -> Result<(), LogbookUpdateError> {
// external: bool, if user.id != self.shipmaster {
// location_id: Option<i64>, return Err(LogbookUpdateError::NotYourEntry);
// owner: Option<i64>, }
// ) -> bool { //TODO: check current date
// sqlx::query!(
// "UPDATE boat SET name=?, amount_seats=?, year_built=?, boatbuilder=?, default_shipmaster_only_steering=?, skull=?, external=?, location_id=?, owner=? WHERE id=?", let arrival = format!("{}", chrono::offset::Local::now().format("%Y-%m-%d %H:%M"));
// name,
// amount_seats, sqlx::query!(
// year_built, "UPDATE logbook SET destination=?, distance_in_km=?, comments=?, logtype=?, arrival=? WHERE id=?",
// boatbuilder, destination,
// default_shipmaster_only_steering, distance_in_km,
// skull, comments,
// external, logtype,
// location_id, arrival,
// owner, self.id
// self.id )
// ) .execute(db)
// .execute(db) .await.unwrap(); //TODO: fixme
// .await Ok(())
// .is_ok() }
// }
//
// pub async fn delete(&self, db: &SqlitePool) { // pub async fn delete(&self, db: &SqlitePool) {
// sqlx::query!("DELETE FROM boat WHERE id=?", self.id) // sqlx::query!("DELETE FROM boat WHERE id=?", self.id)
// .execute(db) // .execute(db)

View File

@ -64,7 +64,7 @@ async fn create(
data: Form<LogAddForm>, data: Form<LogAddForm>,
_adminuser: AdminUser, _adminuser: AdminUser,
) -> Flash<Redirect> { ) -> Flash<Redirect> {
if Logbook::create( match Logbook::create(
db, db,
data.boat_id, data.boat_id,
data.shipmaster, data.shipmaster,
@ -80,14 +80,61 @@ async fn create(
) )
.await .await
{ {
Flash::success(Redirect::to("/log"), "Ausfahrt erfolgreich hinzugefügt") Ok(_) => Flash::success(Redirect::to("/log"), "Ausfahrt erfolgreich hinzugefügt"),
} else { Err(_) => Flash::error(Redirect::to("/log"), format!("Fehler beim hinzufügen!"))
Flash::error(Redirect::to("/log"), format!("Fehler beim hinzufügen!"))
}
} }
}
#[derive(FromForm)]
struct LogHomeForm {
destination: String,
distance_in_km: i64,
comments: Option<String>,
logtype: Option<i64>,
}
#[post("/<logbook_id>", data = "<data>")]
async fn home(
db: &State<SqlitePool>,
data: Form<LogHomeForm>,
logbook_id: i32,
_adminuser: AdminUser,
) -> 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,
&_adminuser.user,
data.destination.clone(), //TODO: fixme
data.distance_in_km,
data.comments.clone(), //TODO: fixme
data.logtype
)
.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),
)
}
}
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![index, create] routes![index, create, home]
} }
#[cfg(test)] #[cfg(test)]

View File

@ -15,9 +15,9 @@
<div class="-space-y-px rounded-md shadow-sm"> <div class="-space-y-px rounded-md shadow-sm">
<div> <div>
{% if name %} {% if name %}
{{ macros::input(label='Name', name='name', type='input', required=true, class='rounded-t-md',hide_label=true,value=name) }} {{ macros::input(label='Name', name='name', type='input', required=true, class='rounded-t-md',hide_label=true,value=name, autofocus=true) }}
{% else %} {% else %}
{{ macros::input(label='Name', name='name', type='input', required=true, class='rounded-t-md',hide_label=true) }} {{ macros::input(label='Name', name='name', type='input', required=true, class='rounded-t-md',hide_label=true, autofocus=true) }}
{% endif %} {% endif %}
</div> </div>

View File

@ -38,10 +38,10 @@
<div class="h-8"></div> <div class="h-8"></div>
{% endmacro header %} {% endmacro header %}
{% macro input(label, name, type, required=false, class='rounded-md', value='', min='', hide_label=false) %} {% macro input(label, name, type, required=false, class='rounded-md', value='', min='', hide_label=false, id='', autofocus=false) %}
<div> <div>
<label for="{{ name }}" class="{% if hide_label %} sr-only {% else %} small text-gray-600 {% endif %}">{{ label }}</label> <label for="{{ name }}" class="{% if hide_label %} sr-only {% else %} small text-gray-600 {% endif %}">{{ label }}</label>
<input id="{{ name }}" name="{{ name }}" type="{{ type }}" {% if required %} required {% endif %} value="{{ value }}" class="input {{ class }}" placeholder="{% if hide_label %}{{ label }}{% endif %}" {% if min %} min="{{ min }}" {% endif %}> <input {% if id %} id="{{ id }}" {% else %} id="{{ name }}" {% endif %} name="{{ name }}" type="{{ type }}" {% if required %} required {% endif %} value="{{ value }}" class="input {{ class }}" placeholder="{% if hide_label %}{{ label }}{% endif %}" {% if min %} min="{{ min }}" {% endif %}{% if autofocus %}autofocus {% endif %}>
</div> </div>
{% endmacro input %} {% endmacro input %}

View File

@ -32,7 +32,7 @@
<option value="Ottensheim" distance=25 /> <option value="Ottensheim" distance=25 />
<option value="Ottensheim + Regattastrecke" distance=29 /> <option value="Ottensheim + Regattastrecke" distance=29 />
</datalist> </datalist>
{{ macros::input(label="Distanz", name="distance_in_km", type="number", min=0) }}<!-- TODO: depending on destination, pre-fill this distance --> {{ 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") }}
<input type="submit" /> <input type="submit" />
@ -62,6 +62,24 @@
Ziel: {{ log.destination }}<br /> Ziel: {{ log.destination }}<br />
Kommentare: {{ log.comments }}<br /> Kommentare: {{ log.comments }}<br />
Logtype: {{ log.logtype }}<br /> Logtype: {{ log.logtype }}<br />
{% if log.shipmaster == loggedin_user.id %}
<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');
var dataList = document.getElementById('destinations');
var selectedValue = inputElement.value;
for (var i = 0; i < dataList.options.length; i++) {
if (dataList.options[i].value === selectedValue) {
var distance = dataList.options[i].getAttribute('distance');
document.getElementById('distance_in_km_home').value = distance;
break;
}
}">
{{ macros::input(label="Distanz", name="distance_in_km", id="distance_in_km_home", type="number", min=0, value=log.distance_in_km) }}
{{ macros::input(label="Kommentar", name="comments", type="text", value=log.comments) }}
{{ macros::select(data=logtypes, select_name='logtype', default="Normal", selected_id=log.logtype) }}
<input type="submit" value="AUSFAHRT BEENDEN"/>
</form>
{% endif %}
<hr /> <hr />
{% endfor %} {% endfor %}
@ -75,6 +93,7 @@
Weggefahren: {{ log.departure }}<br /> Weggefahren: {{ log.departure }}<br />
Angekommen: {{ log.arrival}}<br /> Angekommen: {{ log.arrival}}<br />
Ziel: {{ log.destination }}<br /> Ziel: {{ log.destination }}<br />
Km: {{ log.distance_in_km }}<br />
Kommentare: {{ log.comments }}<br /> Kommentare: {{ log.comments }}<br />
Logtype: {{ log.logtype }}<br /> Logtype: {{ log.logtype }}<br />
<hr /> <hr />