Merge pull request 'boatshouse' (#258) from boatshouse into main
Reviewed-on: #258
This commit was merged in pull request #258.
	This commit is contained in:
		@@ -140,3 +140,13 @@ CREATE TABLE IF NOT EXISTS "boat_damage" (
 | 
			
		||||
	"verified_at" datetime,
 | 
			
		||||
	"lock_boat" boolean not null default false -- if true: noone can use the boat 
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "boathouse" (
 | 
			
		||||
    "id" INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    "boat_id" INTEGER NOT NULL REFERENCES boat(id),
 | 
			
		||||
    "aisle" TEXT NOT NULL CHECK (aisle in ('water', 'middle', 'mountain')),
 | 
			
		||||
    "side" TEXT NOT NULL CHECK(side IN ('mountain', 'water')),
 | 
			
		||||
    "level" INTEGER NOT NULL CHECK(level BETWEEN 0 AND 3),
 | 
			
		||||
    CONSTRAINT unq UNIQUE (aisle, side, level) -- only 1 boat allowed to rest at each space 
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -181,6 +181,41 @@ ORDER BY amount_seats DESC
 | 
			
		||||
        Self::boats_to_details(db, boats).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn all_for_boatshouse(db: &SqlitePool) -> Vec<BoatWithDetails> {
 | 
			
		||||
        let boats = sqlx::query_as!(
 | 
			
		||||
            Boat,
 | 
			
		||||
            "
 | 
			
		||||
SELECT 
 | 
			
		||||
    b.id, 
 | 
			
		||||
    b.name, 
 | 
			
		||||
    b.amount_seats, 
 | 
			
		||||
    b.location_id, 
 | 
			
		||||
    b.owner, 
 | 
			
		||||
    b.year_built, 
 | 
			
		||||
    b.boatbuilder, 
 | 
			
		||||
    b.default_shipmaster_only_steering, 
 | 
			
		||||
    b.default_destination, 
 | 
			
		||||
    b.skull, 
 | 
			
		||||
    b.external
 | 
			
		||||
FROM 
 | 
			
		||||
    boat AS b
 | 
			
		||||
LEFT JOIN 
 | 
			
		||||
    boathouse AS bh ON b.id = bh.boat_id
 | 
			
		||||
WHERE 
 | 
			
		||||
    b.external = false 
 | 
			
		||||
    AND b.location_id = (SELECT id FROM location WHERE name = 'Linz')
 | 
			
		||||
    AND bh.id IS NULL -- This ensures the boat does not have an entry in the boathouse table
 | 
			
		||||
ORDER BY 
 | 
			
		||||
    b.name DESC;
 | 
			
		||||
        "
 | 
			
		||||
        )
 | 
			
		||||
        .fetch_all(db)
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap(); //TODO: fixme
 | 
			
		||||
 | 
			
		||||
        Self::boats_to_details(db, boats).await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn for_user(db: &SqlitePool, user: &User) -> Vec<BoatWithDetails> {
 | 
			
		||||
        if user.has_role(db, "admin").await {
 | 
			
		||||
            return Self::all(db).await;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										90
									
								
								src/model/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/model/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use rocket::serde::{Deserialize, Serialize};
 | 
			
		||||
use sqlx::{FromRow, SqlitePool};
 | 
			
		||||
 | 
			
		||||
use crate::tera::board::boathouse::FormBoathouseToAdd;
 | 
			
		||||
 | 
			
		||||
use super::boat::Boat;
 | 
			
		||||
 | 
			
		||||
#[derive(FromRow, Debug, Serialize, Deserialize)]
 | 
			
		||||
pub struct Boathouse {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
    pub boat_id: i64,
 | 
			
		||||
    pub aisle: String,
 | 
			
		||||
    pub side: String,
 | 
			
		||||
    pub level: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Boathouse {
 | 
			
		||||
    pub async fn get(db: &SqlitePool) -> HashMap<&str, HashMap<&str, [Option<(i64, Boat)>; 4]>> {
 | 
			
		||||
        let mut ret: HashMap<&str, HashMap<&str, [Option<(i64, Boat)>; 4]>> = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        let mut mountain = HashMap::new();
 | 
			
		||||
        mountain.insert("mountain", [None, None, None, None]);
 | 
			
		||||
        mountain.insert("water", [None, None, None, None]);
 | 
			
		||||
        ret.insert("mountain-aisle", mountain);
 | 
			
		||||
 | 
			
		||||
        let mut middle = HashMap::new();
 | 
			
		||||
        middle.insert("mountain", [None, None, None, None]);
 | 
			
		||||
        middle.insert("water", [None, None, None, None]);
 | 
			
		||||
        ret.insert("middle-aisle", middle);
 | 
			
		||||
 | 
			
		||||
        let mut water = HashMap::new();
 | 
			
		||||
        water.insert("mountain", [None, None, None, None]);
 | 
			
		||||
        water.insert("water", [None, None, None, None]);
 | 
			
		||||
        ret.insert("water-aisle", water);
 | 
			
		||||
 | 
			
		||||
        let boathouses = sqlx::query_as!(
 | 
			
		||||
            Boathouse,
 | 
			
		||||
            "SELECT id, boat_id, aisle, side, level FROM boathouse"
 | 
			
		||||
        )
 | 
			
		||||
        .fetch_all(db)
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap(); //TODO: fixme
 | 
			
		||||
 | 
			
		||||
        for boathouse in boathouses {
 | 
			
		||||
            let aisle = ret
 | 
			
		||||
                .get_mut(format!("{}-aisle", boathouse.aisle).as_str())
 | 
			
		||||
                .unwrap();
 | 
			
		||||
            let side = aisle.get_mut(boathouse.side.as_str()).unwrap();
 | 
			
		||||
 | 
			
		||||
            side[boathouse.level as usize] = Some((
 | 
			
		||||
                boathouse.id,
 | 
			
		||||
                Boat::find_by_id(db, boathouse.boat_id as i32)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .unwrap(),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ret
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn create(db: &SqlitePool, data: FormBoathouseToAdd) -> Result<(), String> {
 | 
			
		||||
        sqlx::query!(
 | 
			
		||||
            "INSERT INTO boathouse(boat_id, aisle, side, level) VALUES (?,?,?,?)",
 | 
			
		||||
            data.boat_id,
 | 
			
		||||
            data.aisle,
 | 
			
		||||
            data.side,
 | 
			
		||||
            data.level
 | 
			
		||||
        )
 | 
			
		||||
        .execute(db)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| e.to_string())?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
 | 
			
		||||
        sqlx::query_as!(Self, "SELECT * FROM boathouse WHERE id like ?", id)
 | 
			
		||||
            .fetch_one(db)
 | 
			
		||||
            .await
 | 
			
		||||
            .ok()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn delete(&self, db: &SqlitePool) {
 | 
			
		||||
        sqlx::query!("DELETE FROM boathouse WHERE id=?", self.id)
 | 
			
		||||
            .execute(db)
 | 
			
		||||
            .await
 | 
			
		||||
            .unwrap(); //Okay, because we can only create a Boat of a valid id
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,7 @@ use self::{
 | 
			
		||||
 | 
			
		||||
pub mod boat;
 | 
			
		||||
pub mod boatdamage;
 | 
			
		||||
pub mod boathouse;
 | 
			
		||||
pub mod family;
 | 
			
		||||
pub mod location;
 | 
			
		||||
pub mod log;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										85
									
								
								src/tera/board/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/tera/board/boathouse.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
use crate::model::{
 | 
			
		||||
    boat::Boat,
 | 
			
		||||
    boathouse::Boathouse,
 | 
			
		||||
    user::{AdminUser, UserWithRoles, VorstandUser},
 | 
			
		||||
};
 | 
			
		||||
use rocket::{
 | 
			
		||||
    form::Form,
 | 
			
		||||
    get, post,
 | 
			
		||||
    request::FlashMessage,
 | 
			
		||||
    response::{Flash, Redirect},
 | 
			
		||||
    routes, FromForm, Route, State,
 | 
			
		||||
};
 | 
			
		||||
use rocket_dyn_templates::{tera::Context, Template};
 | 
			
		||||
use sqlx::SqlitePool;
 | 
			
		||||
 | 
			
		||||
#[get("/boathouse")]
 | 
			
		||||
async fn index(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    admin: VorstandUser,
 | 
			
		||||
    flash: Option<FlashMessage<'_>>,
 | 
			
		||||
) -> Template {
 | 
			
		||||
    let mut context = Context::new();
 | 
			
		||||
    if let Some(msg) = flash {
 | 
			
		||||
        context.insert("flash", &msg.into_inner());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let boats = Boat::all_for_boatshouse(db).await;
 | 
			
		||||
    context.insert("boats", &boats);
 | 
			
		||||
 | 
			
		||||
    let boathouse = Boathouse::get(db).await;
 | 
			
		||||
    context.insert("boathouse", &boathouse);
 | 
			
		||||
 | 
			
		||||
    context.insert(
 | 
			
		||||
        "loggedin_user",
 | 
			
		||||
        &UserWithRoles::from_user(admin.into(), db).await,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Template::render("board/boathouse", context.into_json())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(FromForm)]
 | 
			
		||||
pub struct FormBoathouseToAdd {
 | 
			
		||||
    pub boat_id: i32,
 | 
			
		||||
    pub aisle: String,
 | 
			
		||||
    pub side: String,
 | 
			
		||||
    pub level: i32,
 | 
			
		||||
}
 | 
			
		||||
#[post("/boathouse", data = "<data>")]
 | 
			
		||||
async fn new<'r>(
 | 
			
		||||
    db: &State<SqlitePool>,
 | 
			
		||||
    data: Form<FormBoathouseToAdd>,
 | 
			
		||||
    _admin: AdminUser,
 | 
			
		||||
) -> Flash<Redirect> {
 | 
			
		||||
    match Boathouse::create(db, data.into_inner()).await {
 | 
			
		||||
        Ok(_) => Flash::success(Redirect::to("/board/boathouse"), "Boot hinzugefügt"),
 | 
			
		||||
        Err(e) => Flash::error(Redirect::to("/board/boathouse"), e),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[get("/boathouse/<boathouse_id>/delete")]
 | 
			
		||||
async fn delete(db: &State<SqlitePool>, _admin: AdminUser, boathouse_id: i32) -> Flash<Redirect> {
 | 
			
		||||
    let boat = Boathouse::find_by_id(db, boathouse_id).await;
 | 
			
		||||
    match boat {
 | 
			
		||||
        Some(boat) => {
 | 
			
		||||
            boat.delete(db).await;
 | 
			
		||||
            Flash::success(Redirect::to("/board/boathouse"), "Bootsplatz gelöscht")
 | 
			
		||||
        }
 | 
			
		||||
        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> {
 | 
			
		||||
    routes![index, new, delete]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/tera/board/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/tera/board/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
use rocket::Route;
 | 
			
		||||
 | 
			
		||||
pub mod boathouse;
 | 
			
		||||
 | 
			
		||||
pub fn routes() -> Vec<Route> {
 | 
			
		||||
    let mut ret = Vec::new();
 | 
			
		||||
    ret.append(&mut boathouse::routes());
 | 
			
		||||
    ret
 | 
			
		||||
}
 | 
			
		||||
@@ -21,6 +21,7 @@ use crate::model::user::{User, UserWithRoles};
 | 
			
		||||
 | 
			
		||||
pub(crate) mod admin;
 | 
			
		||||
mod auth;
 | 
			
		||||
pub(crate) mod board;
 | 
			
		||||
mod boatdamage;
 | 
			
		||||
mod cox;
 | 
			
		||||
mod ergo;
 | 
			
		||||
@@ -89,6 +90,7 @@ pub fn config(rocket: Rocket<Build>) -> Rocket<Build> {
 | 
			
		||||
        .mount("/boatdamage", boatdamage::routes())
 | 
			
		||||
        .mount("/cox", cox::routes())
 | 
			
		||||
        .mount("/admin", admin::routes())
 | 
			
		||||
        .mount("/board", board::routes())
 | 
			
		||||
        .mount("/", misc::routes())
 | 
			
		||||
        .mount("/public", FileServer::from("static/"))
 | 
			
		||||
        .register("/", catchers![unauthorized_error, forbidden_error])
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "boathouse" (
 | 
			
		||||
    "id" INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
    "boat_id" INTEGER NOT NULL REFERENCES boat(id),
 | 
			
		||||
    "aisle" TEXT NOT NULL CHECK (aisle in ('water', 'middle', 'mountain')),
 | 
			
		||||
    "side" TEXT NOT NULL CHECK(side IN ('mountain', 'water')),
 | 
			
		||||
    "level" INTEGER NOT NULL CHECK(level BETWEEN 0 AND 3),
 | 
			
		||||
    CONSTRAINT unq UNIQUE (aisle, side, level) -- only 1 boat allowed to rest at each space 
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% import "includes/forms/boat" as boat %}
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        <h1 class="h1">Boats</h1>
 | 
			
		||||
        {{ boat::new() }}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
{% import "includes/macros" as macros %}
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        <h1 class="h1">List</h1>
 | 
			
		||||
        <form action="/admin/list" method="post">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
{% import "includes/macros" as macros %}
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        <h1 class="h1">List - Result</h1>
 | 
			
		||||
        <ol>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% import "includes/forms/boat" as boat %}
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        <h1 class="h1">Mail</h1>
 | 
			
		||||
        <form action="/admin/mail" method="post" enctype="multipart/form-data">
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        <h1 class="h1">Schnupper Verwaltung</h1>
 | 
			
		||||
        <div class="grid gap-3">
 | 
			
		||||
            <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        <h1 class="h1">Gebühren</h1>
 | 
			
		||||
        <!-- START filterBar -->
 | 
			
		||||
        <div class="search-wrapper">
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        <h1 class="h1">Users</h1>
 | 
			
		||||
        {% if allowed_to_edit %}
 | 
			
		||||
            <form action="/admin/user/new"
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        <h1 class="h1">Scheckbücher</h1>
 | 
			
		||||
        <!-- START filterBar -->
 | 
			
		||||
        <div class="search-wrapper">
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,12 @@
 | 
			
		||||
                </div>
 | 
			
		||||
            </header>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <div class="flex min-h-screen {% if not loggedin_user and not show_kiosk_header %} items-center dark:bg-primary-900 {% else %} items-start {% endif %} justify-center px-4 py-12 sm:px-6 lg:px-8">
 | 
			
		||||
        <div class="flex flex-wrap min-h-screen {% if not loggedin_user and not show_kiosk_header %} items-center dark:bg-primary-900 {% else %} items-start {% endif %} justify-center px-4 py-12 sm:px-6 lg:px-8">
 | 
			
		||||
            {% if flash and loggedin_user %}
 | 
			
		||||
                <div class="max-w-screen-lg w-full mb-3">
 | 
			
		||||
                    {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% block content %}
 | 
			
		||||
            {% endblock content %}
 | 
			
		||||
        </div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								templates/board/boathouse.html.tera
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								templates/board/boathouse.html.tera
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
{% import "includes/macros" as macros %}
 | 
			
		||||
{% import "includes/forms/log" as log %}
 | 
			
		||||
{% import "includes/forms/boat" as boat %}
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% macro show_place(aisle_name, side_name, level) %}
 | 
			
		||||
    <li class="truncate p-2 flex relative w-full">
 | 
			
		||||
        {% set aisle = aisle_name ~ "-aisle" %}
 | 
			
		||||
        {% set place = boathouse[aisle][side_name] %}
 | 
			
		||||
        {% if place[level] %}
 | 
			
		||||
            {{ place[level].1.name }} <a class="btn btn-primary absolute end-0" href="/board/boathouse/{{ place[level].0 }}/delete">X</a>
 | 
			
		||||
        {% elif boats | length > 0 %}
 | 
			
		||||
            <details>
 | 
			
		||||
                <summary>Kein Boot</summary>
 | 
			
		||||
                <form action="/board/boathouse" method="post" class="grid gap-3">
 | 
			
		||||
                    {{ macros::select(label="Boot", data=boats, name="boat_id", id="boat_id", display=["name", " (","amount_seats", " x)"], wrapper_class="col-span-4") }}
 | 
			
		||||
                    <input type="hidden" name="aisle" value="{{ aisle_name }}" />
 | 
			
		||||
                    <input type="hidden" name="side" value="{{ side_name }}" />
 | 
			
		||||
                    <input type="hidden" name="level" value="{{ level }}" />
 | 
			
		||||
                    <input type="submit"
 | 
			
		||||
                           class="btn btn-primary w-full col-span-4"
 | 
			
		||||
                           value="Boot eintragen" />
 | 
			
		||||
                </form>
 | 
			
		||||
            </details>
 | 
			
		||||
        {% else %}
 | 
			
		||||
            Kein Boot
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </li>
 | 
			
		||||
{% endmacro show_place %}
 | 
			
		||||
{% macro show_side(aisle_name, side_name) %}
 | 
			
		||||
    <div class="{{ side_name }}-side">
 | 
			
		||||
        <ol>
 | 
			
		||||
            {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 0) }}
 | 
			
		||||
            {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 1) }}
 | 
			
		||||
            {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 2) }}
 | 
			
		||||
            {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 3) }}
 | 
			
		||||
        </ol>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endmacro show_side %}
 | 
			
		||||
{% macro show_aisle(name, last=false) %}
 | 
			
		||||
    <div id="{{ name }}-aisle" class="grid grid-cols-2 gap-4 {% if not last %}md:border-r{% endif %}">
 | 
			
		||||
        {{ self::show_side(aisle_name = name, side_name = "mountain") }}
 | 
			
		||||
        {{ self::show_side(aisle_name = name, side_name = "water") }}
 | 
			
		||||
    </div>
 | 
			
		||||
{% endmacro show_aisle %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full dark:text-white">
 | 
			
		||||
        <h1 class="h1">Bootshaus</h1>
 | 
			
		||||
        <div class="grid md:grid-cols-3 gap-4">
 | 
			
		||||
            {{ self::show_aisle(name = "mountain") }}
 | 
			
		||||
            {{ self::show_aisle(name = "middle") }}
 | 
			
		||||
            {{ self::show_aisle(name = "water", last = true) }}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock content %}
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        <h1 class="h1">Bootschäden</h1>
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3 mt-3") }}{% endif %}
 | 
			
		||||
        <h2 class="text-md font-bold tracking-wide bg-primary-900 mt-3 p-3 text-white flex justify-between items-center rounded-md">
 | 
			
		||||
            Neuen Schaden
 | 
			
		||||
            <a href="#"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        <h1 class="h1">Aktuelle Woche</h1>
 | 
			
		||||
        <details>
 | 
			
		||||
            <summary>Dirty Thirty</summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        <h1 class="h1">Ergo Challenges</h1>
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="my-3") }}{% endif %}
 | 
			
		||||
        <div class="grid gap-3">
 | 
			
		||||
            <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
 | 
			
		||||
                 role="alert">
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-lg w-full">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        <h1 class="h1">Ruderassistent</h1>
 | 
			
		||||
        <div class="grid gap-3">
 | 
			
		||||
            <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
 | 
			
		||||
@@ -110,6 +109,9 @@
 | 
			
		||||
                            <li class="py-1">
 | 
			
		||||
                                <a href="/admin/user" class="link-primary">User</a>
 | 
			
		||||
                            </li>
 | 
			
		||||
                            <li class="py-1">
 | 
			
		||||
                                <a href="/board/boathouse" class="link-primary">Bootshaus</a>
 | 
			
		||||
                            </li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="w-full">
 | 
			
		||||
        <h1 class="h1">Logbuch</h1>
 | 
			
		||||
        {% if flash %}
 | 
			
		||||
        {% if flash and not loggedin_user %}
 | 
			
		||||
            <div class="pt-3 max-w-lg m-auto">
 | 
			
		||||
                {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,6 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="w-full">
 | 
			
		||||
        <h1 class="h1">Logbuch</h1>
 | 
			
		||||
        {% if flash %}
 | 
			
		||||
            <div class="w-full">{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}</div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <div class="w-full grid md:grid-cols-5 gap-3 mt-5">
 | 
			
		||||
            <div class="bg-white dark:bg-primary-900 rounded-md hidden md:block shadow">
 | 
			
		||||
                <h2 class="h2">Boote</h2>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
{% extends "base" %}
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <div class="max-w-screen-xl w-full grid sm:grid-cols-2 lg:grid-cols-3 gap-4">
 | 
			
		||||
        {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}
 | 
			
		||||
        {% if "scheckbuch" in loggedin_user.roles %}
 | 
			
		||||
            <div class="grid gap-3 sm:col-span-2 lg:col-span-3">
 | 
			
		||||
                <div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user