update-deps #717
@@ -18,7 +18,7 @@ test("cox can create and delete trip", async ({ page }) => {
 | 
				
			|||||||
  await expect(page.locator("body")).toContainText("18:00 Uhr (cox) Details");
 | 
					  await expect(page.locator("body")).toContainText("18:00 Uhr (cox) Details");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await page.goto("/planned");
 | 
					  await page.goto("/planned");
 | 
				
			||||||
  await page.getByRole("link", { name: "Details" }).click();
 | 
					  await page.getByRole('link', { name: 'Details' }).nth(1).click();
 | 
				
			||||||
  await page.getByRole("link", { name: "Termin löschen" }).click();
 | 
					  await page.getByRole("link", { name: "Termin löschen" }).click();
 | 
				
			||||||
  await expect(page.locator("body")).toContainText("Erfolgreich gelöscht!");
 | 
					  await expect(page.locator("body")).toContainText("Erfolgreich gelöscht!");
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@@ -52,11 +52,11 @@ test.describe("cox can edit trips", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test("edit remarks", async () => {
 | 
					  test("edit remarks", async () => {
 | 
				
			||||||
    await sharedPage.goto("/planned");
 | 
					    await sharedPage.goto("/planned");
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole('link', { name: 'Details' }).nth(1).click();
 | 
				
			||||||
    await sharedPage.locator("#sidebar #notes").click();
 | 
					    await sharedPage.locator("#sidebar #notes").click();
 | 
				
			||||||
    await sharedPage.locator("#sidebar #notes").fill("Meine Anmerkung");
 | 
					    await sharedPage.locator("#sidebar #notes").fill("Meine Anmerkung");
 | 
				
			||||||
    await sharedPage.getByRole("button", { name: "Speichern" }).click();
 | 
					    await sharedPage.getByRole("button", { name: "Speichern" }).click();
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
 | 
				
			||||||
    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
					    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
				
			||||||
      "Meine Anmerkung",
 | 
					      "Meine Anmerkung",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -68,14 +68,14 @@ test.describe("cox can edit trips", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test("add and remove guest", async () => {
 | 
					  test("add and remove guest", async () => {
 | 
				
			||||||
    await sharedPage.goto("/planned");
 | 
					    await sharedPage.goto("/planned");
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
 | 
				
			||||||
    await sharedPage.locator("#sidebar #user_note").click();
 | 
					    await sharedPage.locator("#sidebar #user_note").click();
 | 
				
			||||||
    await sharedPage.locator("#sidebar #user_note").fill("Mein Gast");
 | 
					    await sharedPage.locator("#sidebar #user_note").fill("Mein Gast");
 | 
				
			||||||
    await sharedPage.getByRole("button", { name: "Gast hinzufügen" }).click();
 | 
					    await sharedPage.getByRole("button", { name: "Gast hinzufügen" }).click();
 | 
				
			||||||
    await expect(sharedPage.locator("body")).toContainText(
 | 
					    await expect(sharedPage.locator("body")).toContainText(
 | 
				
			||||||
      "Erfolgreich angemeldet!",
 | 
					      "Erfolgreich angemeldet!",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
 | 
				
			||||||
    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
					    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
				
			||||||
      "Freie Plätze: 4",
 | 
					      "Freie Plätze: 4",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -90,7 +90,7 @@ test.describe("cox can edit trips", () => {
 | 
				
			|||||||
    await expect(sharedPage.locator("body")).toContainText(
 | 
					    await expect(sharedPage.locator("body")).toContainText(
 | 
				
			||||||
      "Erfolgreich abgemeldet!",
 | 
					      "Erfolgreich abgemeldet!",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
 | 
				
			||||||
    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
					    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
				
			||||||
      "Freie Plätze: 5",
 | 
					      "Freie Plätze: 5",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -108,7 +108,7 @@ test.describe("cox can edit trips", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test("change amount rower", async () => {
 | 
					  test("change amount rower", async () => {
 | 
				
			||||||
    await sharedPage.goto("/planned");
 | 
					    await sharedPage.goto("/planned");
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
 | 
				
			||||||
    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
					    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
				
			||||||
      "Freie Plätze: 5",
 | 
					      "Freie Plätze: 5",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -122,7 +122,7 @@ test.describe("cox can edit trips", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test("call off trip", async () => {
 | 
					  test("call off trip", async () => {
 | 
				
			||||||
    await sharedPage.goto("/planned");
 | 
					    await sharedPage.goto("/planned");
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Details" }).nth(1).click();
 | 
				
			||||||
    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
					    await expect(sharedPage.locator("#sidebar")).toContainText(
 | 
				
			||||||
      "Freie Plätze: 3",
 | 
					      "Freie Plätze: 3",
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@@ -137,7 +137,7 @@ test.describe("cox can edit trips", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test.afterAll(async () => {
 | 
					  test.afterAll(async () => {
 | 
				
			||||||
    await sharedPage.goto("/planned");
 | 
					    await sharedPage.goto("/planned");
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Details" }).click();
 | 
					    await sharedPage.getByRole('link', { name: 'Details' }).nth(1).click();
 | 
				
			||||||
    await sharedPage.getByRole("link", { name: "Termin löschen" }).click();
 | 
					    await sharedPage.getByRole("link", { name: "Termin löschen" }).click();
 | 
				
			||||||
    await sharedPage.close();
 | 
					    await sharedPage.close();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,10 +45,10 @@ INSERT INTO "user_role" (user_id, role_id) VALUES(10,5);
 | 
				
			|||||||
INSERT INTO "user_role" (user_id, role_id) VALUES(10,6);
 | 
					INSERT INTO "user_role" (user_id, role_id) VALUES(10,6);
 | 
				
			||||||
INSERT INTO "user_role" (user_id, role_id) VALUES(10,9);
 | 
					INSERT INTO "user_role" (user_id, role_id) VALUES(10,9);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('10:00', 2, '1970-01-01', 'trip_details for a planned event');
 | 
					INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('10:00', 2, date('now'), 'trip_details for a planned event');
 | 
				
			||||||
INSERT INTO "planned_event" (name, planned_amount_cox, trip_details_id) VALUES('test-planned-event', 2, 1);
 | 
					INSERT INTO "planned_event" (name, planned_amount_cox, trip_details_id) VALUES('test-planned-event', 2, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('11:00', 1, '1970-01-02', 'trip_details for trip from cox');
 | 
					INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('11:00', 1, date('now', '+1 day'), 'trip_details for trip from cox');
 | 
				
			||||||
INSERT INTO "trip" (cox_id, trip_details_id) VALUES(4, 2);
 | 
					INSERT INTO "trip" (cox_id, trip_details_id) VALUES(4, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Regatta', 'Regatta!', 'Kein normales Event. Das ist eine Regatta! Willst du wirklich teilnehmen?', '🏅');
 | 
					INSERT INTO "trip_type" (name, desc, question, icon) VALUES ('Regatta', 'Regatta!', 'Kein normales Event. Das ist eine Regatta! Willst du wirklich teilnehmen?', '🏅');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -233,6 +233,7 @@ WHERE trip_details.id=?
 | 
				
			|||||||
        db: &SqlitePool,
 | 
					        db: &SqlitePool,
 | 
				
			||||||
        name: &str,
 | 
					        name: &str,
 | 
				
			||||||
        planned_amount_cox: i32,
 | 
					        planned_amount_cox: i32,
 | 
				
			||||||
 | 
					        always_show: bool,
 | 
				
			||||||
        trip_details: &TripDetails,
 | 
					        trip_details: &TripDetails,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        if trip_details.always_show {
 | 
					        if trip_details.always_show {
 | 
				
			||||||
@@ -245,6 +246,10 @@ WHERE trip_details.id=?
 | 
				
			|||||||
            .await;
 | 
					            .await;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if always_show && !trip_details.always_show {
 | 
				
			||||||
 | 
					            trip_details.set_always_show(db, true).await;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sqlx::query!(
 | 
					        sqlx::query!(
 | 
				
			||||||
            "INSERT INTO planned_event(name, planned_amount_cox, trip_details_id) VALUES(?, ?, ?)",
 | 
					            "INSERT INTO planned_event(name, planned_amount_cox, trip_details_id) VALUES(?, ?, ?)",
 | 
				
			||||||
            name,
 | 
					            name,
 | 
				
			||||||
@@ -433,14 +438,14 @@ mod test {
 | 
				
			|||||||
    use crate::{model::tripdetails::TripDetails, testdb};
 | 
					    use crate::{model::tripdetails::TripDetails, testdb};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use super::Event;
 | 
					    use super::Event;
 | 
				
			||||||
    use chrono::NaiveDate;
 | 
					    use chrono::Local;
 | 
				
			||||||
    use sqlx::SqlitePool;
 | 
					    use sqlx::SqlitePool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[sqlx::test]
 | 
					    #[sqlx::test]
 | 
				
			||||||
    fn test_get_day() {
 | 
					    fn test_get_day() {
 | 
				
			||||||
        let pool = testdb!();
 | 
					        let pool = testdb!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let res = Event::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await;
 | 
					        let res = Event::get_for_day(&pool, Local::now().date_naive()).await;
 | 
				
			||||||
        assert_eq!(res.len(), 1);
 | 
					        assert_eq!(res.len(), 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -450,9 +455,9 @@ mod test {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
 | 
					        let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Event::create(&pool, "new-event".into(), 2, &trip_details).await;
 | 
					        Event::create(&pool, "new-event".into(), 2, false, &trip_details).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let res = Event::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await;
 | 
					        let res = Event::get_for_day(&pool, Local::now().date_naive()).await;
 | 
				
			||||||
        assert_eq!(res.len(), 2);
 | 
					        assert_eq!(res.len(), 2);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -463,7 +468,7 @@ mod test {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        planned_event.delete(&pool).await.unwrap();
 | 
					        planned_event.delete(&pool).await.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let res = Event::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await;
 | 
					        let res = Event::get_for_day(&pool, Local::now().date_naive()).await;
 | 
				
			||||||
        assert_eq!(res.len(), 0);
 | 
					        assert_eq!(res.len(), 0);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -471,7 +476,8 @@ mod test {
 | 
				
			|||||||
    fn test_ics() {
 | 
					    fn test_ics() {
 | 
				
			||||||
        let pool = testdb!();
 | 
					        let pool = testdb!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let today = Local::now().date_naive().format("%Y%m%d").to_string();
 | 
				
			||||||
        let actual = Event::get_ics_feed(&pool).await;
 | 
					        let actual = Event::get_ics_feed(&pool).await;
 | 
				
			||||||
        assert_eq!("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:ics-rs\r\nBEGIN:VEVENT\r\nUID:1@rudernlinz.at\r\nDTSTAMP:19900101T180000\r\nDTSTART:19700101T100000\r\nSUMMARY:test-planned-event \r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", actual);
 | 
					        assert_eq!(format!("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:ics-rs\r\nBEGIN:VEVENT\r\nUID:1@rudernlinz.at\r\nDTSTAMP:19900101T180000\r\nDTSTART:{today}T100000\r\nSUMMARY:test-planned-event \r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"), actual);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -575,10 +575,8 @@ ORDER BY departure DESC
 | 
				
			|||||||
            return Err(LogbookUpdateError::ArrivalNotAfterDeparture);
 | 
					            return Err(LogbookUpdateError::ArrivalNotAfterDeparture);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !boat.external {
 | 
					        if !boat.external && boat.on_water_between(db, dep, arr).await {
 | 
				
			||||||
            if boat.on_water_between(db, dep, arr).await {
 | 
					 | 
				
			||||||
            return Err(LogbookUpdateError::BoatAlreadyOnWater);
 | 
					            return Err(LogbookUpdateError::BoatAlreadyOnWater);
 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let duration_in_mins = (arr.and_utc().timestamp() - dep.and_utc().timestamp()) / 60;
 | 
					        let duration_in_mins = (arr.and_utc().timestamp() - dep.and_utc().timestamp()) / 60;
 | 
				
			||||||
@@ -594,15 +592,14 @@ ORDER BY departure DESC
 | 
				
			|||||||
        let today = Local::now().date_naive();
 | 
					        let today = Local::now().date_naive();
 | 
				
			||||||
        let day_diff = today - arr.date();
 | 
					        let day_diff = today - arr.date();
 | 
				
			||||||
        let day_diff = day_diff.num_days();
 | 
					        let day_diff = day_diff.num_days();
 | 
				
			||||||
        if day_diff >= 7 {
 | 
					        if day_diff >= 7
 | 
				
			||||||
            if !user.has_role_tx(db, "admin").await
 | 
					            && !user.has_role_tx(db, "admin").await
 | 
				
			||||||
            && !user
 | 
					            && !user
 | 
				
			||||||
                .has_role_tx(db, "allow-retroactive-logbookentries")
 | 
					                .has_role_tx(db, "allow-retroactive-logbookentries")
 | 
				
			||||||
                .await
 | 
					                .await
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return Err(LogbookUpdateError::OnlyAllowedToEndTripsEndingToday);
 | 
					            return Err(LogbookUpdateError::OnlyAllowedToEndTripsEndingToday);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if day_diff < 0 && !user.has_role_tx(db, "admin").await {
 | 
					        if day_diff < 0 && !user.has_role_tx(db, "admin").await {
 | 
				
			||||||
            return Err(LogbookUpdateError::OnlyAllowedToEndTripsEndingToday);
 | 
					            return Err(LogbookUpdateError::OnlyAllowedToEndTripsEndingToday);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -203,6 +203,7 @@ mod test {
 | 
				
			|||||||
        testdb,
 | 
					        testdb,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    use chrono::Local;
 | 
				
			||||||
    use sqlx::SqlitePool;
 | 
					    use sqlx::SqlitePool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[sqlx::test]
 | 
					    #[sqlx::test]
 | 
				
			||||||
@@ -213,17 +214,16 @@ mod test {
 | 
				
			|||||||
        let add_tripdetails = TripDetailsToAdd {
 | 
					        let add_tripdetails = TripDetailsToAdd {
 | 
				
			||||||
            planned_starting_time: "10:00",
 | 
					            planned_starting_time: "10:00",
 | 
				
			||||||
            max_people: 4,
 | 
					            max_people: 4,
 | 
				
			||||||
            day: "1970-02-01".into(),
 | 
					            day: Local::now().date_naive().format("%Y-%m-%d").to_string(),
 | 
				
			||||||
            notes: None,
 | 
					            notes: None,
 | 
				
			||||||
            trip_type: None,
 | 
					            trip_type: None,
 | 
				
			||||||
            allow_guests: false,
 | 
					            allow_guests: false,
 | 
				
			||||||
            always_show: false,
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let tripdetails_id = TripDetails::create(&pool, add_tripdetails).await;
 | 
					        let tripdetails_id = TripDetails::create(&pool, add_tripdetails).await;
 | 
				
			||||||
        let trip_details = TripDetails::find_by_id(&pool, tripdetails_id)
 | 
					        let trip_details = TripDetails::find_by_id(&pool, tripdetails_id)
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
        Event::create(&pool, "new-event".into(), 2, &trip_details).await;
 | 
					        Event::create(&pool, "new-event".into(), 2, false, &trip_details).await;
 | 
				
			||||||
        let event = Event::find_by_trip_details(&pool, trip_details.id)
 | 
					        let event = Event::find_by_trip_details(&pool, trip_details.id)
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
            .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,6 @@ pub struct TripUpdate<'a> {
 | 
				
			|||||||
    pub max_people: i32,
 | 
					    pub max_people: i32,
 | 
				
			||||||
    pub notes: Option<&'a str>,
 | 
					    pub notes: Option<&'a str>,
 | 
				
			||||||
    pub trip_type: Option<i64>, //TODO: Move to `TripType`
 | 
					    pub trip_type: Option<i64>, //TODO: Move to `TripType`
 | 
				
			||||||
    pub always_show: bool,
 | 
					 | 
				
			||||||
    pub is_locked: bool,
 | 
					    pub is_locked: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,7 +82,7 @@ impl Trip {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // don't notify people who have cancelled their trip
 | 
					                // don't notify people who have cancelled their trip
 | 
				
			||||||
                if notify.cancelled(db) {
 | 
					                if notify.cancelled() {
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -217,11 +216,10 @@ WHERE day=?
 | 
				
			|||||||
        let was_already_cancelled = tripdetails.max_people == 0;
 | 
					        let was_already_cancelled = tripdetails.max_people == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sqlx::query!(
 | 
					        sqlx::query!(
 | 
				
			||||||
            "UPDATE trip_details SET max_people = ?, notes = ?, trip_type_id = ?, always_show = ?, is_locked = ? WHERE id = ?",
 | 
					            "UPDATE trip_details SET max_people = ?, notes = ?, trip_type_id = ?, is_locked = ? WHERE id = ?",
 | 
				
			||||||
            update.max_people,
 | 
					            update.max_people,
 | 
				
			||||||
            update.notes,
 | 
					            update.notes,
 | 
				
			||||||
            update.trip_type,
 | 
					            update.trip_type,
 | 
				
			||||||
            update.always_show,
 | 
					 | 
				
			||||||
            update.is_locked,
 | 
					            update.is_locked,
 | 
				
			||||||
            trip_details_id
 | 
					            trip_details_id
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -345,6 +343,20 @@ WHERE day=?
 | 
				
			|||||||
        self.cox_id == user_id
 | 
					        self.cox_id == user_id
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) async fn toggle_always_show(&self, db: &SqlitePool) {
 | 
				
			||||||
 | 
					        if let Some(trip_details) = self.trip_details_id {
 | 
				
			||||||
 | 
					            let new_state = !self.always_show;
 | 
				
			||||||
 | 
					            sqlx::query!(
 | 
				
			||||||
 | 
					                "UPDATE trip_details SET always_show = ? WHERE id = ?",
 | 
				
			||||||
 | 
					                new_state,
 | 
				
			||||||
 | 
					                trip_details
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .execute(db)
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub(crate) async fn get_pinned_for_day(
 | 
					    pub(crate) async fn get_pinned_for_day(
 | 
				
			||||||
        db: &sqlx::Pool<sqlx::Sqlite>,
 | 
					        db: &sqlx::Pool<sqlx::Sqlite>,
 | 
				
			||||||
        day: NaiveDate,
 | 
					        day: NaiveDate,
 | 
				
			||||||
@@ -394,7 +406,7 @@ mod test {
 | 
				
			|||||||
        testdb,
 | 
					        testdb,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use chrono::NaiveDate;
 | 
					    use chrono::Local;
 | 
				
			||||||
    use sqlx::SqlitePool;
 | 
					    use sqlx::SqlitePool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use super::Trip;
 | 
					    use super::Trip;
 | 
				
			||||||
@@ -421,7 +433,8 @@ mod test {
 | 
				
			|||||||
    fn test_get_day_cox_trip() {
 | 
					    fn test_get_day_cox_trip() {
 | 
				
			||||||
        let pool = testdb!();
 | 
					        let pool = testdb!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let res = Trip::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 2).unwrap()).await;
 | 
					        let tomorrow = Local::now().date_naive() + chrono::Duration::days(1);
 | 
				
			||||||
 | 
					        let res = Trip::get_for_day(&pool, tomorrow).await;
 | 
				
			||||||
        assert_eq!(res.len(), 1);
 | 
					        assert_eq!(res.len(), 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -477,7 +490,6 @@ mod test {
 | 
				
			|||||||
            max_people: 10,
 | 
					            max_people: 10,
 | 
				
			||||||
            notes: None,
 | 
					            notes: None,
 | 
				
			||||||
            trip_type: None,
 | 
					            trip_type: None,
 | 
				
			||||||
            always_show: false,
 | 
					 | 
				
			||||||
            is_locked: false,
 | 
					            is_locked: false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -506,7 +518,6 @@ mod test {
 | 
				
			|||||||
            max_people: 10,
 | 
					            max_people: 10,
 | 
				
			||||||
            notes: None,
 | 
					            notes: None,
 | 
				
			||||||
            trip_type: Some(1),
 | 
					            trip_type: Some(1),
 | 
				
			||||||
            always_show: false,
 | 
					 | 
				
			||||||
            is_locked: false,
 | 
					            is_locked: false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert!(Trip::update_own(&pool, &update).await.is_ok());
 | 
					        assert!(Trip::update_own(&pool, &update).await.is_ok());
 | 
				
			||||||
@@ -535,7 +546,6 @@ mod test {
 | 
				
			|||||||
            max_people: 10,
 | 
					            max_people: 10,
 | 
				
			||||||
            notes: None,
 | 
					            notes: None,
 | 
				
			||||||
            trip_type: None,
 | 
					            trip_type: None,
 | 
				
			||||||
            always_show: false,
 | 
					 | 
				
			||||||
            is_locked: false,
 | 
					            is_locked: false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert!(Trip::update_own(&pool, &update).await.is_err());
 | 
					        assert!(Trip::update_own(&pool, &update).await.is_err());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
use crate::model::user::User;
 | 
					use crate::model::user::User;
 | 
				
			||||||
use chrono::NaiveDate;
 | 
					use chrono::{Local, NaiveDate};
 | 
				
			||||||
use rocket::FromForm;
 | 
					use rocket::FromForm;
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use sqlx::{FromRow, SqlitePool};
 | 
					use sqlx::{FromRow, SqlitePool};
 | 
				
			||||||
@@ -33,7 +33,6 @@ pub struct TripDetailsToAdd<'r> {
 | 
				
			|||||||
    pub notes: Option<&'r str>,
 | 
					    pub notes: Option<&'r str>,
 | 
				
			||||||
    pub trip_type: Option<i64>,
 | 
					    pub trip_type: Option<i64>,
 | 
				
			||||||
    pub allow_guests: bool,
 | 
					    pub allow_guests: bool,
 | 
				
			||||||
    pub always_show: bool,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl TripDetails {
 | 
					impl TripDetails {
 | 
				
			||||||
@@ -59,6 +58,24 @@ WHERE id like ?
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn date(&self) -> NaiveDate {
 | 
				
			||||||
 | 
					        NaiveDate::parse_from_str(&self.day, "%Y-%m-%d").unwrap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) async fn user_sees_trip(&self, db: &SqlitePool, user: &User) -> bool {
 | 
				
			||||||
 | 
					        let today = Local::now().date_naive();
 | 
				
			||||||
 | 
					        let day_diff = self.date() - today;
 | 
				
			||||||
 | 
					        let day_diff = day_diff.num_days();
 | 
				
			||||||
 | 
					        if day_diff < 0 {
 | 
				
			||||||
 | 
					            // tripdetails is in past
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if day_diff <= user.amount_days_to_show(db).await {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.always_show
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn find_by_startingdatetime(
 | 
					    pub async fn find_by_startingdatetime(
 | 
				
			||||||
        db: &SqlitePool,
 | 
					        db: &SqlitePool,
 | 
				
			||||||
        day: String,
 | 
					        day: String,
 | 
				
			||||||
@@ -77,7 +94,7 @@ WHERE day = ? AND planned_starting_time = ?
 | 
				
			|||||||
        .await.unwrap()
 | 
					        .await.unwrap()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn cancelled(&self, db: &SqlitePool) -> bool {
 | 
					    pub fn cancelled(&self) -> bool {
 | 
				
			||||||
        self.max_people == 0
 | 
					        self.max_people == 0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,7 +106,7 @@ WHERE day = ? AND planned_starting_time = ?
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.cancelled(db) {
 | 
					        if self.cancelled() {
 | 
				
			||||||
            // Cox cancelled event, thus it's probably bad weather. Don't bother with sending
 | 
					            // Cox cancelled event, thus it's probably bad weather. Don't bother with sending
 | 
				
			||||||
            // notifications
 | 
					            // notifications
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@@ -146,14 +163,13 @@ WHERE day = ? AND planned_starting_time = ?
 | 
				
			|||||||
    /// Creates a new entry in `trip_details` and returns its id.
 | 
					    /// Creates a new entry in `trip_details` and returns its id.
 | 
				
			||||||
    pub async fn create(db: &SqlitePool, tripdetails: TripDetailsToAdd<'_>) -> i64 {
 | 
					    pub async fn create(db: &SqlitePool, tripdetails: TripDetailsToAdd<'_>) -> i64 {
 | 
				
			||||||
        let query = sqlx::query!(
 | 
					        let query = sqlx::query!(
 | 
				
			||||||
            "INSERT INTO trip_details(planned_starting_time, max_people, day, notes, allow_guests, trip_type_id, always_show) VALUES(?, ?, ?, ?, ?, ?, ?)" ,
 | 
					            "INSERT INTO trip_details(planned_starting_time, max_people, day, notes, allow_guests, trip_type_id) VALUES(?, ?, ?, ?, ?, ?)" ,
 | 
				
			||||||
            tripdetails.planned_starting_time,
 | 
					            tripdetails.planned_starting_time,
 | 
				
			||||||
            tripdetails.max_people,
 | 
					            tripdetails.max_people,
 | 
				
			||||||
            tripdetails.day,
 | 
					            tripdetails.day,
 | 
				
			||||||
            tripdetails.notes,
 | 
					            tripdetails.notes,
 | 
				
			||||||
            tripdetails.allow_guests,
 | 
					            tripdetails.allow_guests,
 | 
				
			||||||
            tripdetails.trip_type,
 | 
					            tripdetails.trip_type,
 | 
				
			||||||
            tripdetails.always_show
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .execute(db)
 | 
					        .execute(db)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
@@ -161,6 +177,17 @@ WHERE day = ? AND planned_starting_time = ?
 | 
				
			|||||||
        query.last_insert_rowid()
 | 
					        query.last_insert_rowid()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn set_always_show(&self, db: &SqlitePool, value: bool) {
 | 
				
			||||||
 | 
					        sqlx::query!(
 | 
				
			||||||
 | 
					            "UPDATE trip_details SET always_show = ? WHERE id = ?",
 | 
				
			||||||
 | 
					            value,
 | 
				
			||||||
 | 
					            self.id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .execute(db)
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .unwrap(); //Okay, as planned_event can only be created with proper DB backing
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn is_full(&self, db: &SqlitePool) -> bool {
 | 
					    pub async fn is_full(&self, db: &SqlitePool) -> bool {
 | 
				
			||||||
        let amount_currently_registered = sqlx::query!(
 | 
					        let amount_currently_registered = sqlx::query!(
 | 
				
			||||||
            "SELECT COUNT(*) as count FROM user_trip WHERE trip_details_id = ?",
 | 
					            "SELECT COUNT(*) as count FROM user_trip WHERE trip_details_id = ?",
 | 
				
			||||||
@@ -309,7 +336,6 @@ mod test {
 | 
				
			|||||||
                    notes: None,
 | 
					                    notes: None,
 | 
				
			||||||
                    allow_guests: false,
 | 
					                    allow_guests: false,
 | 
				
			||||||
                    trip_type: None,
 | 
					                    trip_type: None,
 | 
				
			||||||
                    always_show: false
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .await,
 | 
					            .await,
 | 
				
			||||||
@@ -325,7 +351,6 @@ mod test {
 | 
				
			|||||||
                    notes: None,
 | 
					                    notes: None,
 | 
				
			||||||
                    allow_guests: false,
 | 
					                    allow_guests: false,
 | 
				
			||||||
                    trip_type: None,
 | 
					                    trip_type: None,
 | 
				
			||||||
                    always_show: false
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .await,
 | 
					            .await,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -450,6 +450,12 @@ ASKÖ Ruderverein Donau Linz", self.name),
 | 
				
			|||||||
        false
 | 
					        false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn allowed_to_update_always_show_trip(&self, db: &SqlitePool) -> bool {
 | 
				
			||||||
 | 
					        AllowedToUpdateTripToAlwaysBeShownUser::new(db, self.clone())
 | 
				
			||||||
 | 
					            .await
 | 
				
			||||||
 | 
					            .is_some()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn has_membership_pdf(&self, db: &SqlitePool) -> bool {
 | 
					    pub async fn has_membership_pdf(&self, db: &SqlitePool) -> bool {
 | 
				
			||||||
        match sqlx::query_scalar!("SELECT membership_pdf FROM user WHERE id = ?", self.id)
 | 
					        match sqlx::query_scalar!("SELECT membership_pdf FROM user WHERE id = ?", self.id)
 | 
				
			||||||
            .fetch_one(db)
 | 
					            .fetch_one(db)
 | 
				
			||||||
@@ -879,18 +885,32 @@ ORDER BY last_access DESC
 | 
				
			|||||||
        days
 | 
					        days
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn amount_days_to_show(&self, db: &SqlitePool) -> i64 {
 | 
					    pub(crate) async fn amount_days_to_show(&self, db: &SqlitePool) -> i64 {
 | 
				
			||||||
        if self.has_role(db, "cox").await {
 | 
					        if self.has_role(db, "cox").await {
 | 
				
			||||||
            let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 12, 31).unwrap(); //Ok,
 | 
					            let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 12, 31).unwrap(); //Ok,
 | 
				
			||||||
                                                                                             //december
 | 
					                                                                                             //december
 | 
				
			||||||
                                                                                             //has 31
 | 
					                                                                                             //has 31
 | 
				
			||||||
                                                                                             //days
 | 
					                                                                                             //days
 | 
				
			||||||
            end_of_year
 | 
					            let days_left_in_year = end_of_year
 | 
				
			||||||
 | 
					                .signed_duration_since(Local::now().date_naive())
 | 
				
			||||||
 | 
					                .num_days()
 | 
				
			||||||
 | 
					                + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if days_left_in_year <= 31 {
 | 
				
			||||||
 | 
					                let end_of_next_year =
 | 
				
			||||||
 | 
					                    NaiveDate::from_ymd_opt(Local::now().year() + 1, 12, 31).unwrap(); //Ok,
 | 
				
			||||||
 | 
					                                                                                       //december
 | 
				
			||||||
 | 
					                                                                                       //has 31
 | 
				
			||||||
 | 
					                                                                                       //days
 | 
				
			||||||
 | 
					                end_of_next_year
 | 
				
			||||||
                    .signed_duration_since(Local::now().date_naive())
 | 
					                    .signed_duration_since(Local::now().date_naive())
 | 
				
			||||||
                    .num_days()
 | 
					                    .num_days()
 | 
				
			||||||
                    + 1
 | 
					                    + 1
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
            6
 | 
					                days_left_in_year
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            10
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1014,6 +1034,7 @@ special_user!(VorstandUser, +"Vorstand");
 | 
				
			|||||||
special_user!(EventUser, +"manage_events");
 | 
					special_user!(EventUser, +"manage_events");
 | 
				
			||||||
special_user!(AllowedToEditPaymentStatusUser, +"kassier", +"admin");
 | 
					special_user!(AllowedToEditPaymentStatusUser, +"kassier", +"admin");
 | 
				
			||||||
special_user!(ManageUserUser, +"admin", +"schriftfuehrer");
 | 
					special_user!(ManageUserUser, +"admin", +"schriftfuehrer");
 | 
				
			||||||
 | 
					special_user!(AllowedToUpdateTripToAlwaysBeShownUser, +"admin");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
 | 
					#[derive(FromRow, Serialize, Deserialize, Clone, Debug)]
 | 
				
			||||||
pub struct UserWithRolesAndMembershipPdf {
 | 
					pub struct UserWithRolesAndMembershipPdf {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,10 @@ impl UserTrip {
 | 
				
			|||||||
            return Err(UserTripError::GuestNotAllowedForThisEvent);
 | 
					            return Err(UserTripError::GuestNotAllowedForThisEvent);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if !trip_details.user_sees_trip(db, user).await {
 | 
				
			||||||
 | 
					            return Err(UserTripError::NotVisibleToUser);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //TODO: Check if user sees the event (otherwise she could forge trip_details_id)
 | 
					        //TODO: Check if user sees the event (otherwise she could forge trip_details_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let is_cox = trip_details.user_is_cox(db, user).await;
 | 
					        let is_cox = trip_details.user_is_cox(db, user).await;
 | 
				
			||||||
@@ -96,6 +100,10 @@ impl UserTrip {
 | 
				
			|||||||
            return Err(UserTripDeleteError::DetailsLocked);
 | 
					            return Err(UserTripDeleteError::DetailsLocked);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if !trip_details.user_sees_trip(db, user).await {
 | 
				
			||||||
 | 
					            return Err(UserTripDeleteError::NotVisibleToUser);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(name) = name {
 | 
					        if let Some(name) = name {
 | 
				
			||||||
            if !trip_details.user_allowed_to_change(db, user).await {
 | 
					            if !trip_details.user_allowed_to_change(db, user).await {
 | 
				
			||||||
                return Err(UserTripDeleteError::NotAllowedToDeleteGuest);
 | 
					                return Err(UserTripDeleteError::NotAllowedToDeleteGuest);
 | 
				
			||||||
@@ -137,6 +145,7 @@ pub enum UserTripError {
 | 
				
			|||||||
    CantRegisterAtOwnEvent,
 | 
					    CantRegisterAtOwnEvent,
 | 
				
			||||||
    GuestNotAllowedForThisEvent,
 | 
					    GuestNotAllowedForThisEvent,
 | 
				
			||||||
    NotAllowedToAddGuest,
 | 
					    NotAllowedToAddGuest,
 | 
				
			||||||
 | 
					    NotVisibleToUser,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
@@ -144,6 +153,7 @@ pub enum UserTripDeleteError {
 | 
				
			|||||||
    DetailsLocked,
 | 
					    DetailsLocked,
 | 
				
			||||||
    GuestNotParticipating,
 | 
					    GuestNotParticipating,
 | 
				
			||||||
    NotAllowedToDeleteGuest,
 | 
					    NotAllowedToDeleteGuest,
 | 
				
			||||||
 | 
					    NotVisibleToUser,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ use crate::model::{
 | 
				
			|||||||
struct AddEventForm<'r> {
 | 
					struct AddEventForm<'r> {
 | 
				
			||||||
    name: &'r str,
 | 
					    name: &'r str,
 | 
				
			||||||
    planned_amount_cox: i32,
 | 
					    planned_amount_cox: i32,
 | 
				
			||||||
 | 
					    always_show: bool,
 | 
				
			||||||
    tripdetails: TripDetailsToAdd<'r>,
 | 
					    tripdetails: TripDetailsToAdd<'r>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +35,14 @@ async fn create(
 | 
				
			|||||||
                                                                                    //just created
 | 
					                                                                                    //just created
 | 
				
			||||||
                                                                                    //the object
 | 
					                                                                                    //the object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Event::create(db, data.name, data.planned_amount_cox, &trip_details).await;
 | 
					    Event::create(
 | 
				
			||||||
 | 
					        db,
 | 
				
			||||||
 | 
					        data.name,
 | 
				
			||||||
 | 
					        data.planned_amount_cox,
 | 
				
			||||||
 | 
					        data.always_show,
 | 
				
			||||||
 | 
					        &trip_details,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Flash::success(Redirect::to("/planned"), "Event hinzugefügt")
 | 
					    Flash::success(Redirect::to("/planned"), "Event hinzugefügt")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -374,7 +374,7 @@ async fn create_scheckbuch(
 | 
				
			|||||||
    if mail.parse::<Address>().is_err() {
 | 
					    if mail.parse::<Address>().is_err() {
 | 
				
			||||||
        return Flash::error(
 | 
					        return Flash::error(
 | 
				
			||||||
            Redirect::to("/admin/user/scheckbuch"),
 | 
					            Redirect::to("/admin/user/scheckbuch"),
 | 
				
			||||||
            format!("Keine gültige Mailadresse"),
 | 
					            "Keine gültige Mailadresse".to_string(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -383,9 +383,8 @@ async fn create_scheckbuch(
 | 
				
			|||||||
    if User::find_by_name(db, name).await.is_some() {
 | 
					    if User::find_by_name(db, name).await.is_some() {
 | 
				
			||||||
        return Flash::error(
 | 
					        return Flash::error(
 | 
				
			||||||
            Redirect::to("/admin/user/scheckbuch"),
 | 
					            Redirect::to("/admin/user/scheckbuch"),
 | 
				
			||||||
            format!(
 | 
					 | 
				
			||||||
            "Kann kein Scheckbuch erstellen, der Name wird bereits von einem User verwendet"
 | 
					            "Kann kein Scheckbuch erstellen, der Name wird bereits von einem User verwendet"
 | 
				
			||||||
            ),
 | 
					                .to_string(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -418,14 +417,14 @@ async fn schnupper_to_scheckbuch(
 | 
				
			|||||||
    let Some(user) = User::find_by_id(db, id).await else {
 | 
					    let Some(user) = User::find_by_id(db, id).await else {
 | 
				
			||||||
        return Flash::error(
 | 
					        return Flash::error(
 | 
				
			||||||
            Redirect::to("/admin/schnupper"),
 | 
					            Redirect::to("/admin/schnupper"),
 | 
				
			||||||
            format!("user id not found"),
 | 
					            "user id not found".to_string(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if !user.has_role(db, "schnupperant").await {
 | 
					    if !user.has_role(db, "schnupperant").await {
 | 
				
			||||||
        return Flash::error(
 | 
					        return Flash::error(
 | 
				
			||||||
            Redirect::to("/admin/schnupper"),
 | 
					            Redirect::to("/admin/schnupper"),
 | 
				
			||||||
            format!("kein schnupperant..."),
 | 
					            "kein schnupperant...".to_string(),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ use crate::model::{
 | 
				
			|||||||
    log::Log,
 | 
					    log::Log,
 | 
				
			||||||
    trip::{self, CoxHelpError, Trip, TripDeleteError, TripHelpDeleteError, TripUpdateError},
 | 
					    trip::{self, CoxHelpError, Trip, TripDeleteError, TripHelpDeleteError, TripUpdateError},
 | 
				
			||||||
    tripdetails::{TripDetails, TripDetailsToAdd},
 | 
					    tripdetails::{TripDetails, TripDetailsToAdd},
 | 
				
			||||||
    user::CoxUser,
 | 
					    user::{AllowedToUpdateTripToAlwaysBeShownUser, CoxUser},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[post("/trip", data = "<data>")]
 | 
					#[post("/trip", data = "<data>")]
 | 
				
			||||||
@@ -42,7 +42,6 @@ struct EditTripForm<'r> {
 | 
				
			|||||||
    max_people: i32,
 | 
					    max_people: i32,
 | 
				
			||||||
    notes: Option<&'r str>,
 | 
					    notes: Option<&'r str>,
 | 
				
			||||||
    trip_type: Option<i64>,
 | 
					    trip_type: Option<i64>,
 | 
				
			||||||
    always_show: bool,
 | 
					 | 
				
			||||||
    is_locked: bool,
 | 
					    is_locked: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,7 +59,6 @@ async fn update(
 | 
				
			|||||||
            max_people: data.max_people,
 | 
					            max_people: data.max_people,
 | 
				
			||||||
            notes: data.notes,
 | 
					            notes: data.notes,
 | 
				
			||||||
            trip_type: data.trip_type,
 | 
					            trip_type: data.trip_type,
 | 
				
			||||||
            always_show: data.always_show,
 | 
					 | 
				
			||||||
            is_locked: data.is_locked,
 | 
					            is_locked: data.is_locked,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        match Trip::update_own(db, &update).await {
 | 
					        match Trip::update_own(db, &update).await {
 | 
				
			||||||
@@ -80,6 +78,23 @@ async fn update(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[get("/trip/<trip_id>/toggle-always-show")]
 | 
				
			||||||
 | 
					async fn toggle_always_show(
 | 
				
			||||||
 | 
					    db: &State<SqlitePool>,
 | 
				
			||||||
 | 
					    trip_id: i64,
 | 
				
			||||||
 | 
					    _user: AllowedToUpdateTripToAlwaysBeShownUser,
 | 
				
			||||||
 | 
					) -> Flash<Redirect> {
 | 
				
			||||||
 | 
					    if let Some(trip) = Trip::find_by_id(db, trip_id).await {
 | 
				
			||||||
 | 
					        trip.toggle_always_show(db).await;
 | 
				
			||||||
 | 
					        Flash::success(
 | 
				
			||||||
 | 
					            Redirect::to("/planned"),
 | 
				
			||||||
 | 
					            "'Immer anzeigen' erfolgreich gesetzt!",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        Flash::error(Redirect::to("/planned"), "Ausfahrt gibt's nicht")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[get("/join/<planned_event_id>")]
 | 
					#[get("/join/<planned_event_id>")]
 | 
				
			||||||
async fn join(db: &State<SqlitePool>, planned_event_id: i64, cox: CoxUser) -> Flash<Redirect> {
 | 
					async fn join(db: &State<SqlitePool>, planned_event_id: i64, cox: CoxUser) -> Flash<Redirect> {
 | 
				
			||||||
    if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await {
 | 
					    if let Some(planned_event) = Event::find_by_id(db, planned_event_id).await {
 | 
				
			||||||
@@ -164,12 +179,19 @@ async fn remove(db: &State<SqlitePool>, planned_event_id: i64, cox: CoxUser) ->
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn routes() -> Vec<Route> {
 | 
					pub fn routes() -> Vec<Route> {
 | 
				
			||||||
    routes![create, join, remove, remove_trip, update]
 | 
					    routes![
 | 
				
			||||||
 | 
					        create,
 | 
				
			||||||
 | 
					        join,
 | 
				
			||||||
 | 
					        remove,
 | 
				
			||||||
 | 
					        remove_trip,
 | 
				
			||||||
 | 
					        update,
 | 
				
			||||||
 | 
					        toggle_always_show
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use chrono::NaiveDate;
 | 
					    use chrono::{Local, NaiveDate};
 | 
				
			||||||
    use rocket::{
 | 
					    use rocket::{
 | 
				
			||||||
        http::{ContentType, Status},
 | 
					        http::{ContentType, Status},
 | 
				
			||||||
        local::asynchronous::Client,
 | 
					        local::asynchronous::Client,
 | 
				
			||||||
@@ -230,7 +252,9 @@ mod test {
 | 
				
			|||||||
    fn test_trip_update_succ() {
 | 
					    fn test_trip_update_succ() {
 | 
				
			||||||
        let db = testdb!();
 | 
					        let db = testdb!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let trip = &Trip::get_for_day(&db, NaiveDate::from_ymd_opt(1970, 01, 02).unwrap()).await[0];
 | 
					        let tomorrow = Local::now().date_naive() + chrono::Duration::days(1);
 | 
				
			||||||
 | 
					        println!("{tomorrow}");
 | 
				
			||||||
 | 
					        let trip = &Trip::get_for_day(&db, tomorrow).await[0];
 | 
				
			||||||
        assert_eq!(1, trip.trip.max_people);
 | 
					        assert_eq!(1, trip.trip.max_people);
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            "trip_details for trip from cox",
 | 
					            "trip_details for trip from cox",
 | 
				
			||||||
@@ -266,7 +290,8 @@ mod test {
 | 
				
			|||||||
            "7:successAusfahrt erfolgreich aktualisiert."
 | 
					            "7:successAusfahrt erfolgreich aktualisiert."
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let trip = &Trip::get_for_day(&db, NaiveDate::from_ymd_opt(1970, 01, 02).unwrap()).await[0];
 | 
					        let tomorrow = Local::now().date_naive() + chrono::Duration::days(1);
 | 
				
			||||||
 | 
					        let trip = &Trip::get_for_day(&db, tomorrow).await[0];
 | 
				
			||||||
        assert_eq!(12, trip.trip.max_people);
 | 
					        assert_eq!(12, trip.trip.max_people);
 | 
				
			||||||
        assert_eq!("my-new-notes", &trip.trip.notes.clone().unwrap());
 | 
					        assert_eq!("my-new-notes", &trip.trip.notes.clone().unwrap());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -306,7 +331,9 @@ mod test {
 | 
				
			|||||||
    fn test_trip_update_wrong_cox() {
 | 
					    fn test_trip_update_wrong_cox() {
 | 
				
			||||||
        let db = testdb!();
 | 
					        let db = testdb!();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let trip = &Trip::get_for_day(&db, NaiveDate::from_ymd_opt(1970, 01, 02).unwrap()).await[0];
 | 
					        let tomorrow = Local::now().date_naive() + chrono::Duration::days(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let trip = &Trip::get_for_day(&db, tomorrow).await[0];
 | 
				
			||||||
        assert_eq!(1, trip.trip.max_people);
 | 
					        assert_eq!(1, trip.trip.max_people);
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            "trip_details for trip from cox",
 | 
					            "trip_details for trip from cox",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -131,13 +131,13 @@ async fn new_blogpost(
 | 
				
			|||||||
    blogpost: Form<NewBlogpostForm<'_>>,
 | 
					    blogpost: Form<NewBlogpostForm<'_>>,
 | 
				
			||||||
    config: &State<Config>,
 | 
					    config: &State<Config>,
 | 
				
			||||||
) -> String {
 | 
					) -> String {
 | 
				
			||||||
    if blogpost.pw == &config.wordpress_key {
 | 
					    if blogpost.pw == config.wordpress_key {
 | 
				
			||||||
        let member = Role::find_by_name(&db, "Donau Linz").await.unwrap();
 | 
					        let member = Role::find_by_name(db, "Donau Linz").await.unwrap();
 | 
				
			||||||
        Notification::create_for_role(
 | 
					        Notification::create_for_role(
 | 
				
			||||||
            db,
 | 
					            db,
 | 
				
			||||||
            &member,
 | 
					            &member,
 | 
				
			||||||
            &urlencoding::decode(blogpost.article_title).expect("UTF-8"),
 | 
					            &urlencoding::decode(blogpost.article_title).expect("UTF-8"),
 | 
				
			||||||
            &format!("Neuer Blogpost"),
 | 
					            "Neuer Blogpost",
 | 
				
			||||||
            Some(blogpost.article_url),
 | 
					            Some(blogpost.article_url),
 | 
				
			||||||
            None,
 | 
					            None,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -160,9 +160,9 @@ async fn blogpost_unpublished(
 | 
				
			|||||||
    blogpost: Form<BlogpostUnpublishedForm<'_>>,
 | 
					    blogpost: Form<BlogpostUnpublishedForm<'_>>,
 | 
				
			||||||
    config: &State<Config>,
 | 
					    config: &State<Config>,
 | 
				
			||||||
) -> String {
 | 
					) -> String {
 | 
				
			||||||
    if blogpost.pw == &config.wordpress_key {
 | 
					    if blogpost.pw == config.wordpress_key {
 | 
				
			||||||
        Notification::delete_by_link(
 | 
					        Notification::delete_by_link(
 | 
				
			||||||
            &db,
 | 
					            db,
 | 
				
			||||||
            &urlencoding::decode(blogpost.article_url).expect("UTF-8"),
 | 
					            &urlencoding::decode(blogpost.article_url).expect("UTF-8"),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .await;
 | 
					        .await;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,10 @@ async fn index(
 | 
				
			|||||||
        context.insert("flash", &msg.into_inner());
 | 
					        context.insert("flash", &msg.into_inner());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context.insert(
 | 
				
			||||||
 | 
					        "allowed_to_update_always_show_trip",
 | 
				
			||||||
 | 
					        &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("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);
 | 
				
			||||||
@@ -99,6 +103,10 @@ async fn join(
 | 
				
			|||||||
            Redirect::to("/planned"),
 | 
					            Redirect::to("/planned"),
 | 
				
			||||||
            "Du darfst keine Gäste hinzufügen.",
 | 
					            "Du darfst keine Gäste hinzufügen.",
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					        Err(UserTripError::NotVisibleToUser) => Flash::error(
 | 
				
			||||||
 | 
					            Redirect::to("/planned"),
 | 
				
			||||||
 | 
					            "Du kannst dich nicht registrieren, weil du die Ausfahrt gar nicht sehen solltest.",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
        Err(UserTripError::DetailsLocked) => Flash::error(
 | 
					        Err(UserTripError::DetailsLocked) => Flash::error(
 | 
				
			||||||
            Redirect::to("/planned"),
 | 
					            Redirect::to("/planned"),
 | 
				
			||||||
            "Die Bootseinteilung wurde bereits gemacht. Wenn du noch mitrudern möchtest, frag bitte bei einer angemeldeten Steuerperson nach, ob das noch möglich ist.",
 | 
					            "Die Bootseinteilung wurde bereits gemacht. Wenn du noch mitrudern möchtest, frag bitte bei einer angemeldeten Steuerperson nach, ob das noch möglich ist.",
 | 
				
			||||||
@@ -147,6 +155,10 @@ async fn remove_guest(
 | 
				
			|||||||
        Err(UserTripDeleteError::GuestNotParticipating) => {
 | 
					        Err(UserTripDeleteError::GuestNotParticipating) => {
 | 
				
			||||||
            Flash::error(Redirect::to("/planned"), "Gast nicht angemeldet.")
 | 
					            Flash::error(Redirect::to("/planned"), "Gast nicht angemeldet.")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        Err(UserTripDeleteError::NotVisibleToUser) => Flash::error(
 | 
				
			||||||
 | 
					            Redirect::to("/planned"),
 | 
				
			||||||
 | 
					            "Du kannst dich nicht abmelden, weil du die Ausfahrt gar nicht sehen solltest.",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
        Err(UserTripDeleteError::NotAllowedToDeleteGuest) => Flash::error(
 | 
					        Err(UserTripDeleteError::NotAllowedToDeleteGuest) => Flash::error(
 | 
				
			||||||
            Redirect::to("/planned"),
 | 
					            Redirect::to("/planned"),
 | 
				
			||||||
            "Keine Berechtigung um den Gast zu entfernen.",
 | 
					            "Keine Berechtigung um den Gast zu entfernen.",
 | 
				
			||||||
@@ -191,6 +203,18 @@ async fn remove(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            Flash::error(Redirect::to("/planned"), "Das Boot ist bereits eingeteilt. Bitte kontaktiere den Schiffsführer (Nummern siehe Signalgruppe) falls du dich doch abmelden willst.")
 | 
					            Flash::error(Redirect::to("/planned"), "Das Boot ist bereits eingeteilt. Bitte kontaktiere den Schiffsführer (Nummern siehe Signalgruppe) falls du dich doch abmelden willst.")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        Err(UserTripDeleteError::NotVisibleToUser) => {
 | 
				
			||||||
 | 
					            Log::create(
 | 
				
			||||||
 | 
					                db,
 | 
				
			||||||
 | 
					                format!(
 | 
				
			||||||
 | 
					                    "User {} tried to unregister for not-yet-seeable trip_details.id={}",
 | 
				
			||||||
 | 
					                    user.name, trip_details_id
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Flash::error(Redirect::to("/planned"), "Abmeldung nicht möglich, da du dieses Event eigentlich gar nicht sehen solltest...")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        Err(_) => {
 | 
					        Err(_) => {
 | 
				
			||||||
            panic!("Not possible to be here");
 | 
					            panic!("Not possible to be here");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@
 | 
				
			|||||||
        {{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', required=true, min='0') }}
 | 
					        {{ macros::input(label='Anzahl Steuerleute', name='planned_amount_cox', type='number', required=true, min='0') }}
 | 
				
			||||||
        {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='tripdetails.max_people', type='number', required=true, min='0') }}
 | 
					        {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='tripdetails.max_people', type='number', required=true, min='0') }}
 | 
				
			||||||
        {{ macros::checkbox(label='Scheckbuch-Anmeldungen erlauben', name='tripdetails.allow_guests') }}
 | 
					        {{ macros::checkbox(label='Scheckbuch-Anmeldungen erlauben', name='tripdetails.allow_guests') }}
 | 
				
			||||||
        {{ macros::checkbox(label='Immer anzeigen', name='tripdetails.always_show') }}
 | 
					        {{ macros::checkbox(label='Immer anzeigen', name='always_show') }}
 | 
				
			||||||
        {{ macros::input(label='Anmerkungen', name='tripdetails.notes', type='input') }}
 | 
					        {{ macros::input(label='Anmerkungen', name='tripdetails.notes', type='input') }}
 | 
				
			||||||
        {{ macros::select(label='Typ', data=trip_types, name='tripdetails.trip_type', default='Reguläre Ausfahrt') }}
 | 
					        {{ macros::select(label='Typ', data=trip_types, name='tripdetails.trip_type', default='Reguläre Ausfahrt') }}
 | 
				
			||||||
        <input value="Erstellen" class="w-full btn btn-primary" type="submit" />
 | 
					        <input value="Erstellen" class="w-full btn btn-primary" type="submit" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,6 @@
 | 
				
			|||||||
        {{ macros::input(label='Startzeit (zB "10:00")', name='planned_starting_time', type='time', required=true) }}
 | 
					        {{ macros::input(label='Startzeit (zB "10:00")', name='planned_starting_time', type='time', required=true) }}
 | 
				
			||||||
        {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='max_people', type='number', required=true, min='0') }}
 | 
					        {{ macros::input(label='Anzahl Ruderer (ohne Steuerperson)', name='max_people', type='number', required=true, min='0') }}
 | 
				
			||||||
        {{ macros::checkbox(label='Scheckbuch-Anmeldungen erlauben', name='allow_guests') }}
 | 
					        {{ macros::checkbox(label='Scheckbuch-Anmeldungen erlauben', name='allow_guests') }}
 | 
				
			||||||
        {{ macros::checkbox(label='Immer anzeigen', name='always_show') }}
 | 
					 | 
				
			||||||
        {{ macros::input(label='Anmerkungen', name='notes', type='input') }}
 | 
					        {{ macros::input(label='Anmerkungen', name='notes', type='input') }}
 | 
				
			||||||
        {{ macros::select(label='Typ', data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }}
 | 
					        {{ macros::select(label='Typ', data=trip_types, name='trip_type', default='Reguläre Ausfahrt') }}
 | 
				
			||||||
        <input value="Erstellen" class="w-full btn btn-primary" type="submit" />
 | 
					        <input value="Erstellen" class="w-full btn btn-primary" type="submit" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,8 @@
 | 
				
			|||||||
                    {% endif %}
 | 
					                    {% endif %}
 | 
				
			||||||
                {% endfor %}
 | 
					                {% endfor %}
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            <div id="{{ day.day| date(format="%Y-%m-%d") }}" class="bg-white dark:bg-primary-900 rounded-md flex justify-between flex-col shadow reset-js"
 | 
					            <div id="{{ day.day| date(format="%Y-%m-%d") }}"
 | 
				
			||||||
 | 
					                 class="bg-white dark:bg-primary-900 rounded-md flex justify-between flex-col shadow reset-js"
 | 
				
			||||||
                 style="min-height: 10rem"
 | 
					                 style="min-height: 10rem"
 | 
				
			||||||
                 data-trips="{{ amount_trips }}"
 | 
					                 data-trips="{{ amount_trips }}"
 | 
				
			||||||
                 data-month="{{ day.day| date(format='%m') }}"
 | 
					                 data-month="{{ day.day| date(format='%m') }}"
 | 
				
			||||||
@@ -346,7 +347,6 @@
 | 
				
			|||||||
                                                <form action="/cox/trip/{{ trip.id }}" method="post" class="grid gap-3">
 | 
					                                                <form action="/cox/trip/{{ trip.id }}" method="post" class="grid gap-3">
 | 
				
			||||||
                                                    {{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min=trip.rower | length) }}
 | 
					                                                    {{ macros::input(label='Anzahl Ruderer', name='max_people', type='number', required=true, value=trip.max_people, min=trip.rower | length) }}
 | 
				
			||||||
                                                    {{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }}
 | 
					                                                    {{ macros::input(label='Anmerkungen', name='notes', type='input', value=trip.notes) }}
 | 
				
			||||||
                                                    {{ macros::checkbox(label='Immer anzeigen', name='always_show', id=trip.id,checked=trip.always_show) }}
 | 
					 | 
				
			||||||
                                                    {{ macros::checkbox(label='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }}
 | 
					                                                    {{ macros::checkbox(label='Gesperrt', name='is_locked', id=trip.id,checked=trip.is_locked) }}
 | 
				
			||||||
                                                    {{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }}
 | 
					                                                    {{ macros::select(label='Typ', name='trip_type', data=trip_types, default='Reguläre Ausfahrt', selected_id=trip.trip_type_id) }}
 | 
				
			||||||
                                                    <input value="Speichern" class="btn btn-primary" type="submit" />
 | 
					                                                    <input value="Speichern" class="btn btn-primary" type="submit" />
 | 
				
			||||||
@@ -369,7 +369,6 @@
 | 
				
			|||||||
                                                        <form action="/cox/trip/{{ trip.id }}" method="post" class="grid">
 | 
					                                                        <form action="/cox/trip/{{ trip.id }}" method="post" class="grid">
 | 
				
			||||||
                                                            {{ macros::input(label='', name='max_people', type='hidden', value=0) }}
 | 
					                                                            {{ macros::input(label='', name='max_people', type='hidden', value=0) }}
 | 
				
			||||||
                                                            {{ macros::input(label='Grund der Absage', name='notes', type='input', value='') }}
 | 
					                                                            {{ macros::input(label='Grund der Absage', name='notes', type='input', value='') }}
 | 
				
			||||||
                                                            {{ macros::input(label='', name='always_show', type='hidden', value=trip.always_show) }}
 | 
					 | 
				
			||||||
                                                            {{ macros::input(label='', name='is_locked', type='hidden', value=trip.is_locked) }}
 | 
					                                                            {{ macros::input(label='', name='is_locked', type='hidden', value=trip.is_locked) }}
 | 
				
			||||||
                                                            {{ macros::input(label='', name='trip_type', type='hidden', value=trip.trip_type_id) }}
 | 
					                                                            {{ macros::input(label='', name='trip_type', type='hidden', value=trip.trip_type_id) }}
 | 
				
			||||||
                                                            <input value="Ausfahrt absagen" class="btn btn-alert" type="submit" />
 | 
					                                                            <input value="Ausfahrt absagen" class="btn btn-alert" type="submit" />
 | 
				
			||||||
@@ -379,6 +378,20 @@
 | 
				
			|||||||
                                            {% endif %}
 | 
					                                            {% endif %}
 | 
				
			||||||
                                        {% endif %}
 | 
					                                        {% endif %}
 | 
				
			||||||
                                        {# --- END Edit Form --- #}
 | 
					                                        {# --- END Edit Form --- #}
 | 
				
			||||||
 | 
					                                        {# --- START Admin Form --- #}
 | 
				
			||||||
 | 
					                                        {% if allowed_to_update_always_show_trip %}
 | 
				
			||||||
 | 
					                                            <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>
 | 
				
			||||||
 | 
					                                                <form action="/cox/trip/{{ trip.id }}/toggle-always-show"
 | 
				
			||||||
 | 
					                                                      method="get"
 | 
				
			||||||
 | 
					                                                      class="grid gap-3">
 | 
				
			||||||
 | 
					                                                    <input value="{% if trip.always_show %}Normal anzeigen{% else %}Immer anzeigen{% endif %}"
 | 
				
			||||||
 | 
					                                                           class="btn btn-primary"
 | 
				
			||||||
 | 
					                                                           type="submit" />
 | 
				
			||||||
 | 
					                                                </form>
 | 
				
			||||||
 | 
					                                            </div>
 | 
				
			||||||
 | 
					                                        {% endif %}
 | 
				
			||||||
 | 
					                                        {# --- END Admin Form --- #}
 | 
				
			||||||
                                    </div>
 | 
					                                    </div>
 | 
				
			||||||
                                </div>
 | 
					                                </div>
 | 
				
			||||||
                                {# --- END Sidebar Content --- #}
 | 
					                                {# --- END Sidebar Content --- #}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user