Merge branch 'main' of gitlab.com:PhilippHofer/rot
This commit is contained in:
commit
e601630e9d
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)]
|
||||||
|
@ -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>
|
||||||
|
@ -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 %}
|
||||||
|
|
||||||
|
@ -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 />
|
||||||
|
Loading…
Reference in New Issue
Block a user