aequatorpreis #729
@ -25,6 +25,7 @@ pub mod logbook;
|
|||||||
pub mod logtype;
|
pub mod logtype;
|
||||||
pub mod mail;
|
pub mod mail;
|
||||||
pub mod notification;
|
pub mod notification;
|
||||||
|
pub mod personal;
|
||||||
pub mod role;
|
pub mod role;
|
||||||
pub mod rower;
|
pub mod rower;
|
||||||
pub mod stat;
|
pub mod stat;
|
||||||
|
58
src/model/personal/equatorprice.rs
Normal file
58
src/model/personal/equatorprice.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
enum Level {
|
||||||
|
BRONZE,
|
||||||
|
SILVER,
|
||||||
|
GOLD,
|
||||||
|
DIAMOND,
|
||||||
|
DONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Level {
|
||||||
|
fn required_km(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Level::BRONZE => 40000,
|
||||||
|
Level::SILVER => 80000,
|
||||||
|
Level::GOLD => 100000,
|
||||||
|
Level::DIAMOND => 200000,
|
||||||
|
Level::DONE => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_level(km: i32) -> Self {
|
||||||
|
if km < Level::BRONZE.required_km() {
|
||||||
|
Level::BRONZE
|
||||||
|
} else if km < Level::SILVER.required_km() {
|
||||||
|
Level::SILVER
|
||||||
|
} else if km < Level::GOLD.required_km() {
|
||||||
|
Level::GOLD
|
||||||
|
} else if km < Level::DIAMOND.required_km() {
|
||||||
|
Level::BRONZE
|
||||||
|
} else {
|
||||||
|
Level::DONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub(crate) struct Next {
|
||||||
|
level: Level,
|
||||||
|
missing_km: i32,
|
||||||
|
required_km: i32,
|
||||||
|
rowed_km: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Next {
|
||||||
|
pub(crate) fn rowed_km(km: i32) -> Self {
|
||||||
|
let level = Level::next_level(km);
|
||||||
|
let required_km = level.required_km();
|
||||||
|
let missing_km = required_km - km;
|
||||||
|
Self {
|
||||||
|
level,
|
||||||
|
missing_km,
|
||||||
|
required_km,
|
||||||
|
rowed_km: km,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/model/personal/mod.rs
Normal file
21
src/model/personal/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
|
use super::{stat::Stat, user::User};
|
||||||
|
|
||||||
|
pub(crate) mod equatorprice;
|
||||||
|
pub(crate) mod rowingbadge;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub(crate) struct Achievements {
|
||||||
|
equatorprice: equatorprice::Next,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Achievements {
|
||||||
|
pub(crate) async fn for_user(db: &SqlitePool, user: &User) -> Self {
|
||||||
|
let rowed_km = Stat::person(db, None, user).await.rowed_km;
|
||||||
|
Self {
|
||||||
|
equatorprice: equatorprice::Next::rowed_km(rowed_km),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
src/model/personal/rowingbadge.rs
Normal file
62
src/model/personal/rowingbadge.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use chrono::{Datelike, Local, NaiveDate};
|
||||||
|
|
||||||
|
use crate::model::user::User;
|
||||||
|
|
||||||
|
enum AgeBracket {
|
||||||
|
Till14,
|
||||||
|
From14Till18,
|
||||||
|
From19Till30,
|
||||||
|
From31Till60,
|
||||||
|
From61Till75,
|
||||||
|
From76,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&User> for AgeBracket {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: &User) -> Result<Self, Self::Error> {
|
||||||
|
if let Some(birthdate) = value.birthdate.clone() {
|
||||||
|
let today = Local::now().date_naive();
|
||||||
|
let birthdate = NaiveDate::parse_from_str(&birthdate, "%Y-%m-%d").unwrap();
|
||||||
|
|
||||||
|
let age = today.year() - birthdate.year();
|
||||||
|
if age <= 14 {
|
||||||
|
Ok(AgeBracket::Till14)
|
||||||
|
} else if age <= 18 {
|
||||||
|
Ok(AgeBracket::From14Till18)
|
||||||
|
} else if age <= 30 {
|
||||||
|
Ok(AgeBracket::From19Till30)
|
||||||
|
} else if age <= 60 {
|
||||||
|
Ok(AgeBracket::From31Till60)
|
||||||
|
} else if age <= 75 {
|
||||||
|
Ok(AgeBracket::From61Till75)
|
||||||
|
} else {
|
||||||
|
Ok(AgeBracket::From76)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("User has no birthdate".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cat(value: &AgeBracket) -> &str {
|
||||||
|
match value {
|
||||||
|
AgeBracket::Till14 => "Schülerinnen und Schüler bis 14 Jahre",
|
||||||
|
AgeBracket::From14Till18 => "Juniorinnen und Junioren, Para-Ruderer bis 18 Jahre",
|
||||||
|
AgeBracket::From19Till30 => "Frauen und Männer, Para-Ruderer bis 30 Jahre",
|
||||||
|
AgeBracket::From31Till60 => "Frauen und Männer, Para-Ruderer von 31 bis 60 Jahre",
|
||||||
|
AgeBracket::From61Till75 => "Frauen und Männer, Para-Ruderer von 61 bis 75 Jahre",
|
||||||
|
AgeBracket::From76 => "Frauen und Männer, Para-Ruderer ab 76 Jahre",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dist_in_km(value: &AgeBracket) -> u32 {
|
||||||
|
match value {
|
||||||
|
AgeBracket::Till14 => 500,
|
||||||
|
AgeBracket::From14Till18 => 1000,
|
||||||
|
AgeBracket::From19Till30 => 1200,
|
||||||
|
AgeBracket::From31Till60 => 1000,
|
||||||
|
AgeBracket::From61Till75 => 800,
|
||||||
|
AgeBracket::From76 => 600,
|
||||||
|
}
|
||||||
|
}
|
@ -24,71 +24,6 @@ use crate::{
|
|||||||
SCHECKBUCH, STUDENT_OR_PUPIL, UNTERSTUETZEND,
|
SCHECKBUCH, STUDENT_OR_PUPIL, UNTERSTUETZEND,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod aequatorpreis {
|
|
||||||
use chrono::{Datelike, Local, NaiveDate};
|
|
||||||
|
|
||||||
use super::User;
|
|
||||||
|
|
||||||
enum AgeBracket {
|
|
||||||
Till14,
|
|
||||||
From14Till18,
|
|
||||||
From19Till30,
|
|
||||||
From31Till60,
|
|
||||||
From61Till75,
|
|
||||||
From76,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&User> for AgeBracket {
|
|
||||||
type Error = String;
|
|
||||||
|
|
||||||
fn try_from(value: &User) -> Result<Self, Self::Error> {
|
|
||||||
if let Some(birthdate) = value.birthdate.clone() {
|
|
||||||
let today = Local::now().date_naive();
|
|
||||||
let birthdate = NaiveDate::parse_from_str(&birthdate, "%Y-%m-%d").unwrap();
|
|
||||||
|
|
||||||
let age = today.year() - birthdate.year();
|
|
||||||
if age <= 14 {
|
|
||||||
Ok(AgeBracket::Till14)
|
|
||||||
} else if age <= 18 {
|
|
||||||
Ok(AgeBracket::From14Till18)
|
|
||||||
} else if age <= 30 {
|
|
||||||
Ok(AgeBracket::From19Till30)
|
|
||||||
} else if age <= 60 {
|
|
||||||
Ok(AgeBracket::From31Till60)
|
|
||||||
} else if age <= 75 {
|
|
||||||
Ok(AgeBracket::From61Till75)
|
|
||||||
} else {
|
|
||||||
Ok(AgeBracket::From76)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err("User has no birthdate".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cat(value: &AgeBracket) -> &str {
|
|
||||||
match value {
|
|
||||||
AgeBracket::Till14 => "Schülerinnen und Schüler bis 14 Jahre",
|
|
||||||
AgeBracket::From14Till18 => "Juniorinnen und Junioren, Para-Ruderer bis 18 Jahre",
|
|
||||||
AgeBracket::From19Till30 => "Frauen und Männer, Para-Ruderer bis 30 Jahre",
|
|
||||||
AgeBracket::From31Till60 => "Frauen und Männer, Para-Ruderer von 31 bis 60 Jahre",
|
|
||||||
AgeBracket::From61Till75 => "Frauen und Männer, Para-Ruderer von 61 bis 75 Jahre",
|
|
||||||
AgeBracket::From76 => "Frauen und Männer, Para-Ruderer ab 76 Jahre",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dist_in_km(value: &AgeBracket) -> u32 {
|
|
||||||
match value {
|
|
||||||
AgeBracket::Till14 => 500,
|
|
||||||
AgeBracket::From14Till18 => 1000,
|
|
||||||
AgeBracket::From19Till30 => 1200,
|
|
||||||
AgeBracket::From31Till60 => 1000,
|
|
||||||
AgeBracket::From61Till75 => 800,
|
|
||||||
AgeBracket::From76 => 600,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromRow, Serialize, Deserialize, Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(FromRow, Serialize, Deserialize, Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
|
@ -24,6 +24,7 @@ use crate::{
|
|||||||
model::{
|
model::{
|
||||||
logbook::Logbook,
|
logbook::Logbook,
|
||||||
notification::Notification,
|
notification::Notification,
|
||||||
|
personal::Achievements,
|
||||||
role::Role,
|
role::Role,
|
||||||
user::{User, UserWithDetails},
|
user::{User, UserWithDetails},
|
||||||
},
|
},
|
||||||
@ -62,6 +63,7 @@ async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_
|
|||||||
context.insert("last_trips", &last_trips);
|
context.insert("last_trips", &last_trips);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.insert("achievements", &Achievements::for_user(db, &user).await);
|
||||||
context.insert("notifications", &Notification::for_user(db, &user).await);
|
context.insert("notifications", &Notification::for_user(db, &user).await);
|
||||||
context.insert("loggedin_user", &UserWithDetails::from_user(user, db).await);
|
context.insert("loggedin_user", &UserWithDetails::from_user(user, db).await);
|
||||||
context.insert("costs_scheckbuch", &SCHECKBUCH);
|
context.insert("costs_scheckbuch", &SCHECKBUCH);
|
||||||
|
@ -74,6 +74,32 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if "Donau Linz" in loggedin_user.roles and "Unterstützend" not in loggedin_user.roles and "Förderndes Mitglied" not in loggedin_user.roles %}
|
{% if "Donau Linz" in loggedin_user.roles and "Unterstützend" not in loggedin_user.roles and "Förderndes Mitglied" not 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">
|
||||||
|
<h2 class="h2">Persönliches</h2>
|
||||||
|
<div class="mx-2 divide-y divide-gray-200 dark:divide-primary-600">
|
||||||
|
<div class="py-3">
|
||||||
|
<h3 class="font-bold text-xl mb-3">Äquatorpreis</h3>
|
||||||
|
{% set price = achievements.equatorprice %}
|
||||||
|
{% if price.level == "DONE" %}
|
||||||
|
Gratuliere, du hast alles erreicht, was es beim Äquatorpreis zu erreichen gibt.
|
||||||
|
{% else %}
|
||||||
|
<label for="equatorprice" class="label">{{ price.level }}</label>
|
||||||
|
<progress id="equatorprice"
|
||||||
|
class="w-full block my-3"
|
||||||
|
value="{{ price.rowed_km }}"
|
||||||
|
max="{{ price.required_km }}"></progress>
|
||||||
|
<details>
|
||||||
|
<summary>Details</summary>
|
||||||
|
Du bist insgesamt {{ price.rowed_km }} km gerudert. Um den Äquatorpreis in {{ price.level }} zu erhalten, benötigst du noch {{ price.missing_km }} um die notwendigen {{ price.required_km }} km zu erreichen.
|
||||||
|
</details>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="py-1">
|
||||||
|
<h3>Fahrtenabzeichen</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
|
<div class="bg-white dark:bg-primary-900 text-black dark:text-white rounded-md block shadow mt-5"
|
||||||
role="alert">
|
role="alert">
|
||||||
<h2 class="h2">Aktives Vereinsmitglied</h2>
|
<h2 class="h2">Aktives Vereinsmitglied</h2>
|
||||||
|
Loading…
Reference in New Issue
Block a user