rename folder
| @@ -4,8 +4,9 @@ version = "0.1.0" | |||||||
| edition = "2021" | edition = "2021" | ||||||
|  |  | ||||||
| [features] | [features] | ||||||
| default = ["rowing-tera"] | default = ["rowing-tera", "rest"] | ||||||
| rowing-tera = ["rocket_dyn_templates", "tera"] | rowing-tera = ["rocket_dyn_templates", "tera"] | ||||||
|  | rest = [] | ||||||
|  |  | ||||||
| [dependencies] | [dependencies] | ||||||
| rocket = { version = "0.5.0-rc.3", features = ["secrets"]} | rocket = { version = "0.5.0-rc.3", features = ["secrets"]} | ||||||
|   | |||||||
| @@ -26,5 +26,8 @@ async fn rocket() -> _ { | |||||||
|     #[cfg(feature = "rowing-tera")] |     #[cfg(feature = "rowing-tera")] | ||||||
|     let rocket = tera::config(rocket); |     let rocket = tera::config(rocket); | ||||||
|  |  | ||||||
|  |     #[cfg(feature = "rest")] | ||||||
|  |     let rocket = rest::config(rocket); | ||||||
|  |  | ||||||
|     rocket |     rocket | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										149
									
								
								src/rest/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,149 @@ | |||||||
|  | use rocket::{ | ||||||
|  |     catch, catchers, | ||||||
|  |     fairing::AdHoc, | ||||||
|  |     fs::FileServer, | ||||||
|  |     get, | ||||||
|  |     request::FlashMessage, | ||||||
|  |     response::{Flash, Redirect}, | ||||||
|  |     routes, Build, Rocket, State, | ||||||
|  | }; | ||||||
|  | use rocket_dyn_templates::{tera::Context, Template}; | ||||||
|  | use serde::Deserialize; | ||||||
|  | use sqlx::SqlitePool; | ||||||
|  |  | ||||||
|  | use crate::model::{ | ||||||
|  |     log::Log, | ||||||
|  |     tripdetails::TripDetails, | ||||||
|  |     triptype::TripType, | ||||||
|  |     user::User, | ||||||
|  |     usertrip::{UserTrip, UserTripError}, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | mod admin; | ||||||
|  | mod auth; | ||||||
|  | mod cox; | ||||||
|  | mod misc; | ||||||
|  |  | ||||||
|  | #[get("/")] | ||||||
|  | async fn index(db: &State<SqlitePool>, user: User, flash: Option<FlashMessage<'_>>) -> Template { | ||||||
|  |     let mut context = Context::new(); | ||||||
|  |  | ||||||
|  |     if user.is_cox || user.is_admin { | ||||||
|  |         let triptypes = TripType::all(db).await; | ||||||
|  |         context.insert("trip_types", &triptypes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let days = user.get_days(db).await; | ||||||
|  |  | ||||||
|  |     if let Some(msg) = flash { | ||||||
|  |         context.insert("flash", &msg.into_inner()); | ||||||
|  |     } | ||||||
|  |     context.insert("loggedin_user", &user); | ||||||
|  |     context.insert("days", &days); | ||||||
|  |     Template::render("index", context.into_json()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[get("/join/<trip_details_id>")] | ||||||
|  | async fn join(db: &State<SqlitePool>, trip_details_id: i64, user: User) -> Flash<Redirect> { | ||||||
|  |     let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else { return Flash::error(Redirect::to("/"), "Trip_details do not exist.") }; | ||||||
|  |  | ||||||
|  |     match UserTrip::create(db, &user, &trip_details).await { | ||||||
|  |         Ok(_) => { | ||||||
|  |             Log::create( | ||||||
|  |                 db, | ||||||
|  |                 format!( | ||||||
|  |                     "User {} registered for trip_details.id={}", | ||||||
|  |                     user.name, trip_details_id | ||||||
|  |                 ), | ||||||
|  |             ) | ||||||
|  |             .await; | ||||||
|  |             Flash::success(Redirect::to("/"), "Erfolgreich angemeldet!") | ||||||
|  |         } | ||||||
|  |         Err(UserTripError::EventAlreadyFull) => { | ||||||
|  |             Flash::error(Redirect::to("/"), "Event bereits ausgebucht!") | ||||||
|  |         } | ||||||
|  |         Err(UserTripError::AlreadyRegistered) => { | ||||||
|  |             Flash::error(Redirect::to("/"), "Du nimmst bereits teil!") | ||||||
|  |         } | ||||||
|  |         Err(UserTripError::AlreadyRegisteredAsCox) => { | ||||||
|  |             Flash::error(Redirect::to("/"), "Du hilfst bereits als Steuerperson aus!") | ||||||
|  |         } | ||||||
|  |         Err(UserTripError::CantRegisterAtOwnEvent) => Flash::error( | ||||||
|  |             Redirect::to("/"), | ||||||
|  |             "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.", | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[get("/remove/<trip_details_id>")] | ||||||
|  | async fn remove(db: &State<SqlitePool>, trip_details_id: i64, user: User) -> Flash<Redirect> { | ||||||
|  |     let Some(trip_details) = TripDetails::find_by_id(db, trip_details_id).await else { | ||||||
|  |              return Flash::error(Redirect::to("/"), "TripDetailsId does not exist"); | ||||||
|  |          }; | ||||||
|  |  | ||||||
|  |     UserTrip::delete(db, &user, &trip_details).await; | ||||||
|  |  | ||||||
|  |     Log::create( | ||||||
|  |         db, | ||||||
|  |         format!( | ||||||
|  |             "User {} unregistered for trip_details.id={}", | ||||||
|  |             user.name, trip_details_id | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  |     .await; | ||||||
|  |  | ||||||
|  |     Flash::success(Redirect::to("/"), "Erfolgreich abgemeldet!") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[catch(401)] //unauthorized | ||||||
|  | fn unauthorized_error() -> Redirect { | ||||||
|  |     Redirect::to("/auth") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Deserialize)] | ||||||
|  | #[serde(crate = "rocket::serde")] | ||||||
|  | pub struct Config { | ||||||
|  |     rss_key: String, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn config(rocket: Rocket<Build>) -> Rocket<Build> { | ||||||
|  |     rocket | ||||||
|  |         .mount("/", routes![index, join, remove]) | ||||||
|  |         .mount("/auth", auth::routes()) | ||||||
|  |         .mount("/cox", cox::routes()) | ||||||
|  |         .mount("/admin", admin::routes()) | ||||||
|  |         .mount("/", misc::routes()) | ||||||
|  |         .mount("/public", FileServer::from("static/")) | ||||||
|  |         .register("/", catchers![unauthorized_error]) | ||||||
|  |         .attach(Template::fairing()) | ||||||
|  |         .attach(AdHoc::config::<Config>()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //#[cfg(test)] | ||||||
|  | //mod test { | ||||||
|  | //    use crate::testdb; | ||||||
|  | // | ||||||
|  | //    use super::start; | ||||||
|  | //    use rocket::http::Status; | ||||||
|  | //    use rocket::local::asynchronous::Client; | ||||||
|  | //    use rocket::uri; | ||||||
|  | //    use sqlx::SqlitePool; | ||||||
|  | // | ||||||
|  | //    #[sqlx::test] | ||||||
|  | //    fn test_not_logged_in() { | ||||||
|  | //        let pool = testdb!(); | ||||||
|  | // | ||||||
|  | //        let client = Client::tracked(start(pool)) | ||||||
|  | //            .await | ||||||
|  | //            .expect("valid rocket instance"); | ||||||
|  | //        let response = client.get(uri!(super::index)).dispatch().await; | ||||||
|  | // | ||||||
|  | //        assert_eq!(response.status(), Status::SeeOther); | ||||||
|  | //        let location = response.headers().get("Location").next().unwrap(); | ||||||
|  | //        assert_eq!(location, "/auth"); | ||||||
|  | //    } | ||||||
|  | //} | ||||||
							
								
								
									
										0
									
								
								rot_app/.gitignore → svelte/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB | 
| Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB | 
| Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 352 KiB | 
| Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB | 
| Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |