confirm-user-creation #840

Merged
philipp merged 14 commits from confirm-user-creation into staging 2025-01-09 10:22:57 +01:00
5 changed files with 83 additions and 58 deletions

View File

@ -298,7 +298,7 @@ Dein Vereinsbeitrag für das aktuelle Jahr beträgt {}€",
}
if is_family {
content.push_str(&format!(
"Dieser gilt für die gesamte Familie ({}).\n",
"Dieser gilt für die gesamte Familie ({}). Diese Mail wird an alle Familienmitglieder verschickt, bezahlen müsst ihr natürlich nur 1x.\n",
fees.name
))
}

View File

@ -98,6 +98,7 @@ ORDER BY
#[derive(FromRow, Serialize, Clone)]
pub struct Stat {
name: String,
pub(crate) amount_trips: i32,
pub(crate) rowed_km: i32,
}
@ -108,9 +109,11 @@ impl Stat {
None => chrono::Local::now().year(),
};
//TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server)
let rowed_km = sqlx::query(&format!(
// proper guests
let guests = sqlx::query(&format!(
"
SELECT SUM((b.amount_seats - COALESCE(m.member_count, 0)) * l.distance_in_km) as total_guest_km
SELECT SUM((b.amount_seats - COALESCE(m.member_count, 0)) * l.distance_in_km) as total_guest_km,
SUM(b.amount_seats - COALESCE(m.member_count, 0)) AS amount_trips
FROM logbook l
JOIN boat b ON l.boat_id = b.id
LEFT JOIN (
@ -123,12 +126,15 @@ WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%' AND not b.exter
))
.fetch_one(db)
.await
.unwrap()
.get::<i64, usize>(0) as i32;
.unwrap();
let rowed_km_guests = sqlx::query(&format!(
let guest_km: i32 = guests.get(0);
let guest_amount_trips: i32 = guests.get(1);
// e.g. scheckbücher
let guest_user = sqlx::query(&format!(
"
SELECT CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km
SELECT CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km, COUNT(*) AS amount_trips
FROM user u
INNER JOIN rower r ON u.id = r.rower_id
INNER JOIN logbook l ON r.logbook_id = l.id
@ -145,15 +151,27 @@ AND u.name != 'Externe Steuerperson';
))
.fetch_one(db)
.await
.unwrap()
.get::<i64, usize>(0) as i32;
.unwrap();
let guest_user_km: i32 = guest_user.get(0);
let guest_user_amount_trips: i32 = guest_user.get(1);
Stat {
name: "Gäste".into(),
rowed_km: rowed_km + rowed_km_guests,
amount_trips: guest_amount_trips + guest_user_amount_trips,
rowed_km: guest_km + guest_user_km,
}
}
pub async fn trips_people(db: &SqlitePool, year: Option<i32>) -> i32 {
let stats = Self::people(db, year).await;
let mut sum = 0;
for stat in stats {
sum += stat.amount_trips;
}
sum
}
pub async fn sum_people(db: &SqlitePool, year: Option<i32>) -> i32 {
let stats = Self::people(db, year).await;
let mut sum = 0;
@ -172,7 +190,7 @@ AND u.name != 'Externe Steuerperson';
//TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server)
sqlx::query(&format!(
"
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km, COUNT(*) AS amount_trips
FROM (
SELECT * FROM user
WHERE id IN (
@ -194,6 +212,7 @@ ORDER BY rowed_km DESC, u.name;
.into_iter()
.map(|row| Stat {
name: row.get("name"),
amount_trips: row.get("amount_trips"),
rowed_km: row.get("rowed_km"),
})
.collect()
@ -203,7 +222,7 @@ ORDER BY rowed_km DESC, u.name;
//TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server)
let row = sqlx::query(&format!(
"
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km, COUNT(*) AS amount_trips
FROM (
SELECT * FROM user
WHERE id={}
@ -220,6 +239,7 @@ WHERE l.distance_in_km IS NOT NULL;
Stat {
name: row.get("name"),
amount_trips: row.get("amount_trips"),
rowed_km: row.get("rowed_km"),
}
}
@ -232,7 +252,7 @@ WHERE l.distance_in_km IS NOT NULL;
//TODO: switch to query! macro again (once upgraded to sqlite 3.42 on server)
let row = sqlx::query(&format!(
"
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km
SELECT u.name, CAST(SUM(l.distance_in_km) AS INTEGER) AS rowed_km, COUNT(*) AS amount_trips
FROM (
SELECT * FROM user
WHERE id={}
@ -249,6 +269,7 @@ WHERE l.distance_in_km IS NOT NULL AND l.arrival LIKE '{year}-%';
Stat {
name: row.get("name"),
amount_trips: row.get("amount_trips"),
rowed_km: row.get("rowed_km"),
}
}

View File

@ -32,13 +32,14 @@ async fn index_boat_kiosk(db: &State<SqlitePool>, _kiosk: KioskCookie) -> Templa
async fn index(db: &State<SqlitePool>, user: DonauLinzUser, year: Option<i32>) -> Template {
let stat = Stat::people(db, year).await;
let club_km = Stat::sum_people(db, year).await;
let club_trips = Stat::trips_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: &UserWithDetails::from_user(user.into_inner(), db).await, stat, personal, kiosk, guest_km, club_km),
context!(loggedin_user: &UserWithDetails::from_user(user.into_inner(), db).await, stat, personal, kiosk, guest_km, club_km, club_trips),
)
}

View File

@ -5,6 +5,7 @@
<h1 class="h1">Users</h1>
{% if allowed_to_edit %}
<form action="/admin/user/new"
onsubmit="return confirm('Willst du wirklich einen neuen Benutzer anlegen?');"
method="post"
class="mt-4 bg-primary-900 rounded-md text-white px-3 pb-3 pt-2 sm:flex items-end justify-between">
<div class="w-full">

View File

@ -20,7 +20,15 @@
</div>
<div id="filter-result-js" class="search-result"></div>
<div class="border-r border-l border-gray-200 dark:border-primary-600">
{% set_global km = 0 %} {% set_global index = 1 %}
<div class="border-t border-gray-200 dark:border-primary-600 bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1"
data-filterable="false"
data-filter="Header">
<span class="text-sm text-gray-600 dark:text-gray-100 w-10"><b>#</b></span>
<span class="grow"><b>Name</b></span>
<span class="pl-3 w-20 text-right"><b>km</b></span>
<span class="pl-3 w-20 text-right"><b>Fahrten</b></span>
</div>
{% set_global km = 0 %} {% set_global km = 0 %} {% set_global index = 1 %}
{% for s in stat %}
<div class="border-t border-gray-200 dark:border-primary-600 bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1"
data-filterable="true"
@ -34,68 +42,62 @@
{% endif %}
</span>
<span class="grow">{{ s.name }}</span>
<span>{{ s.rowed_km }} km</span>
<span class="pl-3 w-20 text-right">{{ s.rowed_km }}</span>
<span class="pl-3 w-20 text-right">{{ s.amount_trips }}</span>
{% set_global km = s.rowed_km %}
</div>
{% endfor %}
<div class="border-t border-gray-200 dark:border-primary-600 bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1"
data-filterable="true"
<div class="border-t border-black dark:border-white bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1"
data-filterable="false"
data-filter="Summe Vereinsmitglieder">
<span class="text-sm text-gray-600 dark:text-gray-100 w-10"></span>
<span class="grow"><b>Summe Vereinsmitglieder</b></span>
<span><b>{{ club_km }} km</b></span>
<span class="pl-3 w-20 text-right"><b>{{ club_km }}</b></span>
<span class="pl-3 w-20 text-right"><b>{{ club_trips }}</b></span>
</div>
<div class="border-t border-gray-200 dark:border-primary-600 bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1"
data-filterable="true"
data-filterable="false"
data-filter="Summe {{ guest_km.name }}">
<span class="text-sm text-gray-600 dark:text-gray-100 w-10"></span>
<span class="grow"><b>Summe {{ guest_km.name }}</b></span>
<span><b>{{ guest_km.rowed_km }} km</b></span>
<span class="pl-3 w-20 text-right"><b>{{ guest_km.rowed_km }}</b></span>
<span class="pl-3 w-20 text-right"><b>{{ guest_km.amount_trips }}</b></span>
</div>
<div class="border-t border-gray-200 dark:border-primary-600 border-b bg-white dark:bg-primary-900 text-black dark:text-white flex justify-between items-center px-3 py-1"
data-filterable="true"
data-filterable="false"
data-filter="Gesamtsumme">
<span class="text-sm text-gray-600 dark:text-gray-100 w-10"></span>
<span class="grow"><b>Gesamtsumme</b></span>
<span><b>{{ club_km + guest_km.rowed_km }} km</b></span>
<span class="pl-3 w-20 text-right"><b>{{ club_km + guest_km.rowed_km }}</b></span>
<span class="pl-3 w-20 text-right"><b>{{ guest_km.amount_trips + club_trips }}</b></span>
</div>
</div>
<div id="container" class="w-full"></div>
</div>
<script>
{% if personal %}
const data = [
{%- for p in personal %}{ date: '{{p.date}}', km: {{p.km}} },{%- endfor %}
]
sessionStorage.setItem('userStats', JSON.stringify(data));
{% endif %}
function getYearFromURL() {
var queryParams = new URLSearchParams(window.location.search);
return queryParams.get('year');
}
function getYearFromURL() {
var queryParams = new URLSearchParams(window.location.search);
return queryParams.get('year');
}
function populateYears() {
var select = document.getElementById('yearSelect');
var currentYear = new Date().getFullYear();
var selectedYear = getYearFromURL() || currentYear;
for (var year = 1977; year <= currentYear; year++) {
var option = document.createElement('option');
option.value = option.textContent = year;
if (year == selectedYear) {
option.selected = true;
}
select.appendChild(option);
}
}
function populateYears() {
var select = document.getElementById('yearSelect');
var currentYear = new Date().getFullYear();
var selectedYear = getYearFromURL() || currentYear;
for (var year = 1977; year <= currentYear; year++) {
var option = document.createElement('option');
option.value = option.textContent = year;
if (year == selectedYear) {
option.selected = true;
}
select.appendChild(option);
}
}
function changeYear() {
var selectedYear = document.getElementById('yearSelect').value;
window.location.href = '?year=' + selectedYear;
}
function changeYear() {
var selectedYear = document.getElementById('yearSelect').value;
window.location.href = '?year=' + selectedYear;
}
// Call this function when the page loads
populateYears();
populateYears();
</script>
<script src="/public/logbook.js"></script>
{% endblock content %}