first draft of single user-edit page
All checks were successful
CI/CD Pipeline / test (push) Successful in 14m43s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped

This commit is contained in:
Philipp Hofer 2025-04-29 22:37:04 +02:00
parent b0168b798c
commit 34850321b7
12 changed files with 414 additions and 166 deletions

View File

@ -1036,7 +1036,8 @@ pub struct UserWithRolesAndMembershipPdf {
#[serde(flatten)]
pub user: User,
pub membership_pdf: bool,
pub roles: Vec<String>,
pub roles: Vec<String>, // TODO: remove
pub proper_roles: Vec<Role>,
}
impl UserWithRolesAndMembershipPdf {
@ -1045,6 +1046,7 @@ impl UserWithRolesAndMembershipPdf {
Self {
roles: user.roles(db).await,
proper_roles: user.real_roles(db).await,
user,
membership_pdf,
}

View File

@ -112,6 +112,43 @@ async fn index_admin(
Template::render("admin/user/index", context.into_json())
}
#[get("/user/<user>")]
async fn view(
db: &State<SqlitePool>,
admin: VorstandUser,
flash: Option<FlashMessage<'_>>,
user: i32,
) -> Result<Template, Flash<Redirect>> {
let Some(user) = User::find_by_id(db, user).await else {
return Err(Flash::error(
Redirect::to("/admin/usert"),
format!("User mit ID {} gibts ned", user),
));
};
let user = UserWithRolesAndMembershipPdf::from_user(db, user).await;
let admin: User = admin.into_inner();
let allowed_to_edit = ManageUserUser::new(db, &admin).await.is_some();
let roles = Role::all(db).await;
let families = Family::all_with_members(db).await;
let mut context = Context::new();
if let Some(msg) = flash {
context.insert("flash", &msg.into_inner());
}
context.insert("allowed_to_edit", &allowed_to_edit);
context.insert("user", &user);
context.insert("roles", &roles);
context.insert("families", &families);
context.insert(
"loggedin_user",
&UserWithDetails::from_user(admin, db).await,
);
Ok(Template::render("admin/user/view", context.into_json()))
}
#[get("/user/fees")]
async fn fees(
db: &State<SqlitePool>,
@ -469,6 +506,7 @@ pub fn routes() -> Vec<Route> {
routes![
index,
index_admin,
view,
resetpw,
update,
create,

View File

@ -26,26 +26,24 @@
role="alert">
<h2 class="h2">Mitglieds-Beitrags-Info</h2>
<div class="p-3 grid gap-3">
<a class="btn btn-primary" href="/admin/mail/fee/test">
Test-Mail an mich versenden
</a>
<a class="btn btn-alert" href="/admin/mail/fee"
onclick="return confirm('Hast du die Gebührenauflistung geprüft und willst du die Mail an alle ausschicken?');">
An ALLE Mitglieder versenden
</a>
<a class="btn btn-primary" href="/admin/mail/fee/test">Test-Mail an mich versenden</a>
<a class="btn btn-alert"
href="/admin/mail/fee"
onclick="return confirm('Hast du die Gebührenauflistung geprüft und willst du die Mail an alle ausschicken?');">
An ALLE Mitglieder versenden
</a>
</div>
</div>
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
<h2 class="h2">Unfreundliche Zahlungsaufforderung</h2>
<div class="p-3 grid gap-3">
<a class="btn btn-primary" href="/admin/mail/fee-final/test">
Test-Mail an mich versenden
</a>
<a class="btn btn-alert" href="/admin/mail/fee-final"
onclick="return confirm('Hast du die Gebührenauflistung geprüft, gecheckt ob alle die bereits bezahlt haben auch eingetragen wurden und willst du die Mail an alle, die noch nicht bezahlt haben ausschicken?');">
An ALLE Mitglieder versenden, die noch nicht bezahlt haben
</a>
<a class="btn btn-primary" href="/admin/mail/fee-final/test">Test-Mail an mich versenden</a>
<a class="btn btn-alert"
href="/admin/mail/fee-final"
onclick="return confirm('Hast du die Gebührenauflistung geprüft, gecheckt ob alle die bereits bezahlt haben auch eingetragen wurden und willst du die Mail an alle, die noch nicht bezahlt haben ausschicken?');">
An ALLE Mitglieder versenden, die noch nicht bezahlt haben
</a>
</div>
</div>
</div>

View File

@ -5,28 +5,29 @@
<h1 class="h1">Users</h1>
{% if allowed_to_edit %}
<details class="mt-5 bg-gray-200 dark:bg-primary-600 p-3 rounded-md">
<summary class="px-3 cursor-pointer text-md font-bold text-primary-950 dark:text-white">Neue Person hinzufügen</summary>
<summary class="px-3 cursor-pointer text-md font-bold text-primary-950 dark:text-white">
Neue Person hinzufügen
</summary>
<form action="/admin/user/new"
onsubmit="return confirm('Willst du wirklich einen neuen Benutzer anlegen?');"
method="post"
class="flex mt-4 rounded-md sm:flex items-end justify-between">
<div class="w-full">
<div>
<label for="name" class="sr-only">Name</label>
<input type="text"
name="name"
class="input rounded-md w-100"
placeholder="Name" />
onsubmit="return confirm('Willst du wirklich einen neuen Benutzer anlegen?');"
method="post"
class="flex mt-4 rounded-md sm:flex items-end justify-between">
<div class="w-full">
<div>
<label for="name" class="sr-only">Name</label>
<input type="text"
name="name"
class="input rounded-md w-100"
placeholder="Name" />
</div>
</div>
</div>
<div class="text-right ml-3">
<input value="Hinzufügen"
type="submit"
class="w-28 mt-2 sm:mt-0 rounded-md bg-primary-500 px-3 py-2 text-sm font-semibold text-white hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 cursor-pointer" />
</div>
</form>
<div class="text-right ml-3">
<input value="Hinzufügen"
type="submit"
class="w-28 mt-2 sm:mt-0 rounded-md bg-primary-500 px-3 py-2 text-sm font-semibold text-white hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 cursor-pointer" />
</div>
</form>
</details>
{% endif %}
<!-- START filterBar -->
<div class="search-wrapper flex">
@ -36,26 +37,29 @@
id="filter-js"
class="search-bar"
placeholder="Suchen nach (Name, [yes|no]-role:<name>, has-[no-]membership-pdf)" />
<div class="relative">
<button id="dropdownbtn" data-dropdown="dropdown" class="btn btn-dark ml-3" type="button">
Sortieren
</button>
<!-- Dropdown menu -->
<div id="dropdown" class="z-10 hidden bg-white divide-y divide-gray-100 text-secondary-900 rounded-lg shadow-sm w-44 absolute right-0">
<ul class="py-2 text-sm" aria-labelledby="dropdownbtn">
<li>
<a href="./user" class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Zuletzt eingeloggt</a>
</li>
<li>
<a href="?sort=name&asc" class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Name A-Z</a>
</li>
<li>
<a href="?sort=name" class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Name Z-A</a>
</li>
</ul>
</div>
<button id="dropdownbtn"
data-dropdown="dropdown"
class="btn btn-dark ml-3"
type="button">Sortieren</button>
<!-- Dropdown menu -->
<div id="dropdown"
class="z-10 hidden bg-white divide-y divide-gray-100 text-secondary-900 rounded-lg shadow-sm w-44 absolute right-0">
<ul class="py-2 text-sm" aria-labelledby="dropdownbtn">
<li>
<a href="./user"
class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Zuletzt eingeloggt</a>
</li>
<li>
<a href="?sort=name&asc"
class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Name A-Z</a>
</li>
<li>
<a href="?sort=name"
class="block px-4 py-2 hover:bg-gray-100 hover:text-secondary-950">Name Z-A</a>
</li>
</ul>
</div>
</div>
</div>
<!-- END filterBar -->
@ -90,6 +94,8 @@
</small>
</span>
</summary>
<a class="block my-1 font-normal text-[#f43f5e] dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
href="/admin/user/{{ user.id }}">✏️</a>
<form action="/admin/user"
method="post"
enctype="multipart/form-data"

View File

@ -0,0 +1,191 @@
{% import "includes/macros" as macros %}
{% extends "base" %}
{% block content %}
<div class="max-w-screen-lg w-full">
<h1 class="h1">{{ user.name }}</h1>
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
<h2 class="h2">Grunddaten</h2>
<div class="mx-2 divide-y divide-gray-200 dark:divide-primary-600">
<div class="py-3">
{% if user.last_access %}
Zuletzt eingeloggt am {{ user.last_access | date(format="%d. %m. %Y") }}
{% else %}
{{ user.name }} hat sich noch nie eingeloggt.
{% endif %}
</div>
<div class="py-3">
<ul>
<li>Mail: {{ user.mail }}</li>
<li>Notizen: {{ user.notes }}</li>
<li>Telefon: {{ user.phone }}</li>
<li>Spitzname: {{ user.nickname }}</li>
</ul>
</div>
<div class="py-3">
Rollen:
<ul class="list-disc ms-4">
{% for role in user.proper_roles -%}
{% if not role.cluster %}
<li>
<strong>{{ role.name }}:</strong> Hier folgt eine Beschreibung der Rolle
{% if allowed_to_edit %}
<a href="/admin/user/{{ user.id }}/remove-role/{{ role.id }}"
onclick="return confirm('Willst du die Rolle \'{{ role.name }}\' von {{ user.name }} wirklich entfernen?');">🗑️</a>
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>
{% if allowed_to_edit %}
<details>
<summary>+ Rolle</summary>
<form action="/admin/user/{{ user.id }}/add-role">
<fieldset>
<select id="role_id">
{% for role in roles %}
{% if not role.cluster %}<option value="{{ role.id }}">{{ role.name }}</option>{% endif %}
{% endfor %}
</select>
<input value="Rolle hinzufügen" type="submit" class="btn btn-primary ml-1" />
</fieldset>
</form>
</details>
{% endif %}
</div>
</div>
</div>
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
<h2 class="h2">Vereinsmitglied</h2>
<div class="mx-2 divide-y divide-gray-200 dark:divide-primary-600">
<div class="py-3">
<ul class="list-disc ms-4">
<li>Mitglied seit: {{ user.member_since_date }}</li>
<li>Geburtsdatum: {{ user.birthdate }}</li>
<li>Adresse: {{ user.address }}</li>
<li>
Familie: {{ macros::select(label="Familie", data=families, name='family_id', selected_id=user.family_id, display=['names'], default="Keine Familie", new_last_entry='Neue Familie anlegen') }}
</li>
</ul>
</div>
<div class="py-3">
{% if user.membership_pdf %}
<a href="/admin/user/{{ user.id }}/membership"
class="text-black dark:text-white">Beitrittserklärung</a>
{% else %}
⚠️ Aktuell gibt's keine Beitrittserklärung 😢
{% if allowed_to_edit %}
Das kannst du hier ändern ⤵️
<form action="/admin/user/{{ user.id }}/add-membership-pdf" method="post">
<fieldset>
{{ macros::input(label='Neue Beitrittserklärung hochladen', name='membership_pdf', type="file", accept='application/pdf') }}
<input value="Hochladen" type="submit" class="btn btn-primary ml-1" />
</fieldset>
</form>
{% endif %}
{% endif %}
</div>
{% if allowed_to_edit %}
<div class="py-3">
<div class="mt-3 text-right">
<a href="/admin/user/{{ user.id }}/delete"
class="btn btn-alert"
onclick="return confirm('Ist {{ user.name }} wirklich aus dem Verein ausgetreten?');">
{% include "includes/delete-icon" %}
Mitglied ist ausgetreten
</a>
</div>
</div>
{% endif %}
</div>
</div>
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
<h2 class="h2">Aktivität von und mit {{ user.name }}</h2>
<div class="mx-2 divide-y divide-gray-200 dark:divide-primary-600">
<div class="py-3">
<ul class="list-disc ms-4">
<li>Passwort zurückgesetzt am/um X</li>
<li>Am X beigetreten.</li>
</ul>
</div>
</div>
</div>
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
<h2 class="h2">TODO</h2>
<div class="border-t bg-white dark:bg-primary-900 py-3 px-4 relative">
<span class="text-black dark:text-white cursor-pointer">
<span class="font-bold">
{{ user.name }}
{% if not user.last_access and allowed_to_edit and user.mail %}
<form action="/admin/user"
method="post"
enctype="multipart/form-data"
class="inline">
&bullet; <a class="font-normal text-primary-600 dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
href="/admin/user/{{ user.id }}/send-welcome-mail"
onclick="return confirm('Willst du wirklich das Willkommensmail an {{ user.name }} ausschicken?');">Willkommensmail verschicken</a>
</form>
{% endif %}
</span>
</span>
<form action="/admin/user"
method="post"
enctype="multipart/form-data"
class="w-full mt-2">
{% if user.pw %}
<a class="block my-1 font-normal text-[#f43f5e] dark:text-primary-200 hover:text-primary-900 dark:hover:text-primary-300 underline"
href="/admin/user/{{ user.id }}/reset-pw"
onclick="return confirm('Willst du wirklich das Passwort zurücksetzen?');">Passwort zurücksetzen</a>
{% endif %}
<div class="w-full grid gap-3 mt-3">
<input type="hidden" name="id" value="{{ user.id }}" />
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
{% for cluster, cluster_roles in roles | group_by(attribute="cluster") %}
<label for="cluster_{{ loop.index }}">{{ cluster }}</label>
{# Determine the initially selected role within the cluster #}
{% set_global selected_role_id = "none" %}
{% for role in cluster_roles %}
{% if selected_role_id == "none" and role.name in user.roles %}
{% set_global selected_role_id = role.id %}
{% endif %}
{% endfor %}
{# Set default name to the selected role ID or first role if none selected #}
<select id="cluster_{{ loop.index }}"
{% if selected_role_id == 'none' %} {% else %} name="roles[{{ selected_role_id }}]" {% endif %}
{% if allowed_to_edit == false %}disabled{% endif %}
onchange=" if (this.value === '') { this.removeAttribute('name'); } else { this.name = 'roles[' + this.options[this.selectedIndex].getAttribute('data-role-id') + ']'; }">
<option value=""
data-role-id="none"
{% if selected_role_id == 'none' %}selected="selected"{% endif %}>
None
</option>
{% for role in cluster_roles %}
<option value="on"
data-role-id="{{ role.id }}"
{% if role.id == selected_role_id %}selected="selected"{% endif %}>
{{ role.name }}
</option>
{% endfor %}
</select>
{% endfor %}
</div>
</div>
</form>
</div>
</div>
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
<h2 class="h2">Ergo-Challenge</h2>
<div class="mx-2 divide-y divide-gray-200 dark:divide-primary-600">
<div class="py-3">
{{ macros::input(label='DOB', name='dob', type="text", value=user.dob, readonly=allowed_to_edit == false) }}
{{ macros::input(label='Weight (kg)', name='weight', type="text", value=user.weight, readonly=allowed_to_edit == false) }}
{{ macros::input(label='Sex', name='sex', type="text", value=user.sex, readonly=allowed_to_edit == false) }}
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -7,7 +7,7 @@
<summary>Dirty Thirty</summary>
<p>
<div class="border-r border-l">
<textarea style="width: 100%; height: 300px;">
<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 }}&#9;
{%- for name in names -%}
@ -23,7 +23,7 @@
<summary>Dirty Dozen</summary>
<p>
<div class="border-r border-l">
<textarea style="width: 100%; height: 300px;">
<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 }}&#9;
{%- for name in names -%}

View File

@ -21,8 +21,8 @@
</li>
<li class="py-1">
<a href="https://data.ergochallenge.at"
target="_blank"
style="text-decoration: underline">Offizielle Ergebnisse</a>, bei Fehlern direkt mit <a href="mailto:office@ergochallenge.at"
target="_blank"
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>
@ -75,8 +75,8 @@
<div class="pt-3">
<p>
Folgende Daten hat der Ruderassistent von dir. Wenn diese nicht mehr aktuell sind, bitte gewünschte Änderungen an unseren Schriftführer melden (<a href="mailto:info@rudernlinz.at"
class="text-primary-600 dark:text-primary-200 hover:text-primary-950 hover:dark:text-primary-300 underline"
target="_blank">it@rudernlinz.at</a>).
class="text-primary-600 dark:text-primary-200 hover:text-primary-950 hover:dark:text-primary-300 underline"
target="_blank">it@rudernlinz.at</a>).
<br />
<br />
<ul>

View File

@ -6,11 +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') }}
{% 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 %}
{% 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>

View File

@ -82,7 +82,13 @@
<label for="{{ id }}" class="text-sm text-gray-600 dark:text-gray-100">
Ruderer (inkl. Schiffsführer und Steuerperson)
</label>
<select style="width: 100%;" multiple name="rowers[]" id="{{ id }}" class="w-full" data-seats="{{ amount_seats }}" data-init={{ init }}>
<select style="width: 100%"
multiple
name="rowers[]"
id="{{ id }}"
class="w-full"
data-seats="{{ amount_seats }}"
data-init="{{ init }}">
{% for user in users %}
{% set_global sel = false %}
{% for rower in selected %}

View File

@ -203,7 +203,14 @@ 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 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 %}>
<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] -}}

View File

@ -32,7 +32,9 @@
<h2 class="h2">Nachrichten</h2>
{% if loggedin_user.amount_unread_notifications > 10 %}
<div class="text-primary-950 dark:text-white bg-gray-200 dark:bg-primary-950 bg-opacity-80 text-center pb-3 px-3">
Du hast viele ungelesene Benachrichtigungen. Um deine Oberfläche übersichtlich zu halten und wichtige Updates nicht zu verpassen, nimm dir bitte in Zukunft einen kurzen Moment Zeit sie zu überprüfen und als gelesen zu markieren (&#10003;).<br /><a href="/notification/read/all" class="underline">Du kannst hier ausnahmsweise alle als gelesen markieren.</a>
Du hast viele ungelesene Benachrichtigungen. Um deine Oberfläche übersichtlich zu halten und wichtige Updates nicht zu verpassen, nimm dir bitte in Zukunft einen kurzen Moment Zeit sie zu überprüfen und als gelesen zu markieren (&#10003;).
<br />
<a href="/notification/read/all" class="underline">Du kannst hier ausnahmsweise alle als gelesen markieren.</a>
</div>
{% endif %}
<div class="divide-y">
@ -234,93 +236,88 @@
role="alert">
<h2 class="h2">Vereinsmitglied</h2>
<ul class="list-none ms-2 divide-y divide-gray-200 dark:divide-primary-600">
{% if "Unterstützend" not in loggedin_user.roles and "Förderndes Mitglied" not in loggedin_user.roles %}
<li class="py-1">
<a href="/planned" class="block w-100 py-2 hover:text-primary-600">Geplante Ausfahrten</a>
</li>
<li class="py-1">
<a href="/log" class="block w-100 py-2 hover:text-primary-600">Ausfahrt eintragen</a>
</li>
<li class="py-1">
<a href="/log/show" class="block w-100 py-2 hover:text-primary-600">Logbuch</a>
</li>
<li class="py-1">
<a href="/stat" class="block w-100 py-2 hover:text-primary-600">Statistik</a>
</li>
<li class="py-1">
<a href="/stat/boats" class="block w-100 py-2 hover:text-primary-600">Bootsauswertung</a>
</li>
<li class="py-1">
<a href="/boatdamage" class="block w-100 py-2 hover:text-primary-600">Bootsschaden</a>
</li>
<li class="py-1">
<a href="/boatreservation"
class="block w-100 py-2 hover:text-primary-600">Bootsreservierung</a>
</li>
<li class="py-1">
<a href="/trailerreservation"
class="block w-100 py-2 hover:text-primary-600">Hängerreservierung</a>
</li>
<li class="py-1">
<a href="/steering" class="block w-100 py-2 hover:text-primary-600">Steuerleute & Co</a>
</li>
<div class="py-3">
<p>
<details>
<summary>
Kalender
</summary>
<p class="mt-3">
Du möchtest immer up-to-date mit den Events und Ausfahrten bleiben? Wir bieten 3 verschiedene Arten von Kalender an:
</p>
<ol class="list-decimal ml-5 my-3">
<li>
<strong>Alle Events und Ausfahrten</strong>, zu denen du dich angemeldet hast: <a class="underline break-all"
{% if "Unterstützend" not in loggedin_user.roles and "Förderndes Mitglied" not in loggedin_user.roles %}
<li class="py-1">
<a href="/planned" class="block w-100 py-2 hover:text-primary-600">Geplante Ausfahrten</a>
</li>
<li class="py-1">
<a href="/log" class="block w-100 py-2 hover:text-primary-600">Ausfahrt eintragen</a>
</li>
<li class="py-1">
<a href="/log/show" class="block w-100 py-2 hover:text-primary-600">Logbuch</a>
</li>
<li class="py-1">
<a href="/stat" class="block w-100 py-2 hover:text-primary-600">Statistik</a>
</li>
<li class="py-1">
<a href="/stat/boats" class="block w-100 py-2 hover:text-primary-600">Bootsauswertung</a>
</li>
<li class="py-1">
<a href="/boatdamage" class="block w-100 py-2 hover:text-primary-600">Bootsschaden</a>
</li>
<li class="py-1">
<a href="/boatreservation"
class="block w-100 py-2 hover:text-primary-600">Bootsreservierung</a>
</li>
<li class="py-1">
<a href="/trailerreservation"
class="block w-100 py-2 hover:text-primary-600">Hängerreservierung</a>
</li>
<li class="py-1">
<a href="/steering" class="block w-100 py-2 hover:text-primary-600">Steuerleute & Co</a>
</li>
<div class="py-3">
<p>
<details>
<summary>Kalender</summary>
<p class="mt-3">
Du möchtest immer up-to-date mit den Events und Ausfahrten bleiben? Wir bieten 3 verschiedene Arten von Kalender an:
</p>
<ol class="list-decimal ml-5 my-3">
<li>
<strong>Alle Events und Ausfahrten</strong>, zu denen du dich angemeldet hast: <a class="underline break-all"
href="https://app.rudernlinz.at/cal/personal/{{ loggedin_user.id }}/{{ loggedin_user.user_token }}">https://app.rudernlinz.at/cal/personal/{{ loggedin_user.id }}/{{ loggedin_user.user_token }}</a>
<br />
<small>Dieser Link enthält einen zufällig generierten Teil, damit nur du (und jene, denen du diesen Link weitergibst) Zugang zu diesen Daten hast.</small>
</li>
<li>
<strong>Allgemeiner Kalender</strong>, zB save-the-dates (Wanderfahrten, ...): <a href="https://rudernlinz.at/cal" class="break-all underline">https://rudernlinz.at/cal</a>
</li>
<li>
<strong>Alle Events</strong>: <a class="break-all underline" href="https://app.rudernlinz.at/cal">https://app.rudernlinz.at/cal</a>
<br />
<small>Beachte, dass dieser Kalender keine Ausfahrten enthält, die von einzelnen Steuerpersonen augeschrieben werden. Dieser Kalender wird zB auf <a href="https://rudernlinz.at/termine" class="underline">https://rudernlinz.at/termine</a> verwendet und wir möchten keine persönlichen Daten (Namen etc.) leaken.</small>
</li>
</ol>
Du kannst die Kalender einfach in deinen Kalender als "externen Kalender" synchronisieren. Die genauen Schritte hängen von deiner verwendeten Software ab.
</details>
</p>
</div>
<br />
<small>Dieser Link enthält einen zufällig generierten Teil, damit nur du (und jene, denen du diesen Link weitergibst) Zugang zu diesen Daten hast.</small>
</li>
<li>
<strong>Allgemeiner Kalender</strong>, zB save-the-dates (Wanderfahrten, ...): <a href="https://rudernlinz.at/cal" class="break-all underline">https://rudernlinz.at/cal</a>
</li>
<li>
<strong>Alle Events</strong>: <a class="break-all underline" href="https://app.rudernlinz.at/cal">https://app.rudernlinz.at/cal</a>
<br />
<small>Beachte, dass dieser Kalender keine Ausfahrten enthält, die von einzelnen Steuerpersonen augeschrieben werden. Dieser Kalender wird zB auf <a href="https://rudernlinz.at/termine" class="underline">https://rudernlinz.at/termine</a> verwendet und wir möchten keine persönlichen Daten (Namen etc.) leaken.</small>
</li>
</ol>
Du kannst die Kalender einfach in deinen Kalender als "externen Kalender" synchronisieren. Die genauen Schritte hängen von deiner verwendeten Software ab.
</details>
</p>
</div>
<div class="py-3">
<p>
<details>
<summary>Signal-Gruppenchat Donau Linz</summary>
<p class="mt-3">
Mit diesem Link kannst du unserer Signal Gruppe beitreten: <a class="break-all underline"
href="https://signal.group/#CjQKICFrq6zSsRHxrucS3jEcQn6lknEXacAykwwLV3vNLKxPEhA17jxz7cpjfu3JZokLq1TH">https://signal.group/#CjQKICFrq6zSsRHxrucS3jEcQn6lknEXacAykwwLV3vNLKxPEhA17jxz7cpjfu3JZokLq1TH</a>
</p>
</details>
</p>
</div>
{% endif %}
<div class="py-3">
<p>
<details>
<summary>
Signal-Gruppenchat Donau Linz
</summary>
<summary>WLAN-Passwort</summary>
<p class="mt-3">
Mit diesem Link kannst du unserer Signal Gruppe beitreten: <a class="break-all underline" href="https://signal.group/#CjQKICFrq6zSsRHxrucS3jEcQn6lknEXacAykwwLV3vNLKxPEhA17jxz7cpjfu3JZokLq1TH">https://signal.group/#CjQKICFrq6zSsRHxrucS3jEcQn6lknEXacAykwwLV3vNLKxPEhA17jxz7cpjfu3JZokLq1TH</a>
</p>
</details>
</p>
</div>
{% endif %}
<div class="py-3">
<p>
<details>
<summary>
WLAN-Passwort
</summary>
<p class="mt-3">
Das Passwort für unser "ASKÖ Ruderverein Donau Linz" WLAN ist <q>donau1921</q> (ohne Anführungszeichen). Bitte an keine vereinsfremden Personen weitergeben.
Das Passwort für unser "ASKÖ Ruderverein Donau Linz" WLAN ist <q>donau1921</q> (ohne Anführungszeichen). Bitte an keine vereinsfremden Personen weitergeben.
</p>
</details>
</p>
</div>
</ul>
</div>
{% endif %}
{% endif %}
{% if "cox" in loggedin_user.roles or "Bootsführer" in loggedin_user.roles %}
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
role="alert">
@ -329,11 +326,10 @@
<div class="py-3">
<p>
<details>
<summary>
Signal-Gruppenchat Steuerpersonen Donau Linz
</summary>
<summary>Signal-Gruppenchat Steuerpersonen Donau Linz</summary>
<p class="mt-3">
Mit diesem Link kannst du unserer Signal Gruppe beitreten: <a class="break-all underline" href="https://signal.group/#CjQKIHJInNb3zSVW7ipLo7_ygIqVxhxUaaNYx4sy2jdklLsIEhBHJNM2KZM1UnBdQxWy_Gdp">https://signal.group/#CjQKIHJInNb3zSVW7ipLo7_ygIqVxhxUaaNYx4sy2jdklLsIEhBHJNM2KZM1UnBdQxWy_Gdp</a>
Mit diesem Link kannst du unserer Signal Gruppe beitreten: <a class="break-all underline"
href="https://signal.group/#CjQKIHJInNb3zSVW7ipLo7_ygIqVxhxUaaNYx4sy2jdklLsIEhBHJNM2KZM1UnBdQxWy_Gdp">https://signal.group/#CjQKIHJInNb3zSVW7ipLo7_ygIqVxhxUaaNYx4sy2jdklLsIEhBHJNM2KZM1UnBdQxWy_Gdp</a>
</p>
</details>
</p>

View File

@ -67,7 +67,7 @@
{% endif %}
{% endfor %}
{% endif %}
<div id="{{ day.day| date(format="%Y-%m-%d") }}"
<div id="{{ day.day| date(format='%Y-%m-%d') }}"
class="bg-white dark:bg-primary-900 rounded-md flex justify-between flex-col shadow reset-js"
style="min-height: 10rem"
data-trips="{{ amount_trips }}"
@ -93,20 +93,22 @@
<div class="grid grid-cols-1 gap-3 mb-3">
{# --- START Boatreservations--- #}
{% for _, reservations_for_event in day.boat_reservations %}
{% set reservation = reservations_for_event[0] %}
{% set reservation = reservations_for_event[0] %}
<div class="pt-2 px-3 border-gray-200">
<div class="flex justify-between items-center">
<div class="mr-1">
<span class="text-primary-900 dark:text-white">
⏳ {{ reservation.time_desc }} <small class="text-gray-600 dark:text-gray-100">({{ reservation.user_applicant.name }})</small><br/>
⏳ {{ reservation.time_desc }} <small class="text-gray-600 dark:text-gray-100">({{ reservation.user_applicant.name }})</small>
<br />
<strong>
{% for reservation in reservations_for_event -%}
{{ reservation.boat.name }}
{%- if not loop.last %} + {% endif -%}
{% endfor -%}
{% for reservation in reservations_for_event -%}
{{ reservation.boat.name }}
{%- if not loop.last %} +
{% endif -%}
{% endfor -%}
</strong>
</span>
<small class="text-gray-600 dark:text-gray-100">(Reservierung - {{ reservation.usage}})</small>
<small class="text-gray-600 dark:text-gray-100">(Reservierung - {{ reservation.usage }})</small>
</div>
</div>
</div>
@ -241,9 +243,9 @@
<input type="hidden" name="id" value="{{ event.id }}" />
{{ macros::input(label='Titel', name='name', type='input', value=event.name) }}
{% if event.cancelled %}
<input type="hidden" name="max_people" value="-1" />
<input type="hidden" name="max_people" value="-1" />
{% else %}
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=event.max_people, min='0') }}
{{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=event.max_people, min='0') }}
{% endif %}
{{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', value=event.planned_amount_cox, required=true, min='0') }}
{{ macros::checkbox(label='Immer anzeigen', name='always_show', id=event.id,checked=event.always_show) }}
@ -378,11 +380,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) }}
{% 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 %}
{% 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>
@ -472,9 +474,11 @@
{% endif %}
">
<span class="absolute inset-y-0 left-0 flex items-center pl-3">{% include "includes/plus-icon" %}</span>
{% if not loggedin_user.allowed_to_steer %}Ergo-Session
{%- else -%}
Ausfahrt{%endif%}
{% if not loggedin_user.allowed_to_steer %}
Ergo-Session
{%- else -%}
Ausfahrt
{% endif %}
</a>
{% endif %}
</div>
@ -484,7 +488,7 @@
{% endfor %}
</div>
</div>
{% if loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles %}
{% if loggedin_user.allowed_to_steer or "ergo" in loggedin_user.roles %}
{% include "forms/trip" %}
{% endif %}
{% if "manage_events" in loggedin_user.roles %}