Merge remote-tracking branch 'upstream/main'
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy-main (push) Has been cancelled

This commit is contained in:
2025-04-28 22:37:31 +02:00
11 changed files with 239 additions and 63 deletions

View File

@@ -34,11 +34,13 @@ pub struct Event {
}
#[derive(Serialize, Debug)]
pub struct EventWithUserAndTriptype {
pub struct EventWithDetails {
#[serde(flatten)]
pub event: Event,
trip_type: Option<TripType>,
tripdetails: TripDetails,
cox_needed: bool,
cancelled: bool,
cox: Vec<Registration>,
rower: Vec<Registration>,
}
@@ -116,6 +118,12 @@ pub struct EventUpdate<'a> {
pub trip_type_id: Option<i64>,
}
impl EventUpdate<'_> {
fn cancelled(&self) -> bool {
self.max_people == -1
}
}
impl Event {
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
sqlx::query_as!(
@@ -134,16 +142,13 @@ WHERE planned_event.id like ?
.ok()
}
pub async fn get_pinned_for_day(
db: &SqlitePool,
day: NaiveDate,
) -> Vec<EventWithUserAndTriptype> {
pub async fn get_pinned_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<EventWithDetails> {
let mut events = Self::get_for_day(db, day).await;
events.retain(|e| e.event.always_show);
events
}
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<EventWithUserAndTriptype> {
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<EventWithDetails> {
let day = format!("{day}");
let events = sqlx::query_as!(
Event,
@@ -164,10 +169,15 @@ WHERE day=?",
if let Some(trip_type_id) = event.trip_type_id {
trip_type = TripType::find_by_id(db, trip_type_id).await;
}
ret.push(EventWithUserAndTriptype {
let tripdetails = TripDetails::find_by_id(db, event.trip_details_id)
.await
.expect("db constraints");
ret.push(EventWithDetails {
cox_needed: event.planned_amount_cox > cox.len() as i64,
cox,
rower: Registration::all_rower(db, event.trip_details_id).await,
cancelled: tripdetails.cancelled(),
tripdetails,
event,
trip_type,
});
@@ -313,7 +323,7 @@ WHERE trip_details.id=?
.unwrap(); //Okay, as planned_event can only be created with proper DB backing
let tripdetails = self.trip_details(db).await;
let was_already_cancelled = tripdetails.max_people == 0;
let was_already_cancelled = tripdetails.cancelled();
sqlx::query!(
"UPDATE trip_details SET max_people = ?, notes = ?, always_show = ?, is_locked = ?, trip_type_id = ? WHERE id = ?",
@@ -338,7 +348,7 @@ WHERE trip_details.id=?
.await;
}
if update.max_people == 0 && !was_already_cancelled {
if update.cancelled() && !was_already_cancelled {
let coxes = Registration::all_cox(db, self.id).await;
for user in coxes {
if let Some(user) = User::find_by_name(db, &user.name).await {
@@ -387,7 +397,7 @@ WHERE trip_details.id=?
}
}
}
if update.max_people > 0 && was_already_cancelled {
if !update.cancelled() && was_already_cancelled {
Notification::delete_by_action(
db,
&format!("remove_user_trip_with_trip_details_id:{}", tripdetails.id),
@@ -425,7 +435,7 @@ WHERE trip_details.id=?
}
pub fn is_cancelled(&self) -> bool {
self.max_people == 0
self.max_people == -1
}
pub async fn get_ics_feed(db: &SqlitePool) -> String {
@@ -442,10 +452,16 @@ WHERE trip_details.id=?
pub(crate) async fn get_vevent(self, db: &SqlitePool) -> ics::Event {
let mut vevent = ics::Event::new(format!("event-{}@ruad.at", self.id), "19900101T180000");
let time_str = self.planned_starting_time.replace(':', "");
let formatted_time = if time_str.len() == 3 {
format!("0{}", time_str)
} else {
time_str.clone() // TODO: remove again
};
vevent.push(DtStart::new(format!(
"{}T{}00",
self.day.replace('-', ""),
self.planned_starting_time.replace(':', "")
formatted_time
)));
let original_time = NaiveTime::parse_from_str(&self.planned_starting_time, "%H:%M")

View File

@@ -6,8 +6,8 @@ use waterlevel::WaterlevelDay;
use crate::AMOUNT_DAYS_TO_SHOW_TRIPS_AHEAD;
use self::{
event::{Event, EventWithUserAndTriptype},
trip::{Trip, TripWithUserAndType},
event::{Event, EventWithDetails},
trip::{Trip, TripWithDetails},
waterlevel::Waterlevel,
weather::Weather,
};
@@ -28,8 +28,8 @@ pub mod weather;
#[derive(Serialize, Debug)]
pub struct Day {
day: NaiveDate,
events: Vec<EventWithUserAndTriptype>,
trips: Vec<TripWithUserAndType>,
events: Vec<EventWithDetails>,
trips: Vec<TripWithDetails>,
is_pinned: bool,
regular_sees_this_day: bool,
max_waterlevel: Option<WaterlevelDay>,

View File

@@ -284,7 +284,7 @@ mod test {
let cancel_update = EventUpdate {
name: &event.name,
planned_amount_cox: event.planned_amount_cox as i32,
max_people: 0,
max_people: -1,
notes: event.notes.as_deref(),
always_show: event.always_show,
is_locked: event.is_locked,

View File

@@ -30,11 +30,12 @@ pub struct Trip {
}
#[derive(Serialize, Debug)]
pub struct TripWithUserAndType {
pub struct TripWithDetails {
#[serde(flatten)]
pub trip: Trip,
pub rower: Vec<Registration>,
trip_type: Option<TripType>,
cancelled: bool,
}
pub struct TripUpdate<'a> {
@@ -46,7 +47,13 @@ pub struct TripUpdate<'a> {
pub is_locked: bool,
}
impl TripWithUserAndType {
impl<'a> TripUpdate<'a> {
fn cancelled(&self) -> bool {
self.max_people == -1
}
}
impl TripWithDetails {
pub async fn from(db: &SqlitePool, trip: Trip) -> Self {
let mut trip_type = None;
if let Some(trip_type_id) = trip.trip_type_id {
@@ -54,8 +61,9 @@ impl TripWithUserAndType {
}
Self {
rower: Registration::all_rower(db, trip.trip_details_id.unwrap()).await,
trip,
trip_type,
cancelled: trip.is_cancelled(),
trip,
}
}
}
@@ -129,10 +137,17 @@ WHERE trip_details.id=?
pub(crate) async fn get_vevent(self, user: &User) -> ics::Event {
let mut vevent = ics::Event::new(format!("trip-{}@ruad.at", self.id), "19900101T180000");
let time_str = self.planned_starting_time.replace(':', "");
let formatted_time = if time_str.len() == 3 {
format!("0{}", time_str)
} else {
time_str
};
vevent.push(DtStart::new(format!(
"{}T{}00",
self.day.replace('-', ""),
self.planned_starting_time.replace(':', "")
formatted_time
)));
let original_time = NaiveTime::parse_from_str(&self.planned_starting_time, "%H:%M")
@@ -234,7 +249,7 @@ WHERE trip.id=?
return Err(CoxHelpError::DetailsLocked);
}
if event.max_people == 0 {
if event.is_cancelled() {
return Err(CoxHelpError::CanceledEvent);
}
@@ -251,12 +266,12 @@ WHERE trip.id=?
}
}
pub async fn get_for_today(db: &SqlitePool) -> Vec<TripWithUserAndType> {
pub async fn get_for_today(db: &SqlitePool) -> Vec<TripWithDetails> {
let today = Local::now().date_naive();
Self::get_for_day(db, today).await
}
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<TripWithUserAndType> {
pub async fn get_for_day(db: &SqlitePool, day: NaiveDate) -> Vec<TripWithDetails> {
let day = format!("{day}");
let trips = sqlx::query_as!(
Trip,
@@ -275,7 +290,7 @@ WHERE day=?
let mut ret = Vec::new();
for trip in trips {
ret.push(TripWithUserAndType::from(db, trip).await);
ret.push(TripWithDetails::from(db, trip).await);
}
ret
}
@@ -298,9 +313,9 @@ WHERE day=?
};
let tripdetails = TripDetails::find_by_id(db, trip_details_id).await.unwrap();
let was_already_cancelled = tripdetails.max_people == 0;
let was_already_cancelled = tripdetails.cancelled();
let is_locked = if update.max_people == 0 {
let is_locked = if update.cancelled() {
false
} else {
update.is_locked
@@ -318,10 +333,8 @@ WHERE day=?
.await
.unwrap(); //Okay, as trip_details can only be created with proper DB backing
if update.max_people == 0 && !was_already_cancelled {
let rowers = TripWithUserAndType::from(db, update.trip.clone())
.await
.rower;
if update.cancelled() && !was_already_cancelled {
let rowers = TripWithDetails::from(db, update.trip.clone()).await.rower;
for user in rowers {
if let Some(user) = User::find_by_name(db, &user.name).await {
let notes = match update.notes {
@@ -357,7 +370,7 @@ WHERE day=?
.await;
}
if update.max_people > 0 && was_already_cancelled {
if !update.cancelled() && was_already_cancelled {
Notification::delete_by_action(
db,
&format!("remove_user_trip_with_trip_details_id:{}", trip_details_id),
@@ -445,14 +458,14 @@ WHERE day=?
pub(crate) async fn get_pinned_for_day(
db: &sqlx::Pool<sqlx::Sqlite>,
day: NaiveDate,
) -> Vec<TripWithUserAndType> {
) -> Vec<TripWithDetails> {
let mut trips = Self::get_for_day(db, day).await;
trips.retain(|e| e.trip.always_show);
trips
}
fn is_cancelled(&self) -> bool {
self.max_people == 0
self.max_people == -1
}
}

View File

@@ -6,7 +6,7 @@ use sqlx::{FromRow, SqlitePool};
use super::{
notification::Notification,
trip::{Trip, TripWithUserAndType},
trip::{Trip, TripWithDetails},
triptype::TripType,
};
@@ -95,7 +95,7 @@ WHERE day = ? AND planned_starting_time = ?
}
pub fn cancelled(&self) -> bool {
self.max_people == 0
self.max_people == -1
}
/// This function is called when a person registers to a trip or when the cox changes the
@@ -138,7 +138,7 @@ WHERE day = ? AND planned_starting_time = ?
// This trip_details belongs to a planned_event, no need to do anything
continue;
};
let pot_coxes = TripWithUserAndType::from(db, trip.clone()).await;
let pot_coxes = TripWithDetails::from(db, trip.clone()).await;
let pot_coxes = pot_coxes.rower;
for user in pot_coxes {
let cox = User::find_by_id(db, trip.cox_id as i32).await.unwrap();
@@ -196,7 +196,7 @@ WHERE day = ? AND planned_starting_time = ?
.fetch_one(db)
.await
.unwrap(); //TODO: fixme
let amount_currently_registered = i64::from(amount_currently_registered.count);
let amount_currently_registered = amount_currently_registered.count;
amount_currently_registered >= self.max_people
}

View File

@@ -3,7 +3,7 @@ use sqlx::{FromRow, SqlitePool};
use super::{
notification::Notification,
trip::{Trip, TripWithUserAndType},
trip::{Trip, TripWithDetails},
tripdetails::TripDetails,
user::{SteeringUser, User},
};
@@ -158,7 +158,7 @@ impl UserTrip {
.unwrap()
.cancelled()
{
let trip = TripWithUserAndType::from(db, trip.clone()).await;
let trip = TripWithDetails::from(db, trip.clone()).await;
if trip.rower.len() == 1 {
trip_to_delete = Some(trip.trip);
}

View File

@@ -71,7 +71,6 @@ async fn steering(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage
fn unauthorized_error(req: &Request) -> Redirect {
// Save the URL the user tried to access, to be able to go there once logged in
let mut redirect_cookie = Cookie::new("redirect_url", format!("{}", req.uri()));
println!("{}", req.uri());
redirect_cookie.set_expires(OffsetDateTime::now_utc() + Duration::hours(1));
req.cookies().add_private(redirect_cookie);