more updates after meeting
Some checks failed
CI/CD Pipeline / deploy-staging (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled

This commit is contained in:
2025-06-17 22:52:04 +02:00
parent 86b8d3a30d
commit 1f0bfb04e4
5 changed files with 51 additions and 25 deletions

View File

@ -1,8 +1,8 @@
use std::ops::DerefMut; use std::ops::DerefMut;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use rocket::FromForm;
use rocket::serde::{Deserialize, Serialize}; use rocket::serde::{Deserialize, Serialize};
use rocket::FromForm;
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
use crate::model::boathouse::Boathouse; use crate::model::boathouse::Boathouse;

View File

@ -1,7 +1,10 @@
use rocket::serde::{Deserialize, Serialize}; use rocket::serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool}; use sqlx::{FromRow, SqlitePool};
use crate::tera::board::boathouse::FormBoathouseToAdd; use crate::{
model::{log::Log, user::AllowedToUpdateBoathouse},
tera::board::boathouse::FormBoathouseToAdd,
};
use super::boat::Boat; use super::boat::Boat;
@ -114,7 +117,11 @@ impl Boathouse {
BoathouseAisles::from(db, boathouses).await BoathouseAisles::from(db, boathouses).await
} }
pub async fn create(db: &SqlitePool, data: FormBoathouseToAdd) -> Result<(), String> { pub async fn create(
db: &SqlitePool,
changed_by: &AllowedToUpdateBoathouse,
data: FormBoathouseToAdd,
) -> Result<(), String> {
sqlx::query!( sqlx::query!(
"INSERT INTO boathouse(boat_id, aisle, side, level) VALUES (?,?,?,?)", "INSERT INTO boathouse(boat_id, aisle, side, level) VALUES (?,?,?,?)",
data.boat_id, data.boat_id,
@ -125,6 +132,17 @@ impl Boathouse {
.execute(db) .execute(db)
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let boat = Boat::find_by_id(db, data.boat_id).await.unwrap();
Log::create(
db,
format!(
"{changed_by} hat das Boot {boat} auf den Gang {}, Seite {}, und Höhe {} 'gelegt'.",
data.aisle, data.side, data.level
),
)
.await;
Ok(()) Ok(())
} }
@ -135,10 +153,20 @@ impl Boathouse {
.ok() .ok()
} }
pub async fn delete(&self, db: &SqlitePool) { pub async fn delete(&self, db: &SqlitePool, changed_by: &AllowedToUpdateBoathouse) {
sqlx::query!("DELETE FROM boathouse WHERE id=?", self.id) sqlx::query!("DELETE FROM boathouse WHERE id=?", self.id)
.execute(db) .execute(db)
.await .await
.unwrap(); //Okay, because we can only create a Boat of a valid id .unwrap(); //Okay, because we can only create a Boat of a valid id
let boat = Boat::find_by_id(db, self.boat_id as i32).await.unwrap();
Log::create(
db,
format!(
"{changed_by} hat das Boot {boat} von Gang {}, Seite {}, und Höhe {} gelöscht.",
self.aisle, self.side, self.level
),
)
.await;
} }
} }

View File

@ -859,6 +859,7 @@ special_user!(AllowedToEditPaymentStatusUser, +"kassier", +"admin");
special_user!(ManageUserUser, +"admin", +"schriftfuehrer"); special_user!(ManageUserUser, +"admin", +"schriftfuehrer");
special_user!(AllowedToSendFeeReminderUser, +"admin", +"schriftfuehrer", +"kassier"); special_user!(AllowedToSendFeeReminderUser, +"admin", +"schriftfuehrer", +"kassier");
special_user!(AllowedToUpdateTripToAlwaysBeShownUser, +"admin"); special_user!(AllowedToUpdateTripToAlwaysBeShownUser, +"admin");
special_user!(AllowedToUpdateBoathouse, +"admin", +"Vorstand", +"tech");
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)] #[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
pub struct UserWithRolesAndMembershipPdf { pub struct UserWithRolesAndMembershipPdf {

View File

@ -1,17 +1,16 @@
use crate::model::{ use crate::model::{
boat::Boat, boat::Boat,
boathouse::Boathouse, boathouse::Boathouse,
user::{AdminUser, UserWithDetails, VorstandUser}, user::{AllowedToUpdateBoathouse, UserWithDetails, VorstandUser},
}; };
use rocket::{ use rocket::{
FromForm, Route, State,
form::Form, form::Form,
get, post, get, post,
request::FlashMessage, request::FlashMessage,
response::{Flash, Redirect}, response::{Flash, Redirect},
routes, routes, FromForm, Route, State,
}; };
use rocket_dyn_templates::{Template, tera::Context}; use rocket_dyn_templates::{tera::Context, Template};
use sqlx::SqlitePool; use sqlx::SqlitePool;
#[get("/boathouse")] #[get("/boathouse")]
@ -38,6 +37,11 @@ async fn index(
let boathouse = Boathouse::get(db).await; let boathouse = Boathouse::get(db).await;
context.insert("boathouse", &boathouse); context.insert("boathouse", &boathouse);
let allowed_to_edit = AllowedToUpdateBoathouse::new(db, &admin.user)
.await
.is_some();
context.insert("allowed_to_edit", &boathouse);
context.insert( context.insert(
"loggedin_user", "loggedin_user",
&UserWithDetails::from_user(admin.into_inner(), db).await, &UserWithDetails::from_user(admin.into_inner(), db).await,
@ -57,36 +61,29 @@ pub struct FormBoathouseToAdd {
async fn new<'r>( async fn new<'r>(
db: &State<SqlitePool>, db: &State<SqlitePool>,
data: Form<FormBoathouseToAdd>, data: Form<FormBoathouseToAdd>,
_admin: AdminUser, user: AllowedToUpdateBoathouse,
) -> Flash<Redirect> { ) -> Flash<Redirect> {
match Boathouse::create(db, data.into_inner()).await { match Boathouse::create(db, &user, data.into_inner()).await {
Ok(_) => Flash::success(Redirect::to("/board/boathouse"), "Boot hinzugefügt"), Ok(_) => Flash::success(Redirect::to("/board/boathouse"), "Boot hinzugefügt"),
Err(e) => Flash::error(Redirect::to("/board/boathouse"), e), Err(e) => Flash::error(Redirect::to("/board/boathouse"), e),
} }
} }
#[get("/boathouse/<boathouse_id>/delete")] #[get("/boathouse/<boathouse_id>/delete")]
async fn delete(db: &State<SqlitePool>, _admin: AdminUser, boathouse_id: i32) -> Flash<Redirect> { async fn delete(
db: &State<SqlitePool>,
user: AllowedToUpdateBoathouse,
boathouse_id: i32,
) -> Flash<Redirect> {
let boat = Boathouse::find_by_id(db, boathouse_id).await; let boat = Boathouse::find_by_id(db, boathouse_id).await;
match boat { match boat {
Some(boat) => { Some(boat) => {
boat.delete(db).await; boat.delete(db, &user).await;
Flash::success(Redirect::to("/board/boathouse"), "Bootsplatz gelöscht") Flash::success(Redirect::to("/board/boathouse"), "Bootsplatz gelöscht")
} }
None => Flash::error(Redirect::to("/board/boathouse"), "Boatplace does not exist"), None => Flash::error(Redirect::to("/board/boathouse"), "Boatplace does not exist"),
} }
} }
//#[post("/boat/new", data = "<data>")]
//async fn create(
// db: &State<SqlitePool>,
// data: Form<BoatToAdd<'_>>,
// _admin: AdminUser,
//) -> Flash<Redirect> {
// match Boat::create(db, data.into_inner()).await {
// Ok(_) => Flash::success(Redirect::to("/admin/boat"), "Boot hinzugefügt"),
// Err(e) => Flash::error(Redirect::to("/admin/boat"), e),
// }
//}
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![index, new, delete] routes![index, new, delete]

View File

@ -7,12 +7,12 @@
{% set place = boathouse[aisle_name][side_name].boats %} {% set place = boathouse[aisle_name][side_name].boats %}
{% if place[level] %} {% if place[level] %}
{{ place[level].boat.name }} {{ place[level].boat.name }}
{% if "admin" in loggedin_user.roles %} {% if allowed_to_edit %}
<a class="btn btn-primary absolute end-0" <a class="btn btn-primary absolute end-0"
href="/board/boathouse/{{ place[level].boathouse_id }}/delete">X</a> href="/board/boathouse/{{ place[level].boathouse_id }}/delete">X</a>
{% endif %} {% endif %}
{% elif boats | length > 0 %} {% elif boats | length > 0 %}
{% if "admin" in loggedin_user.roles %} {% if allowed_to_edit %}
<details> <details>
<summary>Kein Boot</summary> <summary>Kein Boot</summary>
<form action="/board/boathouse" method="post" class="grid gap-3"> <form action="/board/boathouse" method="post" class="grid gap-3">