From bbb78cbc44824b74560f79e5b7095d49752ea4ea Mon Sep 17 00:00:00 2001 From: philipp Date: Mon, 31 Jul 2023 13:34:02 +0200 Subject: [PATCH] move todos to gitlab; write tests for /cox/remove/; Closes #9 --- README.md | 109 ----------------------------------------- src/model/trip.rs | 8 +-- src/tera/cox.rs | 121 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 115 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index ffce0da..4bd52cb 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,3 @@ -# Backend -- [] **Create missing backend tests (see below)** -- [] trip_details -> is_locked (default: false) -- [] ics for registered trips - -## New large features -### Logbuch -- Only layout + tests missing :-) - -### Guest-Scheckbuch -- guest_trip - - guest_user_id - - amount_trips - - paid_to_user_id -- guest_trip_logbook - - guest_trip_id - - logbook_id - -### Bootsreservierungen -- Confirmation required? -- How long in advance is it possible? -- Default reservations for some regular events (A+F, USI, ...)? - -### Notifications -- notifcations - - id - - message - - category - - created_at - - confirmed_at: Option - - user_id - - link -- ideas - - created an event at the same datetime as you - -### Schnupper-Pipeline -- Mail-Adressen von Interessierten dauerhaft entgegennehmen -- Termin ausgemacht -> Interessierte kontaktieren -- X Personen können teilnehmen (bis zu 3(?) pro Person erlauben (Familie)?) -- Automatisch Bestätigung bei Anmeldung schicken, mit Detail-Infos -- Ein paar Tage vorher Erinnerungs-Mail ausschicken -- Anmeldungen können manuell wieder gelöscht werden -- Es gibt Liste mit aktuellen Anmeldungen - -### Ergochallenge -- Bilder + Dateneingabe -- Automatische Mail senden - -## Backlog (i.e. don't work on this now) -### Sync w/ nextcloud -- remove most fields (names, ...) from users and add uid -- create user_nextcloud table; to be re-created every day(?) - -user -- UID -- pw -- last_access - -user_details -- UID -- fn (formatted name) -- is_cox (if CATEGORIES = {Steuerleute, Bootsführer}) -- is_admin (if CATEGORIES = Admin) -- is_guest (if person not in nextcloud) - -### Misc -- [] Don't show events if time > 1h(?) ago -- [] exactly same time -> deny registration -- [] automatically add regular planned trip -- [] same day+time: aggregate stats (x people, of which y cox and z rower) -- [] Lock trip; noone can register anymore -- [] on delete cascade doesn't work; e.g. created planned_event/trip + delete it -> trip_details entry still there! -- [] allow users to add u2f key -- [] Möglichkeiten für Bootseinteilungen bei planned_events anzeigen - - - # Frontend Process ´cd frontend´ ´npm install´ @@ -82,7 +5,6 @@ user_details # Notes / Bugfixes ## Frontend -- [] add UI for `trip_type` - [] support esc to close sidebar - [] after an hour(?) of inactivity -> show large popup w/ "maybe old data (ignore) (reload page)" (ignore bc maybe use is actively doing something -> don't throw input away!) @@ -90,34 +12,3 @@ user_details # Nice to have ## Frontend - [] my trips for cox - -# Missing backend tests - -- [x] (index) GET / -- [x] (faq) GET /faq -- [x] (cal) GET /cal -- [x] (FileServer: svelte/build) GET / -- [x] (join) GET /join/ -- [x] (remove) GET /remove/ -- [x] (create) POST /cox/trip -- [x] (update) POST /cox/trip/ -- [x] (join) GET /cox/join/ -- [ ] (remove) GET /cox/remove/ -- [ ] (remove_trip) GET /cox/remove/trip/ -- [ ] (index) GET /auth/ -- [ ] (login) POST /auth/ -- [ ] (logout) GET /auth/logout -- [ ] (updatepw) POST /auth/set-pw -- [ ] (setpw) GET /auth/set-pw/ -- [ ] (rss) GET /admin/rss? -- [ ] (index) GET /admin/user -- [ ] (update) POST /admin/user -- [ ] (create) POST /admin/planned-event -- [ ] (update) PUT /admin/planned-event -- [ ] (create) POST /admin/user/new -- [ ] (delete) GET /admin/user//delete -- [ ] (resetpw) GET /admin/user//reset-pw -- [ ] (delete) GET /admin/planned-event//delete -- [ ] (FileServer: static/) GET /public/ [10] -- [ ] (login) POST /api/login/ -- [ ] /tera/admin/boat.rs diff --git a/src/model/trip.rs b/src/model/trip.rs index a7671a6..bfb7564 100644 --- a/src/model/trip.rs +++ b/src/model/trip.rs @@ -154,7 +154,7 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE i .await .unwrap(); //Okay, as trip can only be created with proper DB backing let Some(trip_details_id) = trip_details.id else { - return Err(TripUpdateError::TripDetailsDoesNotExist); //TODO: Remove? + return Err(TripUpdateError::TripDetailsDoesNotExist); //TODO: Remove? }; sqlx::query!( @@ -176,7 +176,7 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE i db: &SqlitePool, cox: &CoxUser, planned_event: &PlannedEvent, - ) { + ) -> bool { sqlx::query!( "DELETE FROM trip WHERE cox_id = ? AND planned_event_id = ?", cox.id, @@ -184,7 +184,9 @@ FROM user_trip WHERE trip_details_id = (SELECT trip_details_id FROM trip WHERE i ) .execute(db) .await - .unwrap(); //TODO: handle case where cox is not registered + .unwrap() + .rows_affected() + > 0 } pub(crate) async fn delete( diff --git a/src/tera/cox.rs b/src/tera/cox.rs index 2aecced..965f4b1 100644 --- a/src/tera/cox.rs +++ b/src/tera/cox.rs @@ -129,18 +129,20 @@ async fn remove_trip(db: &State, trip_id: i64, cox: CoxUser) -> Flas #[get("/remove/")] async fn remove(db: &State, planned_event_id: i64, cox: CoxUser) -> Flash { if let Some(planned_event) = PlannedEvent::find_by_id(db, planned_event_id).await { - Trip::delete_by_planned_event(db, &cox, &planned_event).await; + if Trip::delete_by_planned_event(db, &cox, &planned_event).await { + Log::create( + db, + format!( + "Cox {} deleted registration for planned_event.id={}", + cox.name, planned_event_id + ), + ) + .await; - Log::create( - db, - format!( - "Cox {} deleted registration for planned_event.id={}", - cox.name, planned_event_id - ), - ) - .await; - - Flash::success(Redirect::to("/"), "Erfolgreich abgemeldet!") + Flash::success(Redirect::to("/"), "Erfolgreich abgemeldet!") + } else { + Flash::error(Redirect::to("/"), "Steuermann hilft nicht aus...") + } } else { Flash::error(Redirect::to("/"), "Planned_event does not exist.") } @@ -425,4 +427,101 @@ mod test { assert_eq!(flash_cookie.value(), "5:errorEvent gibt's nicht"); } + + #[sqlx::test] + fn test_remove() { + let db = testdb!(); + + let rocket = rocket::build().manage(db.clone()); + let rocket = crate::tera::config(rocket); + + let client = Client::tracked(rocket).await.unwrap(); + let login = client + .post("/auth") + .header(ContentType::Form) // Set the content type to form + .body("name=cox&password=cox"); // Add the form data to the request body; + login.dispatch().await; + + let req = client.get("/cox/join/1"); + let response = req.dispatch().await; + + let flash_cookie = response + .cookies() + .get("_flash") + .expect("Expected flash cookie"); + + assert_eq!(flash_cookie.value(), "7:successDanke für's helfen!"); + + let req = client.get("/cox/join/1"); + let response = req.dispatch().await; + + let req = client.get("/cox/remove/1"); + let response = req.dispatch().await; + + assert_eq!(response.status(), Status::SeeOther); + assert_eq!(response.headers().get("Location").next(), Some("/")); + + let flash_cookie = response + .cookies() + .get("_flash") + .expect("Expected flash cookie"); + + assert_eq!(flash_cookie.value(), "7:successErfolgreich abgemeldet!"); + } + + #[sqlx::test] + fn test_remove_wrong_id() { + let db = testdb!(); + + let rocket = rocket::build().manage(db.clone()); + let rocket = crate::tera::config(rocket); + + let client = Client::tracked(rocket).await.unwrap(); + let login = client + .post("/auth") + .header(ContentType::Form) // Set the content type to form + .body("name=cox&password=cox"); // Add the form data to the request body; + login.dispatch().await; + + let req = client.get("/cox/remove/999"); + let response = req.dispatch().await; + + assert_eq!(response.status(), Status::SeeOther); + assert_eq!(response.headers().get("Location").next(), Some("/")); + + let flash_cookie = response + .cookies() + .get("_flash") + .expect("Expected flash cookie"); + + assert_eq!(flash_cookie.value(), "5:errorPlanned_event does not exist."); + } + + #[sqlx::test] + fn test_remove_cox_not_participating() { + let db = testdb!(); + + let rocket = rocket::build().manage(db.clone()); + let rocket = crate::tera::config(rocket); + + let client = Client::tracked(rocket).await.unwrap(); + let login = client + .post("/auth") + .header(ContentType::Form) // Set the content type to form + .body("name=cox&password=cox"); // Add the form data to the request body; + login.dispatch().await; + + let req = client.get("/cox/remove/1"); + let response = req.dispatch().await; + + assert_eq!(response.status(), Status::SeeOther); + assert_eq!(response.headers().get("Location").next(), Some("/")); + + let flash_cookie = response + .cookies() + .get("_flash") + .expect("Expected flash cookie"); + + assert_eq!(flash_cookie.value(), "5:errorSteuermann hilft nicht aus..."); + } }