forked from Ruderverein-Donau-Linz/rowt
		
	add functionality to finish logbook trips
This commit is contained in:
		| @@ -4,6 +4,7 @@ | |||||||
|  |  | ||||||
| ## New large features | ## New large features | ||||||
| ### Logbuch | ### Logbuch | ||||||
|  | - Next: add rower to 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)] | ||||||
|   | |||||||
| @@ -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='') %} | ||||||
| <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 %}> | ||||||
| </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" /> | ||||||
| @@ -53,16 +53,34 @@ | |||||||
|  |  | ||||||
|   <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 %} | ||||||
|   	Bootsname: {{ log.boat }}<br /> |     Bootsname: {{ log.boat }}<br /> | ||||||
| 	Schiffsführer: {{ log.shipmaster_name }}<br /> |     Schiffsführer: {{ log.shipmaster_name }}<br /> | ||||||
| 	{% if log.shipmaster_only_steering %} |     {% if log.shipmaster_only_steering %} | ||||||
| 		Schiffsführer steuert nur |       Schiffsführer steuert nur | ||||||
| 	{% endif %} |     {% endif %} | ||||||
| 	Weggefahren: {{ log.departure }}<br /> |     Weggefahren: {{ log.departure }}<br /> | ||||||
| 	Ziel: {{ log.destination }}<br /> |     Ziel: {{ log.destination }}<br /> | ||||||
| 	Kommentare: {{ log.comments }}<br /> |     Kommentare: {{ log.comments }}<br /> | ||||||
| 	Logtype: {{ log.logtype }}<br /> |     Logtype: {{ log.logtype }}<br /> | ||||||
| 	<hr /> |     {% 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 /> | ||||||
|   {% endfor %} |   {% endfor %} | ||||||
|  |  | ||||||
|   <h2 style="font-size: 100px">Einträge</h2> |   <h2 style="font-size: 100px">Einträge</h2> | ||||||
| @@ -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 /> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user