forked from Ruderverein-Donau-Linz/rowt
		
	Merge branch 'main' of ssh://git.hofer.link:2222/Ruderverein-Donau-Linz/rowt
This commit is contained in:
		@@ -9,8 +9,12 @@ use serde::Serialize;
 | 
			
		||||
use sqlx::{FromRow, Row, SqlitePool};
 | 
			
		||||
 | 
			
		||||
use super::{
 | 
			
		||||
    notification::Notification, role::Role, tripdetails::TripDetails, triptype::TripType,
 | 
			
		||||
    user::User,
 | 
			
		||||
    log::Log,
 | 
			
		||||
    notification::Notification,
 | 
			
		||||
    role::Role,
 | 
			
		||||
    tripdetails::TripDetails,
 | 
			
		||||
    triptype::TripType,
 | 
			
		||||
    user::{EventUser, User},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Clone, FromRow, Debug, PartialEq)]
 | 
			
		||||
@@ -242,6 +246,7 @@ WHERE trip_details.id=?
 | 
			
		||||
 | 
			
		||||
    pub async fn create(
 | 
			
		||||
        db: &SqlitePool,
 | 
			
		||||
        user: &EventUser,
 | 
			
		||||
        name: &str,
 | 
			
		||||
        planned_amount_cox: i32,
 | 
			
		||||
        always_show: bool,
 | 
			
		||||
@@ -270,6 +275,15 @@ WHERE trip_details.id=?
 | 
			
		||||
        .execute(db)
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap(); //Okay, as TripDetails can only be created with proper DB backing
 | 
			
		||||
 | 
			
		||||
        Log::create(
 | 
			
		||||
            db,
 | 
			
		||||
            format!(
 | 
			
		||||
                "{} created event {} on {} at {}.",
 | 
			
		||||
                user.user.name, name, trip_details.day, trip_details.planned_starting_time
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        .await;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //TODO: create unit test
 | 
			
		||||
@@ -449,7 +463,13 @@ WHERE trip_details.id=?
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use crate::{model::tripdetails::TripDetails, testdb};
 | 
			
		||||
    use crate::{
 | 
			
		||||
        model::{
 | 
			
		||||
            tripdetails::TripDetails,
 | 
			
		||||
            user::{EventUser, User},
 | 
			
		||||
        },
 | 
			
		||||
        testdb,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    use super::Event;
 | 
			
		||||
    use chrono::Local;
 | 
			
		||||
@@ -469,7 +489,10 @@ mod test {
 | 
			
		||||
 | 
			
		||||
        let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        Event::create(&pool, "new-event".into(), 2, false, &trip_details).await;
 | 
			
		||||
        let admin = EventUser::new(&pool, User::find_by_id(&pool, 1).await.unwrap())
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        Event::create(&pool, &admin, "new-event".into(), 2, false, &trip_details).await;
 | 
			
		||||
 | 
			
		||||
        let res = Event::get_for_day(&pool, Local::now().date_naive()).await;
 | 
			
		||||
        assert_eq!(res.len(), 2);
 | 
			
		||||
 
 | 
			
		||||
@@ -221,7 +221,7 @@ mod test {
 | 
			
		||||
            notification::Notification,
 | 
			
		||||
            trip::Trip,
 | 
			
		||||
            tripdetails::{TripDetails, TripDetailsToAdd},
 | 
			
		||||
            user::{SteeringUser, User},
 | 
			
		||||
            user::{EventUser, SteeringUser, User},
 | 
			
		||||
            usertrip::UserTrip,
 | 
			
		||||
        },
 | 
			
		||||
        testdb,
 | 
			
		||||
@@ -247,7 +247,10 @@ mod test {
 | 
			
		||||
        let trip_details = TripDetails::find_by_id(&pool, tripdetails_id)
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        Event::create(&pool, "new-event".into(), 2, false, &trip_details).await;
 | 
			
		||||
        let user = EventUser::new(&pool, User::find_by_id(&pool, 1).await.unwrap())
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        Event::create(&pool, &user, "new-event".into(), 2, false, &trip_details).await;
 | 
			
		||||
        let event = Event::find_by_trip_details(&pool, trip_details.id)
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ use super::{
 | 
			
		||||
    notification::Notification,
 | 
			
		||||
    tripdetails::TripDetails,
 | 
			
		||||
    triptype::TripType,
 | 
			
		||||
    user::{SteeringUser, User},
 | 
			
		||||
    user::{ErgoUser, SteeringUser, User},
 | 
			
		||||
    usertrip::UserTrip,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -38,7 +38,7 @@ pub struct TripWithUserAndType {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TripUpdate<'a> {
 | 
			
		||||
    pub cox: &'a SteeringUser,
 | 
			
		||||
    pub cox: &'a User,
 | 
			
		||||
    pub trip: &'a Trip,
 | 
			
		||||
    pub max_people: i32,
 | 
			
		||||
    pub notes: Option<&'a str>,
 | 
			
		||||
@@ -63,9 +63,23 @@ impl TripWithUserAndType {
 | 
			
		||||
impl Trip {
 | 
			
		||||
    /// Cox decides to create own trip.
 | 
			
		||||
    pub async fn new_own(db: &SqlitePool, cox: &SteeringUser, trip_details: TripDetails) {
 | 
			
		||||
        Self::perform_new(db, &cox.user, trip_details).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn new_own_ergo(db: &SqlitePool, ergo: &ErgoUser, trip_details: TripDetails) {
 | 
			
		||||
        let typ = trip_details.triptype(db).await;
 | 
			
		||||
        if let Some(typ) = typ {
 | 
			
		||||
            let allowed_type = TripType::find_by_id(db, 4).await.unwrap();
 | 
			
		||||
            if typ == allowed_type {
 | 
			
		||||
                Self::perform_new(db, &ergo.user, trip_details).await;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn perform_new(db: &SqlitePool, user: &User, trip_details: TripDetails) {
 | 
			
		||||
        let _ = sqlx::query!(
 | 
			
		||||
            "INSERT INTO trip (cox_id, trip_details_id) VALUES(?, ?)",
 | 
			
		||||
            cox.id,
 | 
			
		||||
            user.id,
 | 
			
		||||
            trip_details.id
 | 
			
		||||
        )
 | 
			
		||||
        .execute(db)
 | 
			
		||||
@@ -96,7 +110,7 @@ impl Trip {
 | 
			
		||||
                        &user,
 | 
			
		||||
                        &format!(
 | 
			
		||||
                            "{} hat eine Ausfahrt zur selben Zeit ({} um {}) wie du erstellt",
 | 
			
		||||
                            cox.user.name, trip.day, trip.planned_starting_time
 | 
			
		||||
                            user.name, trip.day, trip.planned_starting_time
 | 
			
		||||
                        ),
 | 
			
		||||
                        "Neue Ausfahrt zur selben Zeit",
 | 
			
		||||
                        None,
 | 
			
		||||
@@ -273,6 +287,12 @@ WHERE day=?
 | 
			
		||||
            return Err(TripUpdateError::NotYourTrip);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if update.trip_type != Some(4) {
 | 
			
		||||
            if !update.cox.allowed_to_steer(db).await {
 | 
			
		||||
                return Err(TripUpdateError::TripTypeNotAllowed);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let Some(trip_details_id) = update.trip.trip_details_id else {
 | 
			
		||||
            return Err(TripUpdateError::TripDetailsDoesNotExist); //TODO: Remove?
 | 
			
		||||
        };
 | 
			
		||||
@@ -314,7 +334,7 @@ WHERE day=?
 | 
			
		||||
                        &user,
 | 
			
		||||
                        &format!(
 | 
			
		||||
                            "Die Ausfahrt von {} am {} um {} wurde abgesagt. {} Bitte gib Bescheid, dass du die Info erhalten hast indem du auf ✓ klickst.",
 | 
			
		||||
                            update.cox.user.name,
 | 
			
		||||
                            update.cox.name,
 | 
			
		||||
                            update.trip.day,
 | 
			
		||||
                            update.trip.planned_starting_time,
 | 
			
		||||
                            notes
 | 
			
		||||
@@ -384,11 +404,7 @@ WHERE day=?
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) async fn delete(
 | 
			
		||||
        &self,
 | 
			
		||||
        db: &SqlitePool,
 | 
			
		||||
        user: &SteeringUser,
 | 
			
		||||
    ) -> Result<(), TripDeleteError> {
 | 
			
		||||
    pub(crate) async fn delete(&self, db: &SqlitePool, user: &User) -> Result<(), TripDeleteError> {
 | 
			
		||||
        let registered_rower = Registration::all_rower(db, self.trip_details_id.unwrap()).await;
 | 
			
		||||
        if !registered_rower.is_empty() {
 | 
			
		||||
            return Err(TripDeleteError::SomebodyAlreadyRegistered);
 | 
			
		||||
@@ -398,7 +414,7 @@ WHERE day=?
 | 
			
		||||
            return Err(TripDeleteError::NotYourTrip);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Log::create(db, format!("{} deleted trip: {:#?}", user.user.name, self)).await;
 | 
			
		||||
        Log::create(db, format!("{} deleted trip: {:#?}", user.name, self)).await;
 | 
			
		||||
 | 
			
		||||
        sqlx::query!("DELETE FROM trip WHERE id = ?", self.id)
 | 
			
		||||
            .execute(db)
 | 
			
		||||
@@ -464,6 +480,7 @@ pub enum TripDeleteError {
 | 
			
		||||
pub enum TripUpdateError {
 | 
			
		||||
    NotYourTrip,
 | 
			
		||||
    TripDetailsDoesNotExist,
 | 
			
		||||
    TripTypeNotAllowed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use sqlx::{FromRow, SqlitePool};
 | 
			
		||||
 | 
			
		||||
#[derive(FromRow, Debug, Serialize, Deserialize, Clone)]
 | 
			
		||||
#[derive(FromRow, Debug, Serialize, Deserialize, Clone, PartialEq)]
 | 
			
		||||
pub struct TripType {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
 
 | 
			
		||||
@@ -1166,6 +1166,7 @@ macro_rules! special_user {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
special_user!(TechUser, +"tech");
 | 
			
		||||
special_user!(ErgoUser, +"ergo");
 | 
			
		||||
special_user!(SteeringUser, +"cox", +"Bootsführer");
 | 
			
		||||
special_user!(AdminUser, +"admin");
 | 
			
		||||
special_user!(AllowedForPlannedTripsUser, +"Donau Linz", +"scheckbuch");
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ struct AddEventForm<'r> {
 | 
			
		||||
async fn create(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    data: Form<AddEventForm<'_>>,
 | 
			
		||||
    _admin: EventUser,
 | 
			
		||||
    user: EventUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let data = data.into_inner();
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +37,7 @@ async fn create(
 | 
			
		||||
 | 
			
		||||
    Event::create(
 | 
			
		||||
        db,
 | 
			
		||||
        &user,
 | 
			
		||||
        data.name,
 | 
			
		||||
        data.planned_amount_cox,
 | 
			
		||||
        data.always_show,
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,32 @@ use crate::model::{
 | 
			
		||||
    log::Log,
 | 
			
		||||
    trip::{self, CoxHelpError, Trip, TripDeleteError, TripHelpDeleteError, TripUpdateError},
 | 
			
		||||
    tripdetails::{TripDetails, TripDetailsToAdd},
 | 
			
		||||
    user::{AllowedToUpdateTripToAlwaysBeShownUser, SteeringUser},
 | 
			
		||||
    user::{AllowedToUpdateTripToAlwaysBeShownUser, ErgoUser, SteeringUser, User},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[post("/trip", data = "<data>", rank = 2)]
 | 
			
		||||
async fn create_ergo(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    data: Form<TripDetailsToAdd<'_>>,
 | 
			
		||||
    cox: ErgoUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    let trip_details_id = TripDetails::create(db, data.into_inner()).await;
 | 
			
		||||
    let trip_details = TripDetails::find_by_id(db, trip_details_id).await.unwrap(); //Okay, bc just
 | 
			
		||||
                                                                                    //created
 | 
			
		||||
    Trip::new_own_ergo(db, &cox, trip_details).await; //TODO: fix
 | 
			
		||||
 | 
			
		||||
    //Log::create(
 | 
			
		||||
    //    db,
 | 
			
		||||
    //    format!(
 | 
			
		||||
    //        "Cox {} created trip on {} @ {} for {} rower",
 | 
			
		||||
    //        cox.name, trip_details.day, trip_details.planned_starting_time, trip_details.max_people,
 | 
			
		||||
    //    ),
 | 
			
		||||
    //)
 | 
			
		||||
    //.await;
 | 
			
		||||
 | 
			
		||||
    Flash::success(Redirect::to("/planned"), "Ausfahrt erfolgreich erstellt.")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[post("/trip", data = "<data>")]
 | 
			
		||||
async fn create(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
@@ -50,7 +73,7 @@ async fn update(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    data: Form<EditTripForm<'_>>,
 | 
			
		||||
    trip_id: i64,
 | 
			
		||||
    cox: SteeringUser,
 | 
			
		||||
    cox: User,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    if let Some(trip) = Trip::find_by_id(db, trip_id).await {
 | 
			
		||||
        let update = trip::TripUpdate {
 | 
			
		||||
@@ -69,6 +92,10 @@ async fn update(
 | 
			
		||||
            Err(TripUpdateError::NotYourTrip) => {
 | 
			
		||||
                Flash::error(Redirect::to("/planned"), "Nicht deine Ausfahrt!")
 | 
			
		||||
            }
 | 
			
		||||
            Err(TripUpdateError::TripTypeNotAllowed) => Flash::error(
 | 
			
		||||
                Redirect::to("/planned"),
 | 
			
		||||
                "Du darfst nur Ergo-Events erstellen",
 | 
			
		||||
            ),
 | 
			
		||||
            Err(TripUpdateError::TripDetailsDoesNotExist) => {
 | 
			
		||||
                Flash::error(Redirect::to("/planned"), "Ausfahrt gibt's nicht")
 | 
			
		||||
            }
 | 
			
		||||
@@ -130,7 +157,7 @@ async fn join(db: &State<SqlitePool>, planned_event_id: i64, cox: SteeringUser)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[get("/remove/trip/<trip_id>")]
 | 
			
		||||
async fn remove_trip(db: &State<SqlitePool>, trip_id: i64, cox: SteeringUser) -> Flash<Redirect> {
 | 
			
		||||
async fn remove_trip(db: &State<SqlitePool>, trip_id: i64, cox: User) -> Flash<Redirect> {
 | 
			
		||||
    let trip = Trip::find_by_id(db, trip_id).await;
 | 
			
		||||
    match trip {
 | 
			
		||||
        None => Flash::error(Redirect::to("/planned"), "Trip gibt's nicht!"),
 | 
			
		||||
@@ -185,6 +212,7 @@ async fn remove(
 | 
			
		||||
pub fn routes() -> Vec<Route> {
 | 
			
		||||
    routes![
 | 
			
		||||
        create,
 | 
			
		||||
        create_ergo,
 | 
			
		||||
        join,
 | 
			
		||||
        remove,
 | 
			
		||||
        remove_trip,
 | 
			
		||||
 
 | 
			
		||||
@@ -209,10 +209,12 @@ async fn new_thirty(
 | 
			
		||||
    if let Err(e) = data.proof.move_copy_to(file_path).await {
 | 
			
		||||
        eprintln!("Failed to persist file: {:?}", e);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    let result = data.result.trim_start_matches(|c| c == '0' || c == ' ');
 | 
			
		||||
 | 
			
		||||
    sqlx::query!(
 | 
			
		||||
        "UPDATE user SET dirty_thirty = ? where id = ?",
 | 
			
		||||
        data.result,
 | 
			
		||||
        result,
 | 
			
		||||
        data.user
 | 
			
		||||
    )
 | 
			
		||||
    .execute(db.inner())
 | 
			
		||||
@@ -231,6 +233,32 @@ async fn new_thirty(
 | 
			
		||||
    Flash::success(Redirect::to("/ergo"), "Erfolgreich eingetragen")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn format_time(input: &str) -> String {
 | 
			
		||||
    let mut parts: Vec<&str> = input.split(':').collect();
 | 
			
		||||
 | 
			
		||||
    // If there's only seconds (e.g., "24.2"), treat it as "00:00:24.2"
 | 
			
		||||
    if parts.len() == 1 {
 | 
			
		||||
        parts.insert(0, "0"); // Add "0" for hours
 | 
			
		||||
        parts.insert(0, "0"); // Add "0" for minutes
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If there are two parts (e.g., "4:24.2"), treat it as "00:04:24.2"
 | 
			
		||||
    if parts.len() == 2 {
 | 
			
		||||
        parts.insert(0, "0"); // Add "0" for hours
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Now parts should have [hours, minutes, seconds]
 | 
			
		||||
    let hours = if parts[0].len() == 1 { format!("0{}", parts[0]) } else { parts[0].to_string() };
 | 
			
		||||
    let minutes = if parts[1].len() == 1 { format!("0{}", parts[1]) } else { parts[1].to_string() };
 | 
			
		||||
    let seconds = parts[2];
 | 
			
		||||
 | 
			
		||||
    // Split seconds into whole and fractional parts
 | 
			
		||||
    let (sec_int, sec_frac) = seconds.split_once('.').unwrap_or((seconds, "0"));
 | 
			
		||||
 | 
			
		||||
    // Format the time as "hh:mm:ss.s"
 | 
			
		||||
    format!("{}:{}:{}.{:1}", hours, minutes, sec_int, sec_frac.chars().next().unwrap_or('0'))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[post("/dozen", data = "<data>", format = "multipart/form-data")]
 | 
			
		||||
async fn new_dozen(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
@@ -253,10 +281,16 @@ async fn new_dozen(
 | 
			
		||||
    if let Err(e) = data.proof.move_copy_to(file_path).await {
 | 
			
		||||
        eprintln!("Failed to persist file: {:?}", e);
 | 
			
		||||
    }
 | 
			
		||||
    let result = data.result.trim_start_matches(|c| c == '0' || c == ' ');
 | 
			
		||||
    let result = if result.contains(":") || result.contains(".") {
 | 
			
		||||
     format_time(result)
 | 
			
		||||
    }else{
 | 
			
		||||
result.to_string()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    sqlx::query!(
 | 
			
		||||
        "UPDATE user SET dirty_dozen = ? where id = ?",
 | 
			
		||||
        data.result,
 | 
			
		||||
        result,
 | 
			
		||||
        data.user
 | 
			
		||||
    )
 | 
			
		||||
    .execute(db.inner())
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,10 @@ async fn index(
 | 
			
		||||
 | 
			
		||||
    let mut context = Context::new();
 | 
			
		||||
 | 
			
		||||
    if user.allowed_to_steer(db).await || user.has_role(db, "manage_events").await {
 | 
			
		||||
    if user.allowed_to_steer(db).await
 | 
			
		||||
        || user.has_role(db, "manage_events").await
 | 
			
		||||
        || user.has_role(db, "ergo").await
 | 
			
		||||
    {
 | 
			
		||||
        let triptypes = TripType::all(db).await;
 | 
			
		||||
        context.insert("trip_types", &triptypes);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,15 @@
 | 
			
		||||
            <summary>Dirty Thirty</summary>
 | 
			
		||||
            <p>
 | 
			
		||||
                <div class="border-r border-l">
 | 
			
		||||
                    {% for stat in thirty %}
 | 
			
		||||
                        {% set names = stat.name | split(pat=" ") %}{% set lastname_index = names | length - 1 %}{% set lastname = names[lastname_index] %}{{ lastname }}	
 | 
			
		||||
                        {% for name in names %}
 | 
			
		||||
		<textarea style="width: 100%; height: 300px;">
 | 
			
		||||
                    {%- for stat in thirty %}
 | 
			
		||||
                        {%- set names = stat.name | split(pat=" ") %}{% set lastname_index = names | length - 1 %}{% set lastname = names[lastname_index] %}{{ lastname }}	
 | 
			
		||||
                        {%- for name in names -%}
 | 
			
		||||
                            {% if loop.index != lastname_index +1 %}{{ name }}{% endif %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
                        	{{ stat.dob }}	{{ stat.weight }}	{{ stat.sex }}		DLI	{{ stat.result }}
 | 
			
		||||
                    {% endfor %}
 | 
			
		||||
                        {%- endfor -%}
 | 
			
		||||
                        	{{ stat.dob }}	{{ stat.weight }}	{{ stat.sex }}		DLI	{{ stat.result }}

 | 
			
		||||
                    {%- endfor -%}
 | 
			
		||||
		    </textarea>
 | 
			
		||||
                </div>
 | 
			
		||||
            </p>
 | 
			
		||||
        </details>
 | 
			
		||||
@@ -21,17 +23,15 @@
 | 
			
		||||
            <summary>Dirty Dozen</summary>
 | 
			
		||||
            <p>
 | 
			
		||||
                <div class="border-r border-l">
 | 
			
		||||
                    {% for stat in dozen %}
 | 
			
		||||
                        {% set names = stat.name | split(pat=" ") %}
 | 
			
		||||
                        {% set lastname_index = names | length - 1 %}
 | 
			
		||||
                        {% set lastname = names[lastname_index] %}
 | 
			
		||||
                        {{ lastname }};
 | 
			
		||||
                        {% for name in names %}
 | 
			
		||||
		<textarea style="width: 100%; height: 300px;">
 | 
			
		||||
                    {%- for stat in dozen -%}
 | 
			
		||||
                        {%- set names = stat.name | split(pat=" ") %}{% set lastname_index = names | length - 1 %}{% set lastname = names[lastname_index] %}{{ lastname }}	
 | 
			
		||||
                        {%- for name in names -%}
 | 
			
		||||
                            {% if loop.index != lastname_index +1 %}{{ name }}{% endif %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
                        ;{{ stat.dob }};{{ stat.weight }};{{ stat.sex }};DLI;{{ stat.result }}
 | 
			
		||||
                        <br />
 | 
			
		||||
                    {% endfor %}
 | 
			
		||||
                        {%- endfor -%}
 | 
			
		||||
                        	{{ stat.dob }}	{{ stat.weight }}	{{ stat.sex }}		DLI	{{ stat.result }}

 | 
			
		||||
                    {%- endfor -%}
 | 
			
		||||
		    </textarea>
 | 
			
		||||
                </div>
 | 
			
		||||
            </p>
 | 
			
		||||
        </details>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,9 @@
 | 
			
		||||
                                Montag → gemeinsames Training; bitte um <a href="/planned" class="link-primary">Anmeldung</a>, damit jeder einen Ergo hat
 | 
			
		||||
                            </li>
 | 
			
		||||
                            <li class="py-1">
 | 
			
		||||
                                Offizielle Ergebnisse: <a href="https://rudernlinz.at/dt"
 | 
			
		||||
                                <a href="https://data.ergochallenge.at"
 | 
			
		||||
    target="_blank"
 | 
			
		||||
    style="text-decoration: underline">Dirty Thirty (rudernlinz.at/dt)</a> / <a href="https://rudernlinz.at/dd"
 | 
			
		||||
    target="_blank"
 | 
			
		||||
    style="text-decoration: underline">Dirty Dozen (rudernlinz.at/dd)</a>, bei Fehlern direkt mit <a href="mailto:office@ergochallenge.at"
 | 
			
		||||
    style="text-decoration: underline">Offizielle Ergebnisse</a>, bei Fehlern direkt mit <a href="mailto:office@ergochallenge.at"
 | 
			
		||||
    style="text-decoration: underline">Christian (Ister)</a> Kontakt aufnehmen
 | 
			
		||||
                            </li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,11 @@
 | 
			
		||||
        {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='max_people', type='number', required=true, min='0') }}
 | 
			
		||||
        {{ macros::checkbox(label='Scheckbuch-Anmeldungen erlauben', name='allow_guests') }}
 | 
			
		||||
        {{ macros::input(label='Anmerkungen', name='notes', type='input') }}
 | 
			
		||||
        {{ macros::select(label='Typ', data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }}
 | 
			
		||||
	{% if loggedin_user.allowed_to_steer %}
 | 
			
		||||
	        {{ macros::select(label='Typ', data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }}
 | 
			
		||||
	{% else %}
 | 
			
		||||
	        {{ macros::select(label='Typ', data=trip_types, name='trip_type', only_ergo=true) }}
 | 
			
		||||
	{% endif %}
 | 
			
		||||
        <input value="Erstellen" class="w-full btn btn-primary" type="submit" />
 | 
			
		||||
    </form>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -190,7 +190,7 @@ function setChoiceByLabel(choicesInstance, label) {
 | 
			
		||||
        {{ label }}
 | 
			
		||||
    </label>
 | 
			
		||||
{% endmacro checkbox %}
 | 
			
		||||
{% macro select(label, data, name='trip_type', default='', id='', selected_id='', display='', extras='', class='', wrapper_class='', required=false, show_seats=false, new_last_entry='', nonSelectableDefault=false) %}
 | 
			
		||||
{% macro select(label, data, name='trip_type', default='', id='', selected_id='', display='', extras='', class='', wrapper_class='', required=false, show_seats=false, new_last_entry='', nonSelectableDefault=false, only_ergo=false) %}
 | 
			
		||||
    <div class="{{ wrapper_class }}">
 | 
			
		||||
        <label for="{{ name }}" class="text-sm text-gray-600 dark:text-gray-100">{{ label }}</label>
 | 
			
		||||
        {% if display == '' %}
 | 
			
		||||
@@ -203,7 +203,7 @@ function setChoiceByLabel(choicesInstance, label) {
 | 
			
		||||
            {% if default %}<option selected value>{{ default }}</option>{% endif %}
 | 
			
		||||
            {% if nonSelectableDefault %}<option disabled selected value>{{ nonSelectableDefault }}</option>{% endif %}
 | 
			
		||||
            {% for d in data %}
 | 
			
		||||
                <option value="{{ d.id }}" {% if d.id == selected_id %}selected{% endif %} {% if extras != '' %} {% for extra in extras %} {% if extra != 'on_water' and d[extra] %} data- {{ extra }}={{ d[extra] }} {% else %} {% if d[extra] %}disabled{% endif %} {% endif %} {% endfor %} {% endif %} {% if show_seats %} data-custom-properties='{"amount_seats": {{ d["amount_seats"] }}, "owner": "{{ d["owner"] }}", "default_destination": "{{ d["default_destination"] }}", "boat_in_ottensheim": {{ d["location_id"] == 2 }}, "boat_reserved_today": {{ d["reserved_today"] }}, "convert_handoperated_possible": {{ d["convert_handoperated_possible"] }}, "default_handoperated": {{ d["default_shipmaster_only_steering"] }}}' {% endif %}>
 | 
			
		||||
                <option value="{{ d.id }}" {% if only_ergo and d.id!=4 %} disabled {% endif %}{% if d.id == selected_id %}selected{% endif %} {% if extras != '' %} {% for extra in extras %} {% if extra != 'on_water' and d[extra] %} data- {{ extra }}={{ d[extra] }} {% else %} {% if d[extra] %}disabled{% endif %} {% endif %} {% endfor %} {% endif %} {% if show_seats %} data-custom-properties='{"amount_seats": {{ d["amount_seats"] }}, "owner": "{{ d["owner"] }}", "default_destination": "{{ d["default_destination"] }}", "boat_in_ottensheim": {{ d["location_id"] == 2 }}, "boat_reserved_today": {{ d["reserved_today"] }}, "convert_handoperated_possible": {{ d["convert_handoperated_possible"] }}, "default_handoperated": {{ d["default_shipmaster_only_steering"] }}}' {% endif %}>
 | 
			
		||||
                    {% for displa in display -%}
 | 
			
		||||
                        {%- if d[displa] -%}
 | 
			
		||||
                            {{- d[displa] -}}
 | 
			
		||||
 
 | 
			
		||||
@@ -354,7 +354,11 @@
 | 
			
		||||
                                                    {{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min=trip.rower | length) }}
 | 
			
		||||
                                                    {{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }}
 | 
			
		||||
                                                    {{ macros::checkbox(label='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }}
 | 
			
		||||
                                                    {{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }}
 | 
			
		||||
						    {% if loggedin_user.allowed_to_steer %}
 | 
			
		||||
                                                    {{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id, only_ergo=not loggedin_user.allowed_to_steer) }}
 | 
			
		||||
						    {% else %}
 | 
			
		||||
                                                    {{ macros::select(label='Typ', name='trip_type', data=trip_types, selected_id=trip.trip_type_id, only_ergo=not loggedin_user.allowed_to_steer, only_ergos=true) }}
 | 
			
		||||
						    {% endif %}
 | 
			
		||||
                                                    <input value="Speichern" class="btn btn-primary" type="submit" />
 | 
			
		||||
                                                </form>
 | 
			
		||||
                                            </div>
 | 
			
		||||
@@ -421,11 +425,11 @@
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        {# --- START Add Buttons --- #}
 | 
			
		||||
        {% if "manage_events" in loggedin_user.roles or loggedin_user.allowed_to_steer %}
 | 
			
		||||
            <div class="grid {% if "manage_events" in loggedin_user.roles and loggedin_user.allowed_to_steer %}grid-cols-2{% endif %} text-center">
 | 
			
		||||
        {% if "manage_events" in loggedin_user.roles or loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles %}
 | 
			
		||||
            <div class="grid {% if "manage_events" in loggedin_user.roles and (loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles) %}grid-cols-2{% endif %} text-center">
 | 
			
		||||
                {% if "manage_events" in loggedin_user.roles %}
 | 
			
		||||
                    <a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Event</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#addEventForm" class="relative inline-block w-full bg-primary-900 hover:bg-primary-950 focus:bg-primary-950 dark:bg-primary-950 text-white py-2 text-sm font-semibold
 | 
			
		||||
                        {% if loggedin_user.allowed_to_steer %}
 | 
			
		||||
                        {% if loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles %}
 | 
			
		||||
                            rounded-bl-md
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            rounded-b-md
 | 
			
		||||
@@ -435,7 +439,7 @@
 | 
			
		||||
                        Event
 | 
			
		||||
                    </a>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                {% if loggedin_user.allowed_to_steer %}
 | 
			
		||||
                {% if loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles %}
 | 
			
		||||
                    <a href="#" data-sidebar="true" data-trigger="sidebar" data-header="<strong>Ausfahrt</strong> am {{ day.day| date(format='%d.%m.%Y') }} erstellen" data-day="{{ day.day }}" data-body="#sidebarForm" class="relative inline-block w-full py-2 text-primary-900 hover:text-primary-950 dark:bg-primary-600 dark:text-white dark:hover:bg-primary-500 dark:hover:text-white focus:text-primary-950 text-sm font-semibold bg-gray-100 hover:bg-gray-200 focus:bg-gray-200
 | 
			
		||||
                        {% if "manage_events" in loggedin_user.roles %}
 | 
			
		||||
                            rounded-br-md
 | 
			
		||||
@@ -444,7 +448,9 @@
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        ">
 | 
			
		||||
                        <span class="absolute inset-y-0 left-0 flex items-center pl-3">{% include "includes/plus-icon" %}</span>
 | 
			
		||||
                        Ausfahrt
 | 
			
		||||
			{% if not loggedin_user.allowed_to_steer %}Ergo-Session
 | 
			
		||||
			{%- else -%}
 | 
			
		||||
                        Ausfahrt{%endif%}
 | 
			
		||||
                    </a>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -454,7 +460,7 @@
 | 
			
		||||
{% endfor %}
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
{% if loggedin_user.allowed_to_steer %}
 | 
			
		||||
{% if loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles  %}
 | 
			
		||||
    {% include "forms/trip" %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% if "manage_events" in loggedin_user.roles %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user