Merge pull request 'update logbook entries' (#634) from update-logbook-entries into main
Reviewed-on: #634
This commit is contained in:
commit
1db09cd8ac
@ -60,6 +60,22 @@ pub struct LogToFinalize {
|
|||||||
pub rowers: Vec<i64>,
|
pub rowers: Vec<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm, Debug, Clone)]
|
||||||
|
pub struct LogToUpdate {
|
||||||
|
pub id: i64,
|
||||||
|
pub boat_id: i64,
|
||||||
|
pub shipmaster: i64,
|
||||||
|
pub steering_person: i64,
|
||||||
|
pub shipmaster_only_steering: bool,
|
||||||
|
pub departure: String,
|
||||||
|
pub arrival: Option<String>,
|
||||||
|
pub destination: Option<String>,
|
||||||
|
pub distance_in_km: Option<i64>,
|
||||||
|
pub comments: Option<String>,
|
||||||
|
pub logtype: Option<i64>,
|
||||||
|
pub rowers: Vec<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<LogToAdd> for LogToFinalize {
|
impl TryFrom<LogToAdd> for LogToFinalize {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
@ -94,6 +110,11 @@ pub struct LogbookWithBoatAndRowers {
|
|||||||
pub rowers: Vec<User>,
|
pub rowers: Vec<User>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum LogbookAdminUpdateError {
|
||||||
|
NotAllowed,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum LogbookUpdateError {
|
pub enum LogbookUpdateError {
|
||||||
NotYourEntry,
|
NotYourEntry,
|
||||||
@ -172,7 +193,7 @@ impl Logbook {
|
|||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
|
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
@ -437,6 +458,35 @@ ORDER BY departure DESC
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update(
|
||||||
|
&self,
|
||||||
|
db: &SqlitePool,
|
||||||
|
data: LogToUpdate,
|
||||||
|
user: &User,
|
||||||
|
) -> Result<(), LogbookAdminUpdateError> {
|
||||||
|
if !user.has_role(db, "Vorstand").await {
|
||||||
|
return Err(LogbookAdminUpdateError::NotAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"UPDATE logbook SET boat_id=?, shipmaster=?, steering_person=?, shipmaster_only_steering=?, departure=?, arrival=?, destination=?, distance_in_km=?, comments=?, logtype=? WHERE id=?",
|
||||||
|
data.boat_id,
|
||||||
|
data.shipmaster,
|
||||||
|
data.steering_person,
|
||||||
|
data.shipmaster_only_steering,
|
||||||
|
data.departure,
|
||||||
|
data.arrival,
|
||||||
|
data.destination,
|
||||||
|
data.distance_in_km,
|
||||||
|
data.comments,
|
||||||
|
data.logtype,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
.execute(db)
|
||||||
|
.await.unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn distances(db: &SqlitePool) -> Vec<(String, i64)> {
|
pub async fn distances(db: &SqlitePool) -> Vec<(String, i64)> {
|
||||||
let result = sqlx::query!("SELECT destination, distance_in_km FROM logbook WHERE id IN (SELECT MIN(id) FROM logbook GROUP BY destination) AND destination IS NOT NULL AND distance_in_km IS NOT NULL;")
|
let result = sqlx::query!("SELECT destination, distance_in_km FROM logbook WHERE id IN (SELECT MIN(id) FROM logbook GROUP BY destination) AND destination IS NOT NULL AND distance_in_km IS NOT NULL;")
|
||||||
.fetch_all(db)
|
.fetch_all(db)
|
||||||
|
@ -20,11 +20,11 @@ use crate::model::{
|
|||||||
boatreservation::BoatReservation,
|
boatreservation::BoatReservation,
|
||||||
log::Log,
|
log::Log,
|
||||||
logbook::{
|
logbook::{
|
||||||
LogToAdd, LogToFinalize, Logbook, LogbookCreateError, LogbookDeleteError,
|
LogToAdd, LogToFinalize, LogToUpdate, Logbook, LogbookAdminUpdateError, LogbookCreateError,
|
||||||
LogbookUpdateError,
|
LogbookDeleteError, LogbookUpdateError,
|
||||||
},
|
},
|
||||||
logtype::LogType,
|
logtype::LogType,
|
||||||
user::{AdminUser, DonauLinzUser, User, UserWithDetails},
|
user::{AdminUser, DonauLinzUser, User, UserWithDetails, VorstandUser},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct KioskCookie(());
|
pub struct KioskCookie(());
|
||||||
@ -282,10 +282,40 @@ async fn create_kiosk(
|
|||||||
create_logbook(db, data, &DonauLinzUser(creator)).await //TODO: fixme
|
create_logbook(db, data, &DonauLinzUser(creator)).await //TODO: fixme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/update", data = "<data>")]
|
||||||
|
async fn update(
|
||||||
|
db: &State<SqlitePool>,
|
||||||
|
data: Form<LogToUpdate>,
|
||||||
|
user: VorstandUser,
|
||||||
|
) -> Flash<Redirect> {
|
||||||
|
Log::create(
|
||||||
|
db,
|
||||||
|
format!("User {} tries to update log entry={:?}", &user.name, data),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let data = data.into_inner();
|
||||||
|
|
||||||
|
let Some(logbook) = Logbook::find_by_id(db, data.id).await else {
|
||||||
|
return Flash::error(Redirect::to("/log"), &format!("Logbucheintrag kann nicht bearbeitet werden, da es einen Logbuch-Eintrag mit ID={} nicht gibt", data.id));
|
||||||
|
};
|
||||||
|
|
||||||
|
match logbook.update(db, data, &user.0).await {
|
||||||
|
Ok(()) => Flash::success(
|
||||||
|
Redirect::to("/log/show"),
|
||||||
|
format!("Logbucheintrag erfolgreich bearbeitet"),
|
||||||
|
),
|
||||||
|
Err(LogbookAdminUpdateError::NotAllowed) => Flash::error(
|
||||||
|
Redirect::to("/log/show"),
|
||||||
|
format!("Du hast keine Erlaubnis, diesen Logbucheintrag zu bearbeiten!"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn home_logbook(
|
async fn home_logbook(
|
||||||
db: &SqlitePool,
|
db: &SqlitePool,
|
||||||
data: Form<LogToFinalize>,
|
data: Form<LogToFinalize>,
|
||||||
logbook_id: i32,
|
logbook_id: i64,
|
||||||
user: &DonauLinzUser,
|
user: &DonauLinzUser,
|
||||||
) -> Flash<Redirect> {
|
) -> Flash<Redirect> {
|
||||||
let logbook: Option<Logbook> = Logbook::find_by_id(db, logbook_id).await;
|
let logbook: Option<Logbook> = Logbook::find_by_id(db, logbook_id).await;
|
||||||
@ -312,7 +342,7 @@ async fn home_logbook(
|
|||||||
async fn home_kiosk(
|
async fn home_kiosk(
|
||||||
db: &State<SqlitePool>,
|
db: &State<SqlitePool>,
|
||||||
data: Form<LogToFinalize>,
|
data: Form<LogToFinalize>,
|
||||||
logbook_id: i32,
|
logbook_id: i64,
|
||||||
_kiosk: KioskCookie,
|
_kiosk: KioskCookie,
|
||||||
) -> Flash<Redirect> {
|
) -> Flash<Redirect> {
|
||||||
let logbook = Logbook::find_by_id(db, logbook_id).await.unwrap(); //TODO: fixme
|
let logbook = Logbook::find_by_id(db, logbook_id).await.unwrap(); //TODO: fixme
|
||||||
@ -340,7 +370,7 @@ async fn home_kiosk(
|
|||||||
async fn home(
|
async fn home(
|
||||||
db: &State<SqlitePool>,
|
db: &State<SqlitePool>,
|
||||||
data: Form<LogToFinalize>,
|
data: Form<LogToFinalize>,
|
||||||
logbook_id: i32,
|
logbook_id: i64,
|
||||||
user: DonauLinzUser,
|
user: DonauLinzUser,
|
||||||
) -> Flash<Redirect> {
|
) -> Flash<Redirect> {
|
||||||
Log::create(
|
Log::create(
|
||||||
@ -356,7 +386,7 @@ async fn home(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/<logbook_id>/delete", rank = 2)]
|
#[get("/<logbook_id>/delete", rank = 2)]
|
||||||
async fn delete(db: &State<SqlitePool>, logbook_id: i32, user: DonauLinzUser) -> Flash<Redirect> {
|
async fn delete(db: &State<SqlitePool>, logbook_id: i64, user: DonauLinzUser) -> Flash<Redirect> {
|
||||||
let logbook = Logbook::find_by_id(db, logbook_id).await;
|
let logbook = Logbook::find_by_id(db, logbook_id).await;
|
||||||
if let Some(logbook) = logbook {
|
if let Some(logbook) = logbook {
|
||||||
Log::create(
|
Log::create(
|
||||||
@ -385,7 +415,7 @@ async fn delete(db: &State<SqlitePool>, logbook_id: i32, user: DonauLinzUser) ->
|
|||||||
#[get("/<logbook_id>/delete")]
|
#[get("/<logbook_id>/delete")]
|
||||||
async fn delete_kiosk(
|
async fn delete_kiosk(
|
||||||
db: &State<SqlitePool>,
|
db: &State<SqlitePool>,
|
||||||
logbook_id: i32,
|
logbook_id: i64,
|
||||||
_kiosk: KioskCookie,
|
_kiosk: KioskCookie,
|
||||||
) -> Flash<Redirect> {
|
) -> Flash<Redirect> {
|
||||||
let logbook = Logbook::find_by_id(db, logbook_id).await;
|
let logbook = Logbook::find_by_id(db, logbook_id).await;
|
||||||
@ -425,7 +455,8 @@ pub fn routes() -> Vec<Route> {
|
|||||||
show_kiosk,
|
show_kiosk,
|
||||||
show_for_year,
|
show_for_year,
|
||||||
delete,
|
delete,
|
||||||
delete_kiosk
|
delete_kiosk,
|
||||||
|
update
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,77 +169,101 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro show %}
|
{% endmacro show %}
|
||||||
{% macro show_old(log, state, allowed_to_close=false, index) %}
|
{% macro show_old(log, state, allowed_to_close=false, allowed_to_edit=false, index) %}
|
||||||
<div class="border-t bg-white dark:bg-primary-900 py-3 px-4 relative"
|
<div class="border-t bg-white dark:bg-primary-900 py-3 px-4 relative"
|
||||||
data-filterable="true"
|
data-filterable="true"
|
||||||
data-filter="{{ log.boat.name }} {% for rower in log.rowers %}{{ rower.name }}{% endfor %}">
|
data-filter="{{ log.boat.name }} {% for rower in log.rowers %}{{ rower.name }}{% endfor %}">
|
||||||
{% if log.logtype %}
|
<details>
|
||||||
<div class="absolute top-0 right-0 bg-primary-100 rounded-bl-md text-primary-950 text-xs w-32 px-2 py-1 text-center font-bold">
|
<summary style="list-style: none;">
|
||||||
{% if log.logtype == 1 %}
|
{% if log.logtype %}
|
||||||
Wanderfahrt
|
<div class="absolute top-0 right-0 bg-primary-100 rounded-bl-md text-primary-950 text-xs w-32 px-2 py-1 text-center font-bold">
|
||||||
{% else %}
|
{% if log.logtype == 1 %}
|
||||||
{% if log.logtype == 2 %}
|
Wanderfahrt
|
||||||
Regatta
|
{% else %}
|
||||||
{% else %}
|
{% if log.logtype == 2 %}
|
||||||
{{ log.logtype }}
|
Regatta
|
||||||
{% endif %}
|
{% else %}
|
||||||
{% endif %}
|
{{ log.logtype }}
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
<div {% if log.logtype %}class="mt-4 sm:mt-0"{% endif %}>
|
|
||||||
<strong class="text-black dark:text-white">{{ log.boat.name }}</strong>
|
|
||||||
<small class="text-gray-600 dark:text-gray-100">({{ log.shipmaster_user.name -}}
|
|
||||||
{% if log.shipmaster_only_steering %}
|
|
||||||
- handgesteuert
|
|
||||||
{%- endif -%}
|
|
||||||
)</small>
|
|
||||||
<small class="block text-gray-600 dark:text-gray-100">
|
|
||||||
{% if state == "completed" and log.departure | date(format='%d.%m.%Y') == log.arrival | date(format='%d.%m.%Y') %}
|
|
||||||
{{ log.departure | date(format='%d.%m.%Y') }}
|
|
||||||
({{ log.departure | date(format='%H:%M') }}
|
|
||||||
-
|
|
||||||
{{ log.arrival | date(format='%H:%M') }})
|
|
||||||
{% else %}
|
|
||||||
{{ log.departure | date(format='%d.%m.%Y (%H:%M)') }}
|
|
||||||
{% if state == "completed" %}
|
|
||||||
-
|
|
||||||
{{ log.arrival | date(format='%d.%m.%Y (%H:%M)') }}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
{% set amount_rowers = log.rowers | length %}
|
|
||||||
{% set amount_guests = log.boat.amount_seats - amount_rowers %}
|
|
||||||
{% if allowed_to_close and state == "on_water" %}
|
|
||||||
{{ log::home(log=log) }}
|
|
||||||
{% else %}
|
|
||||||
<div class="text-black dark:text-white">
|
|
||||||
{{ log.destination }}
|
|
||||||
{% if state == "completed" %}
|
|
||||||
<small class="text-gray-600 dark:text-gray-100">({{ log.distance_in_km }}
|
|
||||||
km)</small>
|
|
||||||
{% endif %}
|
|
||||||
{% if log.comments %}<span class="text-sm italic">- "{{ log.comments }}"</span>{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if amount_guests > 0 or log.rowers | length > 0 %}
|
|
||||||
{% if not log.boat.amount_seats == 1 %}
|
|
||||||
<div class="text-sm text-gray-600 dark:text-gray-100">
|
|
||||||
Ruderer:
|
|
||||||
{% for rower in log.rowers -%}
|
|
||||||
{{ rower.name }}
|
|
||||||
{%- if rower.id == log.steering_user.id and rower.id != log.shipmaster_user.id %}
|
|
||||||
(Steuerperson){%- endif -%}
|
|
||||||
{%- if not loop.last or amount_guests > 0 and not log.boat.external %},{% endif %}
|
|
||||||
{% endfor -%}
|
|
||||||
{% if amount_guests > 0 and not log.boat.external %}
|
|
||||||
Gäste
|
|
||||||
<small class="text-gray-600 dark:text-gray-100">(ohne Account)</small>:
|
|
||||||
{{ amount_guests }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
<div {% if log.logtype %}class="mt-4 sm:mt-0"{% endif %}>
|
||||||
|
<strong class="text-black dark:text-white">{{ log.boat.name }}</strong>
|
||||||
|
<small class="text-gray-600 dark:text-gray-100">({{ log.shipmaster_user.name -}}
|
||||||
|
{% if log.shipmaster_only_steering %}
|
||||||
|
- handgesteuert
|
||||||
|
{%- endif -%}
|
||||||
|
)</small>
|
||||||
|
<small class="block text-gray-600 dark:text-gray-100">
|
||||||
|
{% if state == "completed" and log.departure | date(format='%d.%m.%Y') == log.arrival | date(format='%d.%m.%Y') %}
|
||||||
|
{{ log.departure | date(format='%d.%m.%Y') }}
|
||||||
|
({{ log.departure | date(format='%H:%M') }}
|
||||||
|
-
|
||||||
|
{{ log.arrival | date(format='%H:%M') }})
|
||||||
|
{% else %}
|
||||||
|
{{ log.departure | date(format='%d.%m.%Y (%H:%M)') }}
|
||||||
|
{% if state == "completed" %}
|
||||||
|
-
|
||||||
|
{{ log.arrival | date(format='%d.%m.%Y (%H:%M)') }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</small>
|
||||||
|
{% set amount_rowers = log.rowers | length %}
|
||||||
|
{% set amount_guests = log.boat.amount_seats - amount_rowers %}
|
||||||
|
{% if allowed_to_close and state == "on_water" %}
|
||||||
|
{{ log::home(log=log) }}
|
||||||
|
{% else %}
|
||||||
|
<div class="text-black dark:text-white">
|
||||||
|
{{ log.destination }}
|
||||||
|
{% if state == "completed" %}
|
||||||
|
<small class="text-gray-600 dark:text-gray-100">({{ log.distance_in_km }}
|
||||||
|
km)</small>
|
||||||
|
{% endif %}
|
||||||
|
{% if log.comments %}<span class="text-sm italic">- "{{ log.comments }}"</span>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if amount_guests > 0 or log.rowers | length > 0 %}
|
||||||
|
{% if not log.boat.amount_seats == 1 %}
|
||||||
|
<div class="text-sm text-gray-600 dark:text-gray-100">
|
||||||
|
Ruderer:
|
||||||
|
{% for rower in log.rowers -%}
|
||||||
|
{{ rower.name }}
|
||||||
|
{%- if rower.id == log.steering_user.id and rower.id != log.shipmaster_user.id %}
|
||||||
|
(Steuerperson){%- endif -%}
|
||||||
|
{%- if not loop.last or amount_guests > 0 and not log.boat.external %},{% endif %}
|
||||||
|
{% endfor -%}
|
||||||
|
{% if amount_guests > 0 and not log.boat.external %}
|
||||||
|
Gäste
|
||||||
|
<small class="text-gray-600 dark:text-gray-100">(ohne Account)</small>:
|
||||||
|
{{ amount_guests }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
{% if allowed_to_edit %}
|
||||||
|
<form action="/log/update" method="post">
|
||||||
|
<input type="hidden" name="id" value="{{ log.id }}" />
|
||||||
|
<input type="hidden" name="boat_id" value="{{ log.boat_id }}" />
|
||||||
|
<input type="hidden" name="shipmaster" value="{{ log.shipmaster }}" />
|
||||||
|
<input type="hidden"
|
||||||
|
name="steering_person"
|
||||||
|
value="{{ log.steering_person }}" />
|
||||||
|
<input type="hidden"
|
||||||
|
name="shipmaster_only_steering"
|
||||||
|
value="{{ log.shipmaster_only_steering }}" />
|
||||||
|
<input type="datetime-local" name="departure" value="{{ log.departure }}" />
|
||||||
|
<input type="datetime-local" name="arrival" value="{{ log.arrival }}" />
|
||||||
|
<input type="hidden" name="destination" value="{{ log.destination }}" />
|
||||||
|
<input type="hidden" name="distance_in_km" value="{{ log.distance_in_km }}" />
|
||||||
|
<input type="hidden" name="comments" value="{{ log.comments }}" />
|
||||||
|
<input type="hidden" name="logtype" value="{{ log.logtype }}" />
|
||||||
|
<input type="submit" value="Updaten" />
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</details>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro show_old %}
|
{% endmacro show_old %}
|
||||||
{% macro home(log) %}
|
{% macro home(log) %}
|
||||||
|
@ -143,9 +143,9 @@
|
|||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
id="{{ name }}{{ id }}"
|
id="{{ name }}{{ id }}"
|
||||||
name="{{ name }}"
|
name="{{ name }}"
|
||||||
{% if checked %} checked{% endif %}
|
{% if checked %}checked{% endif %}
|
||||||
{% if disabled %} disabled{% endif %}
|
{% if disabled %}disabled{% endif %}
|
||||||
{% if readonly %} readonly="readonly"{% endif %}
|
{% if readonly %}readonly="readonly"{% endif %}
|
||||||
class="h-4 w-4 accent-primary-600 dark:accent-primary-200 mr-2" />
|
class="h-4 w-4 accent-primary-600 dark:accent-primary-200 mr-2" />
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</label>
|
</label>
|
||||||
|
@ -23,7 +23,15 @@
|
|||||||
placeholder="Suchen nach Bootsname oder Ruderer...">
|
placeholder="Suchen nach Bootsname oder Ruderer...">
|
||||||
</div>
|
</div>
|
||||||
<div id="filter-result-js" class="search-result"></div>
|
<div id="filter-result-js" class="search-result"></div>
|
||||||
{% for log in logs %}{{ log::show_old(log=log, state="completed", only_ones=false, index=loop.index) }}{% endfor %}
|
{% for log in logs %}
|
||||||
|
{% set_global allowed_to_edit = false %}
|
||||||
|
{% if loggedin_user %}
|
||||||
|
{% if "Vorstand" in loggedin_user.roles %}
|
||||||
|
{% set_global allowed_to_edit = true %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{{ log::show_old(log=log, state="completed", only_ones=false, index=loop.index, allowed_to_edit=allowed_to_edit) }}
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
Loading…
Reference in New Issue
Block a user