only allow guests to register for specific events; don't even show them the other trips
This commit is contained in:
parent
5b06eaeebc
commit
bb4dba7bc9
@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS "trip_details" (
|
|||||||
"planned_starting_time" text NOT NULL,
|
"planned_starting_time" text NOT NULL,
|
||||||
"max_people" INTEGER NOT NULL,
|
"max_people" INTEGER NOT NULL,
|
||||||
"day" TEXT NOT NULL,
|
"day" TEXT NOT NULL,
|
||||||
|
"allow_guests" boolean NOT NULL default false,
|
||||||
"notes" TEXT,
|
"notes" TEXT,
|
||||||
"trip_type_id" INTEGER,
|
"trip_type_id" INTEGER,
|
||||||
FOREIGN KEY(trip_type_id) REFERENCES trip_type(id)
|
FOREIGN KEY(trip_type_id) REFERENCES trip_type(id)
|
||||||
@ -30,7 +31,6 @@ CREATE TABLE IF NOT EXISTS "planned_event" (
|
|||||||
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
"name" text NOT NULL,
|
"name" text NOT NULL,
|
||||||
"planned_amount_cox" INTEGER unsigned NOT NULL,
|
"planned_amount_cox" INTEGER unsigned NOT NULL,
|
||||||
"allow_guests" boolean NOT NULL default false,
|
|
||||||
"trip_details_id" INTEGER NOT NULL,
|
"trip_details_id" INTEGER NOT NULL,
|
||||||
"created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
FOREIGN KEY(trip_details_id) REFERENCES trip_details(id) ON DELETE CASCADE
|
FOREIGN KEY(trip_details_id) REFERENCES trip_details(id) ON DELETE CASCADE
|
||||||
|
@ -30,4 +30,21 @@ impl Day {
|
|||||||
trips: Trip::get_for_day(db, day).await,
|
trips: Trip::get_for_day(db, day).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub async fn new_guest(db: &SqlitePool, day: NaiveDate) -> Self {
|
||||||
|
let mut day = Self::new(db, day).await;
|
||||||
|
|
||||||
|
day.planned_events = day
|
||||||
|
.planned_events
|
||||||
|
.into_iter()
|
||||||
|
.filter(|e| e.planned_event.allow_guests)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
day.trips = day
|
||||||
|
.trips
|
||||||
|
.into_iter()
|
||||||
|
.filter(|t| t.trip.allow_guests)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
day
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,19 @@ pub struct PlannedEvent {
|
|||||||
pub id: i64,
|
pub id: i64,
|
||||||
name: String,
|
name: String,
|
||||||
planned_amount_cox: i64,
|
planned_amount_cox: i64,
|
||||||
allow_guests: bool,
|
|
||||||
trip_details_id: i64,
|
trip_details_id: i64,
|
||||||
planned_starting_time: String,
|
planned_starting_time: String,
|
||||||
max_people: i64,
|
max_people: i64,
|
||||||
day: String,
|
day: String,
|
||||||
notes: Option<String>,
|
notes: Option<String>,
|
||||||
|
pub allow_guests: bool,
|
||||||
trip_type_id: Option<i64>,
|
trip_type_id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct PlannedEventWithUserAndTriptype {
|
pub struct PlannedEventWithUserAndTriptype {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
planned_event: PlannedEvent,
|
pub planned_event: PlannedEvent,
|
||||||
trip_type: Option<TripType>,
|
trip_type: Option<TripType>,
|
||||||
cox_needed: bool,
|
cox_needed: bool,
|
||||||
cox: Vec<Registration>,
|
cox: Vec<Registration>,
|
||||||
@ -42,7 +42,7 @@ impl PlannedEvent {
|
|||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT
|
SELECT
|
||||||
planned_event.id, planned_event.name, planned_amount_cox, allow_guests, trip_details_id, planned_starting_time, max_people, day, notes, trip_type_id
|
planned_event.id, planned_event.name, planned_amount_cox, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id
|
||||||
FROM planned_event
|
FROM planned_event
|
||||||
INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id
|
INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id
|
||||||
WHERE planned_event.id like ?
|
WHERE planned_event.id like ?
|
||||||
@ -61,7 +61,7 @@ WHERE planned_event.id like ?
|
|||||||
let day = format!("{day}");
|
let day = format!("{day}");
|
||||||
let events = sqlx::query_as!(
|
let events = sqlx::query_as!(
|
||||||
PlannedEvent,
|
PlannedEvent,
|
||||||
"SELECT planned_event.id, planned_event.name, planned_amount_cox, allow_guests, trip_details_id, planned_starting_time, max_people, day, notes, trip_type_id
|
"SELECT planned_event.id, planned_event.name, planned_amount_cox, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id
|
||||||
FROM planned_event
|
FROM planned_event
|
||||||
INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id
|
INNER JOIN trip_details ON planned_event.trip_details_id = trip_details.id
|
||||||
WHERE day=?",
|
WHERE day=?",
|
||||||
@ -127,12 +127,13 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM planned_even
|
|||||||
db: &SqlitePool,
|
db: &SqlitePool,
|
||||||
name: String,
|
name: String,
|
||||||
planned_amount_cox: i32,
|
planned_amount_cox: i32,
|
||||||
allow_guests: bool,
|
|
||||||
trip_details: TripDetails,
|
trip_details: TripDetails,
|
||||||
) {
|
) {
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"INSERT INTO planned_event(name, planned_amount_cox, allow_guests, trip_details_id) VALUES(?, ?, ?, ?)",
|
"INSERT INTO planned_event(name, planned_amount_cox, trip_details_id) VALUES(?, ?, ?)",
|
||||||
name, planned_amount_cox, allow_guests, trip_details.id
|
name,
|
||||||
|
planned_amount_cox,
|
||||||
|
trip_details.id
|
||||||
)
|
)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await
|
.await
|
||||||
@ -170,7 +171,7 @@ mod test {
|
|||||||
|
|
||||||
let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
|
let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
|
||||||
|
|
||||||
PlannedEvent::create(&pool, "new-event".into(), 2, false, trip_details).await;
|
PlannedEvent::create(&pool, "new-event".into(), 2, trip_details).await;
|
||||||
|
|
||||||
let res =
|
let res =
|
||||||
PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await;
|
PlannedEvent::get_for_day(&pool, NaiveDate::from_ymd_opt(1970, 1, 1).unwrap()).await;
|
||||||
|
@ -19,13 +19,14 @@ pub struct Trip {
|
|||||||
max_people: i64,
|
max_people: i64,
|
||||||
day: String,
|
day: String,
|
||||||
notes: Option<String>,
|
notes: Option<String>,
|
||||||
|
pub allow_guests: bool,
|
||||||
trip_type_id: Option<i64>,
|
trip_type_id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct TripWithUserAndType {
|
pub struct TripWithUserAndType {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
trip: Trip,
|
pub trip: Trip,
|
||||||
rower: Vec<Registration>,
|
rower: Vec<Registration>,
|
||||||
trip_type: Option<TripType>,
|
trip_type: Option<TripType>,
|
||||||
}
|
}
|
||||||
@ -47,7 +48,7 @@ impl Trip {
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"
|
"
|
||||||
SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, trip_type_id
|
SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id
|
||||||
FROM trip
|
FROM trip
|
||||||
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
|
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
|
||||||
INNER JOIN user ON trip.cox_id = user.id
|
INNER JOIN user ON trip.cox_id = user.id
|
||||||
@ -100,7 +101,7 @@ WHERE trip.id=?
|
|||||||
let trips = sqlx::query_as!(
|
let trips = sqlx::query_as!(
|
||||||
Trip,
|
Trip,
|
||||||
"
|
"
|
||||||
SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, trip_type_id
|
SELECT trip.id, cox_id, user.name as cox_name, trip_details_id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id
|
||||||
FROM trip
|
FROM trip
|
||||||
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
|
INNER JOIN trip_details ON trip.trip_details_id = trip_details.id
|
||||||
INNER JOIN user ON trip.cox_id = user.id
|
INNER JOIN user ON trip.cox_id = user.id
|
||||||
|
@ -8,6 +8,7 @@ pub struct TripDetails {
|
|||||||
max_people: i64,
|
max_people: i64,
|
||||||
day: String,
|
day: String,
|
||||||
notes: Option<String>,
|
notes: Option<String>,
|
||||||
|
pub allow_guests: bool,
|
||||||
trip_type_id: Option<i64>,
|
trip_type_id: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ impl TripDetails {
|
|||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
TripDetails,
|
TripDetails,
|
||||||
"
|
"
|
||||||
SELECT id, planned_starting_time, max_people, day, notes, trip_type_id
|
SELECT id, planned_starting_time, max_people, day, notes, allow_guests, trip_type_id
|
||||||
FROM trip_details
|
FROM trip_details
|
||||||
WHERE id like ?
|
WHERE id like ?
|
||||||
",
|
",
|
||||||
@ -34,14 +35,16 @@ WHERE id like ?
|
|||||||
max_people: i32,
|
max_people: i32,
|
||||||
day: String,
|
day: String,
|
||||||
notes: Option<String>,
|
notes: Option<String>,
|
||||||
|
allow_guests: bool,
|
||||||
trip_type_id: Option<i64>,
|
trip_type_id: Option<i64>,
|
||||||
) -> i64 {
|
) -> i64 {
|
||||||
let query = sqlx::query!(
|
let query = sqlx::query!(
|
||||||
"INSERT INTO trip_details(planned_starting_time, max_people, day, notes, trip_type_id) VALUES(?, ?, ?, ?, ?)" ,
|
"INSERT INTO trip_details(planned_starting_time, max_people, day, notes, allow_guests, trip_type_id) VALUES(?, ?, ?, ?, ?, ?)" ,
|
||||||
planned_starting_time,
|
planned_starting_time,
|
||||||
max_people,
|
max_people,
|
||||||
day,
|
day,
|
||||||
notes,
|
notes,
|
||||||
|
allow_guests,
|
||||||
trip_type_id
|
trip_type_id
|
||||||
)
|
)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
@ -97,11 +100,29 @@ mod test {
|
|||||||
let pool = testdb!();
|
let pool = testdb!();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TripDetails::create(&pool, "10:00".into(), 2, "1970-01-01".into(), None, None).await,
|
TripDetails::create(
|
||||||
|
&pool,
|
||||||
|
"10:00".into(),
|
||||||
|
2,
|
||||||
|
"1970-01-01".into(),
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await,
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TripDetails::create(&pool, "10:00".into(), 2, "1970-01-01".into(), None, None).await,
|
TripDetails::create(
|
||||||
|
&pool,
|
||||||
|
"10:00".into(),
|
||||||
|
2,
|
||||||
|
"1970-01-01".into(),
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await,
|
||||||
4,
|
4,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ pub struct User {
|
|||||||
pw: Option<String>,
|
pw: Option<String>,
|
||||||
pub is_cox: bool,
|
pub is_cox: bool,
|
||||||
pub is_admin: bool,
|
pub is_admin: bool,
|
||||||
is_guest: bool,
|
pub is_guest: bool,
|
||||||
#[serde(default = "bool::default")]
|
#[serde(default = "bool::default")]
|
||||||
deleted: bool,
|
deleted: bool,
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ impl UserTrip {
|
|||||||
return Err(UserTripError::EventAlreadyFull);
|
return Err(UserTripError::EventAlreadyFull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.is_guest && !trip_details.allow_guests {
|
||||||
|
return Err(UserTripError::GuestNotAllowedForThisEvent);
|
||||||
|
}
|
||||||
|
|
||||||
//check if cox if own event
|
//check if cox if own event
|
||||||
let is_cox = sqlx::query!(
|
let is_cox = sqlx::query!(
|
||||||
"SELECT count(*) as amount
|
"SELECT count(*) as amount
|
||||||
@ -80,6 +84,7 @@ pub enum UserTripError {
|
|||||||
AlreadyRegisteredAsCox,
|
AlreadyRegisteredAsCox,
|
||||||
EventAlreadyFull,
|
EventAlreadyFull,
|
||||||
CantRegisterAtOwnEvent,
|
CantRegisterAtOwnEvent,
|
||||||
|
GuestNotAllowedForThisEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -180,4 +185,19 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(result, UserTripError::AlreadyRegisteredAsCox);
|
assert_eq!(result, UserTripError::AlreadyRegisteredAsCox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[sqlx::test]
|
||||||
|
fn test_fail_create_guest() {
|
||||||
|
let pool = testdb!();
|
||||||
|
|
||||||
|
let user = User::find_by_name(&pool, "guest".into()).await.unwrap();
|
||||||
|
|
||||||
|
let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap();
|
||||||
|
|
||||||
|
let result = UserTrip::create(&pool, &user, &trip_details)
|
||||||
|
.await
|
||||||
|
.expect_err("Not allowed for guests");
|
||||||
|
|
||||||
|
assert_eq!(result, UserTripError::GuestNotAllowedForThisEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ async fn create(
|
|||||||
data.max_people,
|
data.max_people,
|
||||||
data.day.clone(),
|
data.day.clone(),
|
||||||
data.notes.clone(),
|
data.notes.clone(),
|
||||||
|
data.allow_guests,
|
||||||
data.trip_type,
|
data.trip_type,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -43,14 +44,7 @@ async fn create(
|
|||||||
//the object
|
//the object
|
||||||
|
|
||||||
//TODO: fix clone()
|
//TODO: fix clone()
|
||||||
PlannedEvent::create(
|
PlannedEvent::create(db, data.name.clone(), data.planned_amount_cox, trip_details).await;
|
||||||
db,
|
|
||||||
data.name.clone(),
|
|
||||||
data.planned_amount_cox,
|
|
||||||
data.allow_guests,
|
|
||||||
trip_details,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Flash::success(Redirect::to("/"), "Successfully planned the event")
|
Flash::success(Redirect::to("/"), "Successfully planned the event")
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ struct AddTripForm {
|
|||||||
max_people: i32,
|
max_people: i32,
|
||||||
notes: Option<String>,
|
notes: Option<String>,
|
||||||
trip_type: Option<i64>,
|
trip_type: Option<i64>,
|
||||||
|
allow_guests: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/trip", data = "<data>")]
|
#[post("/trip", data = "<data>")]
|
||||||
@ -33,6 +34,7 @@ async fn create(db: &State<SqlitePool>, data: Form<AddTripForm>, cox: CoxUser) -
|
|||||||
data.max_people,
|
data.max_people,
|
||||||
data.day.clone(),
|
data.day.clone(),
|
||||||
data.notes.clone(),
|
data.notes.clone(),
|
||||||
|
data.allow_guests,
|
||||||
data.trip_type,
|
data.trip_type,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -37,6 +37,7 @@ async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_
|
|||||||
.num_days()
|
.num_days()
|
||||||
+ 1;
|
+ 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.is_cox || user.is_admin {
|
if user.is_cox || user.is_admin {
|
||||||
let triptypes = TripType::all(db).await;
|
let triptypes = TripType::all(db).await;
|
||||||
context.insert("trip_types", &triptypes);
|
context.insert("trip_types", &triptypes);
|
||||||
@ -44,7 +45,12 @@ async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_
|
|||||||
|
|
||||||
for i in 0..show_next_n_days {
|
for i in 0..show_next_n_days {
|
||||||
let date = (Local::now() + Duration::days(i)).date_naive();
|
let date = (Local::now() + Duration::days(i)).date_naive();
|
||||||
days.push(Day::new(db, date).await);
|
|
||||||
|
if user.is_guest {
|
||||||
|
days.push(Day::new_guest(db, date).await);
|
||||||
|
} else {
|
||||||
|
days.push(Day::new(db, date).await);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(msg) = flash {
|
if let Some(msg) = flash {
|
||||||
@ -86,6 +92,10 @@ async fn join(db: &State<SqlitePool>, trip_details_id: i64, user: User) -> Flash
|
|||||||
Redirect::to("/"),
|
Redirect::to("/"),
|
||||||
"Du kannst bei einer selbst ausgeschriebenen Fahrt nicht mitrudern ;)",
|
"Du kannst bei einer selbst ausgeschriebenen Fahrt nicht mitrudern ;)",
|
||||||
),
|
),
|
||||||
|
Err(UserTripError::GuestNotAllowedForThisEvent) => Flash::error(
|
||||||
|
Redirect::to("/"),
|
||||||
|
"Bei dieser Ausfahrt können leider keine Gäste mitfahren.",
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{{ macros::input(label='Startzeit', name='planned_starting_time', type='time', required=true) }}
|
{{ macros::input(label='Startzeit', name='planned_starting_time', type='time', required=true) }}
|
||||||
{{ 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='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='Gäste erlauben', name='max_allow_guestspeople') }}
|
{{ macros::checkbox(label='Gäste erlauben', name='allow_guests') }}
|
||||||
{{ macros::input(label='Anmerkungen', name='notes', type='input') }}
|
{{ macros::input(label='Anmerkungen', name='notes', type='input') }}
|
||||||
<input value="Erstellen" class="w-full btn btn-primary" type="submit" />
|
<input value="Erstellen" class="w-full btn btn-primary" type="submit" />
|
||||||
</form>
|
</form>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<input class="day-js" type="hidden" name="day" value="" />
|
<input class="day-js" type="hidden" name="day" value="" />
|
||||||
{{ 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='Gäste erlauben', name='allow_guests') }}
|
||||||
{{ macros::input(label='Anmerkungen', name='notes', type='input') }}
|
{{ macros::input(label='Anmerkungen', name='notes', type='input') }}
|
||||||
<input value="Erstellen" class="w-full btn btn-primary" type="submit" />
|
<input value="Erstellen" class="w-full btn btn-primary" type="submit" />
|
||||||
</form>
|
</form>
|
||||||
|
Loading…
Reference in New Issue
Block a user