diff --git a/.gitea/workflows/action.yml b/.gitea/workflows/action.yml index 07996d0..3279821 100644 --- a/.gitea/workflows/action.yml +++ b/.gitea/workflows/action.yml @@ -26,8 +26,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-debug- + key: ${{ runner.os }}-cargo-debug-rowt-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-debug-rowt- - name: Build run: | @@ -65,8 +65,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-release- + key: ${{ runner.os }}-cargo-release-rowt-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-release-rowt- - name: Build run: | cargo build --release --target $CARGO_TARGET @@ -80,15 +80,15 @@ jobs: echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa - scp target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/philipp/rowing-staging/rot-updating + scp target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/rowing-staging/rot-updating - scp staging-diff.sql $SSH_USER@$SSH_HOST:/home/philipp/rowing-staging/ - scp -r static $SSH_USER@$SSH_HOST:/home/philipp/rowing-staging/ - scp -r templates $SSH_USER@$SSH_HOST:/home/philipp/rowing-staging/ - scp -r svelte $SSH_USER@$SSH_HOST:/home/philipp/rowing-staging/ + scp staging-diff.sql $SSH_USER@$SSH_HOST:/home/rowing-staging/ + scp -r static $SSH_USER@$SSH_HOST:/home/rowing-staging/ + scp -r templates $SSH_USER@$SSH_HOST:/home/rowing-staging/ + scp -r svelte $SSH_USER@$SSH_HOST:/home/rowing-staging/ ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop rotstaging' - ssh $SSH_USER@$SSH_HOST 'rm /home/philipp/rowing-staging/db.sqlite && cp /home/philipp/rowing/db.sqlite /home/philipp/rowing-staging/db.sqlite && mkdir -p /home/philipp/rowing-staging/svelte/build && mkdir -p /home/philipp/rowing-staging/data-ergo/thirty && mkdir -p /home/philipp/rowing-staging/data-ergo/dozen && sqlite3 /home/philipp/rowing-staging/db.sqlite < /home/philipp/rowing-staging/staging-diff.sql' - ssh $SSH_USER@$SSH_HOST 'mv /home/philipp/rowing-staging/rot-updating /home/philipp/rowing-staging/rot' + ssh $SSH_USER@$SSH_HOST 'rm /home/rowing-staging/db.sqlite && cp /home/rowing/db.sqlite /home/rowing-staging/db.sqlite && mkdir -p /home/rowing-staging/svelte/build && mkdir -p /home/rowing-staging/data-ergo/thirty && mkdir -p /home/rowing-staging/data-ergo/dozen && sqlite3 /home/rowing-staging/db.sqlite < /home/rowing-staging/staging-diff.sql' + ssh $SSH_USER@$SSH_HOST 'mv /home/rowing-staging/rot-updating /home/rowing-staging/rot' ssh $SSH_USER@$SSH_HOST 'sudo systemctl start rotstaging' env: SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} @@ -116,8 +116,8 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-release- + key: ${{ runner.os }}-cargo-release-rowt-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-release-rowt- - name: Build run: | @@ -132,13 +132,13 @@ jobs: echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa - scp target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/philipp/rowing/rot-updating - scp -r static $SSH_USER@$SSH_HOST:/home/philipp/rowing/ - scp -r templates $SSH_USER@$SSH_HOST:/home/philipp/rowing/ - scp -r svelte $SSH_USER@$SSH_HOST:/home/philipp/rowing/ - ssh $SSH_USER@$SSH_HOST 'mkdir -p /home/philipp/rowing/svelte/build && mkdir -p /home/philipp/rowing/data-ergo/thirty && mkdir -p /home/philipp/rowing/data-ergo/dozen' + scp target/$CARGO_TARGET/release/rot $SSH_USER@$SSH_HOST:/home/rowing/rot-updating + scp -r static $SSH_USER@$SSH_HOST:/home/rowing/ + scp -r templates $SSH_USER@$SSH_HOST:/home/rowing/ + scp -r svelte $SSH_USER@$SSH_HOST:/home/rowing/ + ssh $SSH_USER@$SSH_HOST 'mkdir -p /home/rowing/svelte/build && mkdir -p /home/rowing/data-ergo/thirty && mkdir -p /home/rowing/data-ergo/dozen' ssh $SSH_USER@$SSH_HOST 'sudo systemctl stop rot' - ssh $SSH_USER@$SSH_HOST 'mv /home/philipp/rowing/rot-updating /home/philipp/rowing/rot' + ssh $SSH_USER@$SSH_HOST 'mv /home/rowing/rot-updating /home/rowing/rot' ssh $SSH_USER@$SSH_HOST 'sudo systemctl start rot' env: SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} diff --git a/README.md b/README.md index 4e61b4d..de2636d 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,25 @@ - Rust: `cargo check` - Tera files: `djlint **.html.tera --profile=jinja --reformat` - Typescript: `prettier -w *.ts` + +# Dependencies +- `sqlite3` +- `rust` + +# Nginx config + +``` +server { + server_name staging.rudernlinz.at; + location / { + proxy_pass http://localhost:7999/; # The / is important! + } +} + +server { + server_name app.rudernlinz.at; + location / { + proxy_pass http://localhost:8001/; # The / is important! + } +} +``` diff --git a/migration.sql b/migration.sql index 74332d1..b265045 100644 --- a/migration.sql +++ b/migration.sql @@ -146,7 +146,7 @@ CREATE TABLE IF NOT EXISTS "boathouse" ( "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), + "level" INTEGER NOT NULL CHECK(level BETWEEN 0 AND 11), CONSTRAINT unq UNIQUE (aisle, side, level) -- only 1 boat allowed to rest at each space ); diff --git a/rot.service b/rot.service index b0f3632..bdb2d95 100644 --- a/rot.service +++ b/rot.service @@ -4,12 +4,15 @@ Description=Rot [Service] User=root Group=root -WorkingDirectory=/home/philipp/rowing +WorkingDirectory=/home/rowing Environment="ROCKET_ENV=prod" Environment="ROCKET_ADDRESS=127.0.0.1" Environment="ROCKET_PORT=8001" Environment="RUST_LOG=info" -ExecStart=/home/k004373/rowing/rot +ExecStart=/home/rowing/rot +Restart=always +RestartSec=10 + [Install] WantedBy=multi-user.target diff --git a/rotstaging.service b/rotstaging.service index ed6ee20..5a76e86 100644 --- a/rotstaging.service +++ b/rotstaging.service @@ -4,12 +4,14 @@ Description=Rot Staging [Service] User=root Group=root -WorkingDirectory=/home/philipp/rowing-staging +WorkingDirectory=/home/rowing-staging Environment="ROCKET_ENV=prod" Environment="ROCKET_ADDRESS=127.0.0.1" Environment="ROCKET_PORT=7999" Environment="ROCKET_LOG=info" -ExecStart=/home/philipp/rowing-staging/rot +ExecStart=/home/rowing-staging/rot +Restart=always +RestartSec=10 [Install] WantedBy=multi-user.target diff --git a/src/model/boathouse.rs b/src/model/boathouse.rs index a3ae022..0e96caf 100644 --- a/src/model/boathouse.rs +++ b/src/model/boathouse.rs @@ -17,22 +17,52 @@ pub struct Boathouse { } 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(); + pub async fn get(db: &SqlitePool) -> HashMap<&str, HashMap<&str, [Option<(i64, Boat)>; 12]>> { + let mut ret: HashMap<&str, HashMap<&str, [Option<(i64, Boat)>; 12]>> = HashMap::new(); let mut mountain = HashMap::new(); - mountain.insert("mountain", [None, None, None, None]); - mountain.insert("water", [None, None, None, None]); + mountain.insert( + "mountain", + [ + None, None, None, None, None, None, None, None, None, None, None, None, + ], + ); + mountain.insert( + "water", + [ + None, None, None, None, None, None, None, None, 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]); + middle.insert( + "mountain", + [ + None, None, None, None, None, None, None, None, None, None, None, None, + ], + ); + middle.insert( + "water", + [ + None, None, None, None, None, None, None, None, 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]); + water.insert( + "mountain", + [ + None, None, None, None, None, None, None, None, None, None, None, None, + ], + ); + water.insert( + "water", + [ + None, None, None, None, None, None, None, None, None, None, None, None, + ], + ); ret.insert("water-aisle", water); let boathouses = sqlx::query_as!( diff --git a/src/model/logbook.rs b/src/model/logbook.rs index a9a70ce..d3c6e92 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -472,7 +472,7 @@ ORDER BY departure DESC mut log: LogToFinalize, ) -> Result<(), LogbookUpdateError> { //TODO: extract common tests with `create()` - if user.id != self.shipmaster { + if !user.has_role_tx(db, "Vorstand").await && user.id != self.shipmaster { return Err(LogbookUpdateError::NotYourEntry); } @@ -549,7 +549,10 @@ ORDER BY departure DESC pub async fn delete(&self, db: &SqlitePool, user: &User) -> Result<(), LogbookDeleteError> { Log::create(db, format!("{user:?} deleted trip: {self:?}")).await; - if user.has_role(db, "admin").await || user.id == self.shipmaster { + if user.has_role(db, "admin").await + || user.has_role(db, "Vorstand").await + || user.id == self.shipmaster + { sqlx::query!("DELETE FROM logbook WHERE id=?", self.id) .execute(db) .await diff --git a/src/model/mail.rs b/src/model/mail.rs index e52866e..1a82ce1 100644 --- a/src/model/mail.rs +++ b/src/model/mail.rs @@ -182,4 +182,116 @@ Der Vorstand } } } + + pub async fn fees_final(db: &SqlitePool, smtp_pw: String) { + let users = User::all_payer_groups(db).await; + for user in users { + if let Some(fee) = user.fee(db).await { + if !fee.paid { + let mut is_family = false; + let mut send_to = String::new(); + match Family::find_by_opt_id(db, user.family_id).await { + Some(family) => { + is_family = true; + for member in family.members(db).await { + if let Some(mail) = member.mail { + send_to.push_str(&format!("{mail},")) + } + } + } + None => { + if let Some(mail) = &user.mail { + send_to.push_str(mail) + } + } + } + + let fees = user.fee(db).await; + if let Some(fees) = fees { + let mut content = format!( + "Liebes Vereinsmitglied, \n\n\ +wir möchten darauf hinweisen, dass wir deinen Mitgliedsbeitrag für das laufende Jahr bislang nicht verbuchen konnten. Es besteht die Möglichkeit, dass es sich hierbei um ein Versehen unsererseits handelt. Solltest du den Betrag bereits überwiesen haben, bitte kurz auf diese E-Mail antworten, damit wir es richtigstellen können. + +Falls die Zahlung noch nicht erfolgt ist, bitten wir um umgehende Überweisung des ausstehenden Betrags, spätestens jedoch bis zum 31. März, auf unser Bankkonto.\n\n\ +Dein Vereinsbeitrag für das aktuelle Jahr beträgt {}€", + fees.sum_in_cents / 100, + ); + + if fees.parts.len() == 1 { + content.push_str(&format!(" ({}).\n", fees.parts[0].0)) + } else { + content + .push_str(". Dieser setzt sich aus folgenden Teilen zusammen: \n"); + for (desc, fee_in_cents) in fees.parts { + content.push_str(&format!("- {}: {}€\n", desc, fee_in_cents / 100)) + } + } + if is_family { + content.push_str(&format!( + "Dieser gilt für die gesamte Familie ({}).\n", + fees.name + )) + } + content.push_str("\n\ +Gemäß § 7 Abs. 3 lit. c unseres Status behalten wir uns vor, bei ausbleibender Zahlung die Mitgliedschaft zu beenden. Dies möchten wir vermeiden und hoffen auf deine Unterstützung.\n\n\ +Bei Fragen oder Problemen stehen wir gerne zur Verfügung. + +Bankverbindung: IBAN: AT13 1200 0804 1300 1200 (Unter https://app.rudernlinz.at/planned findest du einen QR Code, den du mit deiner Bankapp scannen kannst um alle Eingaben bereits ausgefüllt zu haben.) + +Mit freundlichen Grüßen,\n\ +Der Vorstand"); + let mut email = Message::builder() + .from( + "ASKÖ Ruderverein Donau Linz " + .parse() + .unwrap(), + ) + .reply_to( + "ASKÖ Ruderverein Donau Linz " + .parse() + .unwrap(), + ) + .to("ASKÖ Ruderverein Donau Linz " + .parse() + .unwrap()); + let splitted = send_to.split(','); + let mut send_mail = false; + for single_rec in splitted { + let single_rec = single_rec.trim(); + match single_rec.parse() { + Ok(val) => { + email = email.bcc(val); + send_mail = true; + } + Err(_) => { + println!("Error in mail: {single_rec}"); + } + } + } + + if send_mail { + let email = email + .subject("Mahnung Vereinsgebühren | ASKÖ Ruderverein Donau Linz") + .header(ContentType::TEXT_PLAIN) + .body(content) + .unwrap(); + + let creds = Credentials::new( + "no-reply@rudernlinz.at".to_owned(), + smtp_pw.clone(), + ); + + let mailer = SmtpTransport::relay("mail.your-server.de") + .unwrap() + .credentials(creds) + .build(); + + // Send the email + mailer.send(&email).unwrap(); + } + } + } + } + } + } } diff --git a/src/model/stat.rs b/src/model/stat.rs index c53c267..6344a2d 100644 --- a/src/model/stat.rs +++ b/src/model/stat.rs @@ -73,7 +73,8 @@ WHERE u.id NOT IN ( WHERE ro.name = 'Donau Linz' ) AND l.distance_in_km IS NOT NULL -AND l.arrival LIKE '{year}-%'; +AND l.arrival LIKE '{year}-%' +AND u.name != 'Externe Steuerperson'; " )) .fetch_one(db) @@ -87,6 +88,16 @@ AND l.arrival LIKE '{year}-%'; } } + pub async fn sum_people(db: &SqlitePool, year: Option) -> i32 { + let stats = Self::people(db, year).await; + let mut sum = 0; + for stat in stats { + sum += stat.rowed_km; + } + + sum + } + pub async fn people(db: &SqlitePool, year: Option) -> Vec { let year = match year { Some(year) => year, diff --git a/src/model/user.rs b/src/model/user.rs index 11f4af4..ca6b710 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -25,7 +25,7 @@ const REGULAR: i32 = 22000; const UNTERSTUETZEND: i32 = 2500; const FOERDERND: i32 = 8500; -#[derive(FromRow, Debug, Serialize, Deserialize)] +#[derive(FromRow, Debug, Serialize, Deserialize, Clone)] pub struct User { pub id: i64, pub name: String, @@ -106,6 +106,7 @@ pub struct Fee { pub name: String, pub user_ids: String, pub paid: bool, + pub users: Vec, } impl Default for Fee { @@ -121,6 +122,7 @@ impl Fee { name: "".into(), parts: Vec::new(), user_ids: "".into(), + users: Vec::new(), paid: false, } } @@ -139,6 +141,7 @@ impl Fee { self.name.push_str(&user.name); self.user_ids.push_str(&format!("user_ids[]={}", user.id)); + self.users.push(user.clone()); } pub fn paid(&mut self) { @@ -509,6 +512,8 @@ ORDER BY last_access DESC if ![ "n-sageder", "p-hofer", + "daniel-kortschak", + "rudernlinz", "m-birner", "s-sollberger", "d-kortschak", diff --git a/src/tera/admin/mail.rs b/src/tera/admin/mail.rs index fee06ab..2afcd3a 100644 --- a/src/tera/admin/mail.rs +++ b/src/tera/admin/mail.rs @@ -6,6 +6,7 @@ use rocket::{post, FromForm}; use rocket_dyn_templates::{tera::Context, Template}; use sqlx::SqlitePool; +use crate::model::log::Log; use crate::model::mail::Mail; use crate::model::role::Role; use crate::model::user::AdminUser; @@ -34,11 +35,23 @@ async fn index( } #[get("/mail/fee")] -async fn fee(db: &State, _admin: AdminUser, config: &State) -> &'static str { +async fn fee(db: &State, admin: AdminUser, config: &State) -> &'static str { + Log::create(db, format!("{admin:?} trying to send fee")).await; Mail::fees(db, config.smtp_pw.clone()).await; "SUCC" } +#[get("/mail/fee-final")] +async fn fee_final( + db: &State, + admin: AdminUser, + config: &State, +) -> &'static str { + Log::create(db, format!("{admin:?} trying to send fee_final")).await; + Mail::fees_final(db, config.smtp_pw.clone()).await; + "SUCC" +} + #[derive(FromForm, Debug)] pub struct MailToSend<'a> { pub(crate) role_id: i32, @@ -52,18 +65,21 @@ async fn update( db: &State, data: Form>, config: &State, - _admin: AdminUser, + admin: AdminUser, ) -> Flash { let d = data.into_inner(); + Log::create(db, format!("{admin:?} trying to send this mail: {d:?}")).await; if Mail::send(db, d, config.smtp_pw.clone()).await { + Log::create(db, "Mail successfully sent".into()).await; Flash::success(Redirect::to("/admin/mail"), "Mail versendet") } else { + Log::create(db, "Error sending the mail".into()).await; Flash::error(Redirect::to("/admin/mail"), "Fehler") } } pub fn routes() -> Vec { - routes![index, update, fee] + routes![index, update, fee, fee_final] } #[cfg(test)] diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index 82eb4e3..7a55d85 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use crate::model::{ family::Family, + log::Log, logbook::Logbook, role::Role, user::{AdminUser, User, UserWithRoles, VorstandUser}, @@ -163,7 +164,7 @@ async fn scheckbuch( #[get("/user/fees/paid?")] async fn fees_paid( db: &State, - _admin: AdminUser, + admin: AdminUser, user_ids: Vec, referer: Referer, ) -> Flash { @@ -172,9 +173,19 @@ async fn fees_paid( let user = User::find_by_id(db, user_id).await.unwrap(); res.push_str(&format!("{} + ", user.name)); if user.has_role(db, "paid").await { + Log::create( + db, + format!("{} set fees NOT paid for '{}'", admin.user.name, user.name), + ) + .await; user.remove_role(db, &Role::find_by_name(db, "paid").await.unwrap()) .await; } else { + Log::create( + db, + format!("{} set fees paid for '{}'", admin.user.name, user.name), + ) + .await; user.add_role(db, &Role::find_by_name(db, "paid").await.unwrap()) .await; } @@ -204,8 +215,9 @@ async fn resetpw(db: &State, _admin: AdminUser, user: i32) -> Flash< } #[get("/user//delete")] -async fn delete(db: &State, _admin: AdminUser, user: i32) -> Flash { +async fn delete(db: &State, admin: AdminUser, user: i32) -> Flash { let user = User::find_by_id(db, user).await; + Log::create(db, format!("{} deleted user: {user:?}", admin.user.name)).await; match user { Some(user) => { user.delete(db).await; @@ -239,9 +251,14 @@ pub struct UserEditForm { async fn update( db: &State, data: Form, - _admin: AdminUser, + admin: AdminUser, ) -> Flash { let user = User::find_by_id(db, data.id).await; + Log::create( + db, + format!("{} updated user from {user:?} to {data:?}", admin.user.name), + ) + .await; let Some(user) = user else { return Flash::error( Redirect::to("/admin/user"), @@ -254,7 +271,7 @@ async fn update( Flash::success(Redirect::to("/admin/user"), "Successfully updated user") } -#[derive(FromForm)] +#[derive(FromForm, Debug)] struct UserAddForm<'r> { name: &'r str, } @@ -263,9 +280,14 @@ struct UserAddForm<'r> { async fn create( db: &State, data: Form>, - _admin: AdminUser, + admin: AdminUser, ) -> Flash { if User::create(db, data.name).await { + Log::create( + db, + format!("{} created new user: {data:?}", admin.user.name), + ) + .await; Flash::success(Redirect::to("/admin/user"), "Successfully created user") } else { Flash::error( diff --git a/src/tera/stat.rs b/src/tera/stat.rs index 5db94fb..6489fd5 100644 --- a/src/tera/stat.rs +++ b/src/tera/stat.rs @@ -35,25 +35,27 @@ async fn index_boat_kiosk( #[get("/?", rank = 2)] async fn index(db: &State, user: DonauLinzUser, year: Option) -> Template { let stat = Stat::people(db, year).await; + let club_km = Stat::sum_people(db, year).await; let guest_km = Stat::guest(db, year).await; let personal = stat::get_personal(db, &user).await; let kiosk = false; Template::render( "stat.people", - context!(loggedin_user: &UserWithRoles::from_user(user.into(), db).await, stat, personal, kiosk, guest_km), + context!(loggedin_user: &UserWithRoles::from_user(user.into(), db).await, stat, personal, kiosk, guest_km, club_km), ) } #[get("/?")] async fn index_kiosk(db: &State, _kiosk: KioskCookie, year: Option) -> Template { let stat = Stat::people(db, year).await; + let club_km = Stat::sum_people(db, year).await; let guest_km = Stat::guest(db, year).await; let kiosk = true; Template::render( "stat.people", - context!(stat, kiosk, show_kiosk_header: true, guest_km), + context!(stat, kiosk, show_kiosk_header: true, guest_km, club_km), ) } diff --git a/templates/admin/mail.html.tera b/templates/admin/mail.html.tera index 1f80747..1f8436c 100644 --- a/templates/admin/mail.html.tera +++ b/templates/admin/mail.html.tera @@ -2,16 +2,20 @@ {% import "includes/forms/boat" as boat %} {% extends "base" %} {% block content %} -
+

Mail

-
- - - - - -
+
+ +
{% endblock content %} diff --git a/templates/admin/schnupper/index.html.tera b/templates/admin/schnupper/index.html.tera index b2520b8..1c3ddc1 100644 --- a/templates/admin/schnupper/index.html.tera +++ b/templates/admin/schnupper/index.html.tera @@ -9,7 +9,12 @@

Angemeldete Personen: {{ schnupperanten | length }}

    - {% for user in schnupperanten %}
  1. {{ user.name }} ({{ user.mail }} | {{ user.notes }})
  2. {% endfor %} + {% for user in schnupperanten %} +
  3. + {{ user.name }} ({{ user.mail }} | {{ user.notes }}) +
  4. + {% endfor %}
diff --git a/templates/board/boathouse.html.tera b/templates/board/boathouse.html.tera index c8e60b0..5f9e3b7 100644 --- a/templates/board/boathouse.html.tera +++ b/templates/board/boathouse.html.tera @@ -7,20 +7,25 @@ {% set aisle = aisle_name ~ "-aisle" %} {% set place = boathouse[aisle][side_name] %} {% if place[level] %} - {{ place[level].1.name }} X + {{ place[level].1.name }} X {% elif boats | length > 0 %} -
- Kein Boot -
- {{ macros::select(label="Boot", data=boats, name="boat_id", id="boat_id", display=["name", " (","amount_seats", " x)"], wrapper_class="col-span-4") }} - - - - -
-
+ {% if "admin" in loggedin_user.roles %} +
+ Kein Boot +
+ {{ macros::select(label="Boot", data=boats, name="boat_id", id="boat_id", display=["name", " (","amount_seats", " x)"], wrapper_class="col-span-4") }} + + + + +
+
+ {% else %} + Kein Boot + {% endif %} {% else %} Kein Boot {% endif %} @@ -33,11 +38,41 @@ {{ 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) }} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 4) }} + {% if aisle_name != 'water' or side_name != 'water' %} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 5) }} + {% endif %} + {% set show_additional = false %} + {% if aisle_name == "mountain" %} + {% set show_additional = true %} + {% elif aisle_name == "middle" and side_name == "mountain" %} + {% set show_additional = true %} + {% endif %} + {% if show_additional %} +
+ {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 6) }} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 7) }} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 8) }} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 9) }} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 10) }} + {{ self::show_place(aisle_name = aisle_name, side_name = side_name, level = 11) }} + {% endif %} {% endmacro show_side %} {% macro show_aisle(name, last=false) %} -
+
+

+ {% if name == "water" %} + 🌊 + {% elif name == "middle" %} + ◯ + {% else %} + ⛰️ + {% endif %} + - Gang +

{{ self::show_side(aisle_name = name, side_name = "mountain") }} {{ self::show_side(aisle_name = name, side_name = "water") }}
diff --git a/templates/includes/forms/log.html.tera b/templates/includes/forms/log.html.tera index 203d57d..1f29201 100644 --- a/templates/includes/forms/log.html.tera +++ b/templates/includes/forms/log.html.tera @@ -137,9 +137,11 @@ {{ rower.name }} {% if rower.id == log.shipmaster or rower.id == log.steering_person %} ( - {% if rower.id == log.shipmaster %}Schiffsführer{% endif %} + {%- if rower.id == log.shipmaster %}Schiffsführer + {% endif -%} {% if rower.id == log.shipmaster and rower.id == log.steering_person %}/{% endif %} - {% if rower.id == log.steering_person %}Steuerperson{% endif %} + {%- if rower.id == log.steering_person %}Steuerperson + {%- endif -%} ) {% endif %}

diff --git a/templates/includes/macros.html.tera b/templates/includes/macros.html.tera index b54df4d..b958f4f 100644 --- a/templates/includes/macros.html.tera +++ b/templates/includes/macros.html.tera @@ -1,3 +1,17 @@ +{% macro boatreservation() %} +
+

Bootsreservierungen

+
+
    +
  • 22.04. | Christian Gusenbauer | Boot: Linz + kleiner Hänger
  • +
+
+
+{% endmacro boatreservation %} {% macro header(loggedin_user) %}
diff --git a/templates/kiosk.html.tera b/templates/kiosk.html.tera index 149d157..e03a452 100644 --- a/templates/kiosk.html.tera +++ b/templates/kiosk.html.tera @@ -9,6 +9,7 @@ {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}
{% endif %} + {{ macros::boatreservation() }}