2023-02-08 16:25:06 +01:00
|
|
|
#[macro_use]
|
|
|
|
extern crate rocket;
|
|
|
|
|
|
|
|
mod models;
|
|
|
|
|
|
|
|
use std::collections::HashMap;
|
2023-02-09 12:16:04 +01:00
|
|
|
use std::ops::Deref;
|
2023-02-08 16:25:06 +01:00
|
|
|
|
|
|
|
use chrono::Duration;
|
|
|
|
use chrono::Local;
|
2023-02-09 12:16:04 +01:00
|
|
|
use chrono::NaiveDate;
|
|
|
|
use rocket::fairing::AdHoc;
|
|
|
|
use rocket::form;
|
2023-02-09 13:19:00 +01:00
|
|
|
use rocket::form::validate::range;
|
2023-02-09 12:16:04 +01:00
|
|
|
use rocket::form::ValueField;
|
|
|
|
use rocket::http::Cookie;
|
|
|
|
use rocket::http::CookieJar;
|
|
|
|
use rocket::request;
|
|
|
|
use rocket::request::FromRequest;
|
|
|
|
use rocket::request::Outcome;
|
2023-02-08 22:02:17 +01:00
|
|
|
use rocket::response::Redirect;
|
2023-02-09 12:16:04 +01:00
|
|
|
use rocket::Request;
|
2023-02-08 16:25:06 +01:00
|
|
|
use rocket::{form::Form, fs::FileServer, State};
|
|
|
|
use rocket_dyn_templates::context;
|
|
|
|
use rocket_dyn_templates::Template;
|
|
|
|
use sea_orm::ColumnTrait;
|
2023-02-09 12:16:04 +01:00
|
|
|
use sea_orm::ModelTrait;
|
2023-02-08 16:25:06 +01:00
|
|
|
use sea_orm::QueryFilter;
|
|
|
|
use sea_orm::{
|
|
|
|
ActiveModelTrait, Database, DatabaseConnection, EntityTrait, Order, QueryOrder, Set,
|
|
|
|
};
|
2023-02-09 12:16:04 +01:00
|
|
|
use serde::Serialize;
|
2023-02-08 16:25:06 +01:00
|
|
|
|
2023-02-09 12:16:04 +01:00
|
|
|
use crate::models::{day, trip, user};
|
|
|
|
|
|
|
|
#[derive(Serialize, Debug)]
|
|
|
|
struct TripWithUser {
|
|
|
|
trip: trip::Model,
|
|
|
|
user: user::Model,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TripWithUser {
|
|
|
|
async fn new(trip: trip::Model, db: &DatabaseConnection) -> Self {
|
|
|
|
Self {
|
|
|
|
trip: trip.clone(),
|
|
|
|
user: trip
|
|
|
|
.find_related(user::Entity)
|
|
|
|
.one(db)
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.unwrap(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Debug)]
|
|
|
|
struct DayWithTrips {
|
|
|
|
day: day::Model,
|
|
|
|
trips: Vec<TripWithUser>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DayWithTrips {
|
|
|
|
async fn new(day: day::Model, db: &DatabaseConnection) -> Self {
|
|
|
|
let mut trips = Vec::new();
|
|
|
|
for trip in day.find_related(trip::Entity).all(db).await.unwrap() {
|
|
|
|
trips.push(TripWithUser::new(trip, db).await);
|
|
|
|
}
|
|
|
|
|
|
|
|
Self { day, trips }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
struct Name(user::Model);
|
|
|
|
#[rocket::async_trait]
|
|
|
|
impl<'r> FromRequest<'r> for Name {
|
|
|
|
type Error = rocket::Error;
|
|
|
|
|
|
|
|
async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
|
|
|
|
match req.cookies().get("name") {
|
|
|
|
Some(name) => {
|
|
|
|
let db = req.guard::<&'r State<DatabaseConnection>>();
|
|
|
|
let name = name.value();
|
|
|
|
let user = find_or_create_user(name, db.await.unwrap().inner()).await;
|
|
|
|
Outcome::Success(Name(user))
|
|
|
|
}
|
|
|
|
None => Outcome::Forward(()), //No cookie set
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-08 16:25:06 +01:00
|
|
|
|
|
|
|
#[get("/")]
|
2023-02-09 12:16:04 +01:00
|
|
|
async fn index(db: &State<DatabaseConnection>, name: Name) -> Template {
|
2023-02-08 16:25:06 +01:00
|
|
|
let days: Vec<day::Model> = day::Entity::find()
|
|
|
|
.filter(day::Column::Day.gte(format!("{}", Local::now().format("%Y-%m-%d")))) // don't show stuff from the past
|
|
|
|
.order_by(day::Column::Day, Order::Asc)
|
|
|
|
.all(db.inner())
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
2023-02-09 12:16:04 +01:00
|
|
|
let mut dwu = HashMap::new();
|
|
|
|
for day in days {
|
|
|
|
dwu.insert(
|
|
|
|
format!("{}", day.day.format("%Y-%m-%d")),
|
|
|
|
DayWithTrips::new(day, db.inner()).await,
|
|
|
|
);
|
|
|
|
}
|
2023-02-08 16:25:06 +01:00
|
|
|
|
|
|
|
let mut next_days = Vec::new();
|
|
|
|
for i in 0..6 {
|
|
|
|
next_days.push(Local::now() + Duration::days(i));
|
|
|
|
}
|
|
|
|
|
2023-02-09 12:16:04 +01:00
|
|
|
Template::render("index", context! { dwu, next_days, name })
|
|
|
|
}
|
2023-02-08 16:25:06 +01:00
|
|
|
|
2023-02-09 12:16:04 +01:00
|
|
|
#[get("/", rank = 2)]
|
|
|
|
fn name() -> Template {
|
|
|
|
Template::render("name", context! {})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(FromForm)]
|
|
|
|
struct NameForm(String);
|
|
|
|
|
|
|
|
#[post("/setname", data = "<name>")]
|
|
|
|
fn setname(cookies: &CookieJar<'_>, name: Form<NameForm>) -> Redirect {
|
|
|
|
cookies.add(Cookie::new("name", name.0.clone()));
|
|
|
|
Redirect::to("/")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct NaiveDateForm(NaiveDate);
|
|
|
|
|
|
|
|
impl<'v> rocket::form::FromFormField<'v> for NaiveDateForm {
|
|
|
|
fn from_value(field: ValueField<'v>) -> form::Result<'v, NaiveDateForm> {
|
|
|
|
let naivedate = chrono::NaiveDate::parse_from_str(&field.value, "%Y-%m-%d").unwrap(); //TODO:
|
|
|
|
//fixme
|
|
|
|
Ok(NaiveDateForm(naivedate))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deref for NaiveDateForm {
|
|
|
|
type Target = NaiveDate;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
2023-02-08 16:25:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(FromForm, Debug)]
|
|
|
|
struct DayForm {
|
2023-02-09 12:16:04 +01:00
|
|
|
day: NaiveDateForm,
|
|
|
|
#[field(validate = range(0..20))]
|
|
|
|
planned_amount_cox: i32,
|
2023-02-08 16:25:06 +01:00
|
|
|
planned_starting_time: Option<String>,
|
|
|
|
open_registration: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[put("/day", data = "<day>")]
|
2023-02-08 22:02:17 +01:00
|
|
|
async fn create(db: &State<DatabaseConnection>, day: Form<DayForm>) -> Redirect {
|
|
|
|
let new_day = day::ActiveModel {
|
2023-02-09 12:16:04 +01:00
|
|
|
day: Set(*day.day),
|
2023-02-08 16:25:06 +01:00
|
|
|
planned_amount_cox: Set(day.planned_amount_cox),
|
|
|
|
planned_starting_time: Set(day.planned_starting_time.clone()),
|
|
|
|
open_registration: Set(day.open_registration),
|
|
|
|
};
|
|
|
|
|
2023-02-09 12:16:04 +01:00
|
|
|
let day: Option<day::Model> = day::Entity::find_by_id(*day.day)
|
|
|
|
.one(db.inner())
|
|
|
|
.await
|
|
|
|
.unwrap();
|
2023-02-08 22:02:17 +01:00
|
|
|
match day {
|
|
|
|
Some(_) => {
|
|
|
|
new_day.update(db.inner()).await.unwrap(); //TODO: fixme
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
new_day.insert(db.inner()).await.unwrap(); //TODO: fixme
|
|
|
|
}
|
|
|
|
}
|
2023-02-08 16:25:06 +01:00
|
|
|
|
2023-02-08 22:02:17 +01:00
|
|
|
Redirect::to("/")
|
2023-02-08 16:25:06 +01:00
|
|
|
}
|
|
|
|
|
2023-02-09 12:16:04 +01:00
|
|
|
#[derive(FromForm)]
|
|
|
|
struct RegisterForm {
|
|
|
|
day: NaiveDateForm,
|
2023-02-09 13:19:00 +01:00
|
|
|
#[field(validate = len(3..))]
|
2023-02-09 12:16:04 +01:00
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn find_or_create_user(name: &str, db: &DatabaseConnection) -> user::Model {
|
|
|
|
let user = user::Entity::find()
|
|
|
|
.filter(user::Column::Name.eq(name))
|
|
|
|
.one(db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
match user {
|
|
|
|
Some(user) => user,
|
|
|
|
None => {
|
|
|
|
let user = user::ActiveModel {
|
|
|
|
name: Set(name.clone().into()),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
user.insert(db).await.unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[put("/register", data = "<register>")]
|
|
|
|
async fn register(db: &State<DatabaseConnection>, register: Form<RegisterForm>) -> Redirect {
|
|
|
|
let day = day::Entity::find_by_id(*register.day)
|
|
|
|
.one(db.inner())
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.expect("There's no trip on this date (yet)");
|
|
|
|
|
|
|
|
let user = find_or_create_user(®ister.name, db.inner()).await;
|
|
|
|
|
|
|
|
let day = format!("{}", day.day.format("%Y-%m-%d"));
|
|
|
|
let trip = trip::ActiveModel {
|
|
|
|
day: Set(day),
|
|
|
|
user_id: Set(user.id),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
trip.insert(db.inner()).await.unwrap();
|
|
|
|
|
|
|
|
Redirect::to("/")
|
|
|
|
}
|
|
|
|
|
2023-02-08 16:25:06 +01:00
|
|
|
#[launch]
|
|
|
|
async fn rocket() -> _ {
|
|
|
|
rocket::build()
|
|
|
|
.attach(Template::fairing())
|
|
|
|
.manage(Database::connect("sqlite://db.sqlite").await.unwrap())
|
|
|
|
.mount("/public", FileServer::from("static/"))
|
2023-02-09 12:16:04 +01:00
|
|
|
.mount("/", routes![index, create, register, name, setname])
|
2023-02-08 16:25:06 +01:00
|
|
|
}
|