Merge pull request 'updates' (#715) from updates into main
Reviewed-on: #715
This commit is contained in:
commit
c7adea88ed
@ -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 --- #}
|
||||||
|
Loading…
Reference in New Issue
Block a user