Compare commits

...

3 Commits

Author SHA1 Message Date
7ab6d95e23 Merge pull request 'upd' (#721) from upd into staging
Some checks failed
CI/CD Pipeline / test (push) Successful in 11m6s
CI/CD Pipeline / deploy-main (push) Has been cancelled
CI/CD Pipeline / deploy-staging (push) Has been cancelled
Reviewed-on: #721
2024-09-03 20:44:19 +02:00
f38d506fe4 many updates :-(
All checks were successful
CI/CD Pipeline / test (push) Successful in 11m12s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Has been skipped
2024-09-03 21:35:43 +03:00
96dcf2c4ae Merge pull request 'delete cancelled trips if all rowers have seen the notification' (#720) from delete-cancelled-events into main
All checks were successful
CI/CD Pipeline / test (push) Successful in 11m26s
CI/CD Pipeline / deploy-staging (push) Has been skipped
CI/CD Pipeline / deploy-main (push) Successful in 8m19s
Reviewed-on: #720
2024-09-03 16:51:39 +02:00
9 changed files with 82 additions and 45 deletions

View File

@ -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 {

View File

@ -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,
} }

View File

@ -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,18 +330,16 @@ 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)
) .await
.execute(db) .unwrap(); //TODO: fixme
.await
.unwrap(); //TODO: fixme
Ok(()) Ok(())
} }

View File

@ -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
} }
} }

View File

@ -20,11 +20,14 @@ use serde::Deserialize;
use sqlx::SqlitePool; use sqlx::SqlitePool;
use tera::Context; use tera::Context;
use crate::model::{ use crate::{
logbook::Logbook, model::{
notification::Notification, logbook::Logbook,
role::Role, notification::Notification,
user::{User, UserWithDetails, SCHECKBUCH}, role::Role,
user::{User, UserWithDetails},
},
SCHECKBUCH,
}; };
pub(crate) mod admin; pub(crate) mod admin;

View File

@ -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::{
log::Log, model::{
tripdetails::TripDetails, log::Log,
triptype::TripType, tripdetails::TripDetails,
user::{AllowedForPlannedTripsUser, User, UserWithDetails}, triptype::TripType,
usertrip::{UserTrip, UserTripDeleteError, UserTripError}, user::{AllowedForPlannedTripsUser, User, UserWithDetails},
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())

View File

@ -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>

View File

@ -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 }}&nbsp;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 %}

View File

@ -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]">&#9888; Absage <strong class="text-[#f43f5e]">&#9888; 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]">&#9888; <strong class="text-[#f43f5e]">&#9888;
{{ 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 --- #}