upd #721
12
src/lib.rs
12
src/lib.rs
@ -10,6 +10,18 @@ pub mod rest;
|
|||||||
|
|
||||||
pub mod scheduled;
|
pub mod scheduled;
|
||||||
|
|
||||||
|
pub(crate) const AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD: i64 = 10;
|
||||||
|
pub(crate) const RENNRUDERBEITRAG: i32 = 11000;
|
||||||
|
pub(crate) const BOAT_STORAGE: i32 = 4500;
|
||||||
|
pub(crate) const FAMILY_TWO: i32 = 30000;
|
||||||
|
pub(crate) const FAMILY_THREE_OR_MORE: i32 = 35000;
|
||||||
|
pub(crate) const STUDENT_OR_PUPIL: i32 = 8000;
|
||||||
|
pub(crate) const REGULAR: i32 = 22000;
|
||||||
|
pub(crate) const UNTERSTUETZEND: i32 = 2500;
|
||||||
|
pub(crate) const FOERDERND: i32 = 8500;
|
||||||
|
pub(crate) const SCHECKBUCH: i32 = 3000;
|
||||||
|
pub(crate) const EINSCHREIBGEBUEHR: i32 = 3000;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! testdb {
|
macro_rules! testdb {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use chrono::NaiveDate;
|
use chrono::{Local, NaiveDate};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use waterlevel::WaterlevelDay;
|
use waterlevel::WaterlevelDay;
|
||||||
|
|
||||||
|
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
event::{Event, EventWithUserAndTriptype},
|
event::{Event, EventWithUserAndTriptype},
|
||||||
trip::{Trip, TripWithUserAndType},
|
trip::{Trip, TripWithUserAndType},
|
||||||
@ -42,18 +44,23 @@ pub struct Day {
|
|||||||
events: Vec<EventWithUserAndTriptype>,
|
events: Vec<EventWithUserAndTriptype>,
|
||||||
trips: Vec<TripWithUserAndType>,
|
trips: Vec<TripWithUserAndType>,
|
||||||
is_pinned: bool,
|
is_pinned: bool,
|
||||||
|
regular_sees_this_day: bool,
|
||||||
max_waterlevel: Option<WaterlevelDay>,
|
max_waterlevel: Option<WaterlevelDay>,
|
||||||
weather: Option<Weather>,
|
weather: Option<Weather>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Day {
|
impl Day {
|
||||||
pub async fn new(db: &SqlitePool, day: NaiveDate, is_pinned: bool) -> Self {
|
pub async fn new(db: &SqlitePool, day: NaiveDate, is_pinned: bool) -> Self {
|
||||||
|
let today = Local::now().date_naive();
|
||||||
|
let day_diff = (day - today).num_days() + 1;
|
||||||
|
let regular_sees_this_day = day_diff <= AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
|
||||||
if is_pinned {
|
if is_pinned {
|
||||||
Self {
|
Self {
|
||||||
day,
|
day,
|
||||||
events: Event::get_pinned_for_day(db, day).await,
|
events: Event::get_pinned_for_day(db, day).await,
|
||||||
trips: Trip::get_pinned_for_day(db, day).await,
|
trips: Trip::get_pinned_for_day(db, day).await,
|
||||||
is_pinned,
|
is_pinned,
|
||||||
|
regular_sees_this_day,
|
||||||
max_waterlevel: Waterlevel::max_waterlevel_for_day(db, day).await,
|
max_waterlevel: Waterlevel::max_waterlevel_for_day(db, day).await,
|
||||||
weather: Weather::find_by_day(db, day).await,
|
weather: Weather::find_by_day(db, day).await,
|
||||||
}
|
}
|
||||||
@ -63,6 +70,7 @@ impl Day {
|
|||||||
events: Event::get_for_day(db, day).await,
|
events: Event::get_for_day(db, day).await,
|
||||||
trips: Trip::get_for_day(db, day).await,
|
trips: Trip::get_for_day(db, day).await,
|
||||||
is_pinned,
|
is_pinned,
|
||||||
|
regular_sees_this_day,
|
||||||
max_waterlevel: Waterlevel::max_waterlevel_for_day(db, day).await,
|
max_waterlevel: Waterlevel::max_waterlevel_for_day(db, day).await,
|
||||||
weather: Weather::find_by_day(db, day).await,
|
weather: Weather::find_by_day(db, day).await,
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use sqlx::SqlitePool;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event::{Event, Registration},
|
event::{Event, Registration},
|
||||||
|
log::Log,
|
||||||
notification::Notification,
|
notification::Notification,
|
||||||
tripdetails::TripDetails,
|
tripdetails::TripDetails,
|
||||||
triptype::TripType,
|
triptype::TripType,
|
||||||
@ -329,15 +330,13 @@ WHERE day=?
|
|||||||
return Err(TripDeleteError::SomebodyAlreadyRegistered);
|
return Err(TripDeleteError::SomebodyAlreadyRegistered);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.is_trip_from_user(user.id) {
|
if !self.is_trip_from_user(user.id) && !user.has_role(db, "admin").await {
|
||||||
return Err(TripDeleteError::NotYourTrip);
|
return Err(TripDeleteError::NotYourTrip);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlx::query!(
|
Log::create(db, format!("{} deleted trip: {:#?}", user.user.name, self)).await;
|
||||||
"DELETE FROM trip WHERE cox_id = ? AND id = ?",
|
|
||||||
user.id,
|
sqlx::query!("DELETE FROM trip WHERE id = ?", self.id)
|
||||||
self.id
|
|
||||||
)
|
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await
|
.await
|
||||||
.unwrap(); //TODO: fixme
|
.unwrap(); //TODO: fixme
|
||||||
|
@ -18,18 +18,11 @@ use super::{
|
|||||||
family::Family, log::Log, mail::Mail, notification::Notification, role::Role, stat::Stat,
|
family::Family, log::Log, mail::Mail, notification::Notification, role::Role, stat::Stat,
|
||||||
tripdetails::TripDetails, Day,
|
tripdetails::TripDetails, Day,
|
||||||
};
|
};
|
||||||
use crate::tera::admin::user::UserEditForm;
|
use crate::{
|
||||||
|
tera::admin::user::UserEditForm, AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD, BOAT_STORAGE,
|
||||||
const RENNRUDERBEITRAG: i32 = 11000;
|
EINSCHREIBGEBUEHR, FAMILY_THREE_OR_MORE, FAMILY_TWO, FOERDERND, REGULAR, RENNRUDERBEITRAG,
|
||||||
const BOAT_STORAGE: i32 = 4500;
|
SCHECKBUCH, STUDENT_OR_PUPIL, UNTERSTUETZEND,
|
||||||
const FAMILY_TWO: i32 = 30000;
|
};
|
||||||
const FAMILY_THREE_OR_MORE: i32 = 35000;
|
|
||||||
const STUDENT_OR_PUPIL: i32 = 8000;
|
|
||||||
const REGULAR: i32 = 22000;
|
|
||||||
const UNTERSTUETZEND: i32 = 2500;
|
|
||||||
const FOERDERND: i32 = 8500;
|
|
||||||
pub const SCHECKBUCH: i32 = 3000;
|
|
||||||
const EINSCHREIBGEBUEHR: i32 = 3000;
|
|
||||||
|
|
||||||
#[derive(FromRow, Serialize, Deserialize, Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(FromRow, Serialize, Deserialize, Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
@ -910,7 +903,7 @@ ORDER BY last_access DESC
|
|||||||
days_left_in_year
|
days_left_in_year
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
10
|
AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,11 +20,14 @@ use serde::Deserialize;
|
|||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
|
|
||||||
use crate::model::{
|
use crate::{
|
||||||
|
model::{
|
||||||
logbook::Logbook,
|
logbook::Logbook,
|
||||||
notification::Notification,
|
notification::Notification,
|
||||||
role::Role,
|
role::Role,
|
||||||
user::{User, UserWithDetails, SCHECKBUCH},
|
user::{User, UserWithDetails},
|
||||||
|
},
|
||||||
|
SCHECKBUCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) mod admin;
|
pub(crate) mod admin;
|
||||||
|
@ -8,12 +8,15 @@ use rocket_dyn_templates::Template;
|
|||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
|
|
||||||
use crate::model::{
|
use crate::{
|
||||||
|
model::{
|
||||||
log::Log,
|
log::Log,
|
||||||
tripdetails::TripDetails,
|
tripdetails::TripDetails,
|
||||||
triptype::TripType,
|
triptype::TripType,
|
||||||
user::{AllowedForPlannedTripsUser, User, UserWithDetails},
|
user::{AllowedForPlannedTripsUser, User, UserWithDetails},
|
||||||
usertrip::{UserTrip, UserTripDeleteError, UserTripError},
|
usertrip::{UserTrip, UserTripDeleteError, UserTripError},
|
||||||
|
},
|
||||||
|
AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
@ -42,6 +45,10 @@ async fn index(
|
|||||||
&user.allowed_to_update_always_show_trip(db).await,
|
&user.allowed_to_update_always_show_trip(db).await,
|
||||||
);
|
);
|
||||||
context.insert("fee", &user.fee(db).await);
|
context.insert("fee", &user.fee(db).await);
|
||||||
|
context.insert(
|
||||||
|
"amount_days_to_show_trips_ahead",
|
||||||
|
&AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD,
|
||||||
|
);
|
||||||
context.insert("loggedin_user", &UserWithDetails::from_user(user, db).await);
|
context.insert("loggedin_user", &UserWithDetails::from_user(user, db).await);
|
||||||
context.insert("days", &days);
|
context.insert("days", &days);
|
||||||
Template::render("planned", context.into_json())
|
Template::render("planned", context.into_json())
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
{% macro show_boats() %}
|
{% macro show_boats() %}
|
||||||
{% for cat, grouped_boats in boats | group_by(attribute="cat") %}
|
{% for cat, grouped_boats in boats | group_by(attribute="cat") %}
|
||||||
<details>
|
<details>
|
||||||
<summary class="font-bold cursor-pointer text-primary-900 dark:text-white border-t p-3 hover:bg-gray-100 dark:hover:bg-primary-950">
|
<summary class="font-bold cursor-pointer text-primary-900 dark:text-white {% if not loop.first %}border-t{% endif %} p-3 hover:bg-gray-100 dark:hover:bg-primary-950">
|
||||||
<span>{{ cat }}</span>
|
<span>{{ cat }}</span>
|
||||||
<small class="text-gray-500 dark:text-gray-100">({{ grouped_boats | length }})</small>
|
<small class="text-gray-500 dark:text-gray-100">({{ grouped_boats | length }})</small>
|
||||||
</summary>
|
</summary>
|
||||||
|
@ -20,17 +20,18 @@ function setChoiceByLabel(choicesInstance, label) {
|
|||||||
</script>
|
</script>
|
||||||
<div class="bg-white dark:bg-primary-900 rounded-md shadow pb-2 mt-3">
|
<div class="bg-white dark:bg-primary-900 rounded-md shadow pb-2 mt-3">
|
||||||
<h2 class="h2">Heute geplante Ausfahrten</h2>
|
<h2 class="h2">Heute geplante Ausfahrten</h2>
|
||||||
<div class="grid grid-cols-1 gap-3 mb-3 w-full">
|
<div class="grid grid-cols-1 gap-3 w-full">
|
||||||
{% for planned_trip in planned_trips | sort(attribute='planned_starting_time') %}
|
{% for planned_trip in planned_trips | sort(attribute='planned_starting_time') %}
|
||||||
<div class="pt-2 px-3 border-t text-primary-900 dark:text-white">
|
<div class="pt-2 px-3 {% if not loop.first %}border-t{% endif %} text-primary-900 dark:text-white flex justify-between items-center">
|
||||||
<strong class="block">
|
<strong class="block">
|
||||||
{{ planned_trip.cox_name }} ({{ planned_trip.rower | length + 1 }} Personen)
|
{% set amount_members = planned_trip.rower | length + 1 %}
|
||||||
<small>{{ planned_trip.planned_starting_time }}</small>
|
{{ planned_trip.cox_name }} ({{ amount_members }} Person{{ amount_members | pluralize(singular="", plural="en") }})
|
||||||
<button class="btn btn-primary"
|
<small class="block">{{ planned_trip.planned_starting_time }}</small>
|
||||||
onclick="choiceObjects['newrower'].removeActiveItems(-1);choiceObjects['newrower'].setChoiceByValue('{{ planned_trip.cox_id }}'); {% for rower in planned_trip.rower %}setChoiceByLabel(choiceObjects['newrower'], '{{ rower.name }}');{% endfor %}window.scrollTo(0,0); ">
|
|
||||||
|
</strong><button class="btn btn-primary ml-3"
|
||||||
|
onclick="choiceObjects['newrower'].removeActiveItems(-2);choiceObjects['newrower'].setChoiceByValue('{{ planned_trip.cox_id }}'); {% for rower in planned_trip.rower %}setChoiceByLabel(choiceObjects['newrower'], '{{ rower.name }}');{% endfor %}window.scrollTo(0,0); ">
|
||||||
👥
|
👥
|
||||||
</button>
|
</button>
|
||||||
</strong>
|
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@ -43,7 +44,7 @@ function setChoiceByLabel(choicesInstance, label) {
|
|||||||
<div class="grid grid-cols-1 gap-3 mb-3 w-full">
|
<div class="grid grid-cols-1 gap-3 mb-3 w-full">
|
||||||
{% for _, reservations_for_event in reservations %}
|
{% for _, reservations_for_event in reservations %}
|
||||||
{% set reservation = reservations_for_event[0] %}
|
{% set reservation = reservations_for_event[0] %}
|
||||||
<div class="pt-2 px-3 border-t text-primary-900 dark:text-white">
|
<div class="pt-2 px-3 {% if not loop.first %}border-t{% endif %} text-primary-900 dark:text-white">
|
||||||
<strong class="block">
|
<strong class="block">
|
||||||
{{ reservation.start_date | date(format="%d.%m.%Y") }}
|
{{ reservation.start_date | date(format="%d.%m.%Y") }}
|
||||||
{% if reservation.end_date != reservation.start_date %}
|
{% if reservation.end_date != reservation.start_date %}
|
||||||
|
@ -100,7 +100,8 @@
|
|||||||
style="order: {{ event.planned_starting_time | replace(from=":", to="") }}">
|
style="order: {{ event.planned_starting_time | replace(from=":", to="") }}">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="mr-1">
|
<div class="mr-1">
|
||||||
{% if event.max_people == 0 %}
|
{% if event.always_show and not day.regular_sees_this_day %}<span title="Du siehst diese Ausfahrt schon, obwohl sie mehr als {{ amount_days_to_show_trips_ahead }} Tage in der Zukunft liegt. Du Magier!">🔮</span>{% endif -%}
|
||||||
|
{%- if event.max_people == 0 %}
|
||||||
<strong class="text-[#f43f5e]">⚠ Absage
|
<strong class="text-[#f43f5e]">⚠ Absage
|
||||||
{{ event.planned_starting_time }}
|
{{ event.planned_starting_time }}
|
||||||
Uhr
|
Uhr
|
||||||
@ -274,6 +275,7 @@
|
|||||||
data-coxneeded="false">
|
data-coxneeded="false">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="mr-1">
|
<div class="mr-1">
|
||||||
|
{% if trip.always_show and not day.regular_sees_this_day %}<span title="Du siehst diese Ausfahrt schon, obwohl sie mehr als {{ amount_days_to_show_trips_ahead }} Tage in der Zukunft liegt. Du Magier!">🔮</span>{% endif -%}
|
||||||
{% if trip.max_people == 0 %}
|
{% if trip.max_people == 0 %}
|
||||||
<strong class="text-[#f43f5e]">⚠
|
<strong class="text-[#f43f5e]">⚠
|
||||||
{{ trip.planned_starting_time }}
|
{{ trip.planned_starting_time }}
|
||||||
@ -382,13 +384,25 @@
|
|||||||
{% if allowed_to_update_always_show_trip %}
|
{% if allowed_to_update_always_show_trip %}
|
||||||
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
|
<div class="bg-gray-100 dark:bg-primary-900 p-3 mt-4 rounded-md">
|
||||||
<h3 class="text-primary-950 dark:text-white font-bold uppercase tracking-wide mb-2">Admin-Modus</h3>
|
<h3 class="text-primary-950 dark:text-white font-bold uppercase tracking-wide mb-2">Admin-Modus</h3>
|
||||||
|
{% if not day.regular_sees_this_day %}
|
||||||
<form action="/cox/trip/{{ trip.id }}/toggle-always-show"
|
<form action="/cox/trip/{{ trip.id }}/toggle-always-show"
|
||||||
method="get"
|
method="get"
|
||||||
class="grid gap-3">
|
class="grid gap-3">
|
||||||
<input value="{% if trip.always_show %}Normal anzeigen{% else %}Immer anzeigen{% endif %}"
|
{% if not trip.always_show %}
|
||||||
|
<small>Diese Ausfahrt sehen aktuell nur Steuerleute (und Admins). {{ amount_days_to_show_trips_ahead }} Tage vorher sehen sie dann alle.</small>
|
||||||
|
{% else %}
|
||||||
|
<small>Diese Ausfahrt sehen alle Mitglieder.</small>
|
||||||
|
{% endif %}
|
||||||
|
<input value="{% if trip.always_show %}Ausfahrt nur Steuerleute (und Admins) anzeigen{% else %}Ausfahrt allen anzeigen{% endif %}"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
type="submit" />
|
type="submit" />
|
||||||
</form>
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
<a href="/cox/remove/trip/{{ trip.id }}"
|
||||||
|
class="inline-block btn btn-alert mt-5 w-full">
|
||||||
|
{% include "includes/delete-icon" %}
|
||||||
|
Termin löschen
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{# --- END Admin Form --- #}
|
{# --- END Admin Form --- #}
|
||||||
|
Loading…
Reference in New Issue
Block a user