diff --git a/db.sqlite b/db.sqlite index 8289edb..c918d5f 100644 Binary files a/db.sqlite and b/db.sqlite differ diff --git a/migration/src/m20230208_114547_create_day.rs b/migration/src/m20230208_114547_create_day.rs index d39e642..c1af04d 100644 --- a/migration/src/m20230208_114547_create_day.rs +++ b/migration/src/m20230208_114547_create_day.rs @@ -18,11 +18,7 @@ impl MigrationTrait for Migration { .integer() .default(0), ) - .col( - ColumnDef::new(Day::PlannedStartingTime) - .string() - .default(""), - ) + .col(ColumnDef::new(Day::PlannedStartingTime).string()) .col( ColumnDef::new(Day::OpenRegistration) .boolean() diff --git a/migration/src/m20230209_074936_create_trip.rs b/migration/src/m20230209_074936_create_trip.rs index 00684c5..d83ead1 100644 --- a/migration/src/m20230209_074936_create_trip.rs +++ b/migration/src/m20230209_074936_create_trip.rs @@ -1,4 +1,5 @@ use sea_orm_migration::prelude::*; +use sea_query::Expr; use crate::m20230208_114547_create_day::Day; use crate::m20230209_063357_create_user::User; @@ -40,7 +41,7 @@ impl MigrationTrait for Migration { ColumnDef::new(Trip::Created) .timestamp() .not_null() - .default("CURRENT_TIMESTAMP"), + .default(Expr::current_timestamp()), ) .primary_key(Index::create().col(Trip::Day).col(Trip::UserId)) .to_owned(), diff --git a/src/models/user.rs b/src/models/user.rs index a5e4b8e..5139e92 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -18,6 +18,9 @@ pub struct Model { pub is_admin: bool, } +#[derive(Serialize)] +pub struct AdminUser(Model); + impl Model { pub async fn find_or_create_user(name: &str, db: &DatabaseConnection) -> Model { let user = Entity::find() @@ -42,6 +45,7 @@ impl Model { #[derive(Debug)] pub enum UserError { NoCookieSet, + NoAdmin, } #[rocket::async_trait] @@ -61,6 +65,27 @@ impl<'r> FromRequest<'r> for Model { } } +#[rocket::async_trait] +impl<'r> FromRequest<'r> for AdminUser { + type Error = UserError; + + async fn from_request(req: &'r Request<'_>) -> request::Outcome { + match req.cookies().get("name") { + Some(name) => { + let db = req.guard::<&'r State>(); + let name = name.value(); + let user = Model::find_or_create_user(name, db.await.unwrap().inner()).await; + if user.is_admin { + Outcome::Success(AdminUser(user)) + } else { + Outcome::Failure((Status::Unauthorized, UserError::NoAdmin)) + } + } + None => Outcome::Failure((Status::Unauthorized, UserError::NoCookieSet)), + } + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} diff --git a/src/rest/mod.rs b/src/rest/mod.rs index 012c369..8c78041 100644 --- a/src/rest/mod.rs +++ b/src/rest/mod.rs @@ -1,9 +1,10 @@ mod restday; mod restreg; +mod restuser; use std::ops::Deref; -use chrono::{Duration, Local, NaiveDate}; +use chrono::{Datelike, Duration, Local, NaiveDate}; use rocket::{ form::{self, Form, ValueField}, fs::FileServer, @@ -37,7 +38,17 @@ impl Deref for NaiveDateForm { #[get("/")] async fn index(db: &State, user: user::Model) -> Template { let mut data = Vec::new(); - for i in 0..6 { + + let mut show_next_n_days = 6; + if user.is_cox { + let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 5, 31).unwrap(); + show_next_n_days = end_of_year + .signed_duration_since(Local::now().date_naive()) + .num_days() + + 1; + } + + for i in 0..show_next_n_days { let date = (Local::now() + Duration::days(i)).date_naive(); let day = day::Model::find_or_create_day(date, db.inner()).await; data.push(DayWithTrips::new(day, db.inner()).await); @@ -62,6 +73,12 @@ fn savename(name: Form, cookies: &CookieJar) -> Redirect { Redirect::to("/") } +#[get("/logout")] +fn logout(cookies: &CookieJar) -> Redirect { + cookies.remove(Cookie::new("name", "")); + Redirect::to("/") +} + #[catch(401)] //unauthorized fn unauthorized_error() -> Redirect { Redirect::to("/name") @@ -72,8 +89,9 @@ pub async fn start() -> Rocket { .attach(Template::fairing()) .manage(Database::connect("sqlite://db.sqlite").await.unwrap()) .mount("/public", FileServer::from("static/")) - .mount("/", routes![index, name, savename]) + .mount("/", routes![index, name, savename, logout]) .mount("/day", restday::routes()) .mount("/register", restreg::routes()) + .mount("/user", restuser::routes()) .register("/", catchers![unauthorized_error]) } diff --git a/src/rest/restreg.rs b/src/rest/restreg.rs index 7a332d4..9dd4414 100644 --- a/src/rest/restreg.rs +++ b/src/rest/restreg.rs @@ -20,6 +20,10 @@ async fn register(db: &State, register: Form) .unwrap() .expect("There's no trip on this date (yet)"); + if !day.open_registration { + return Redirect::to("/"); + } + let user = user::Model::find_or_create_user(®ister.name, db.inner()).await; let day = format!("{}", day.day.format("%Y-%m-%d")); diff --git a/src/rest/restuser.rs b/src/rest/restuser.rs new file mode 100644 index 0000000..d2f5244 --- /dev/null +++ b/src/rest/restuser.rs @@ -0,0 +1,42 @@ +use rocket::{form::Form, response::Redirect, Route, State}; +use rocket_dyn_templates::{context, Template}; +use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, Set}; + +use crate::models::{day, user}; + +use super::NaiveDateForm; + +#[get("/")] +async fn index(db: &State, user: user::AdminUser) -> Template { + let users = user::Entity::find().all(db.inner()).await.unwrap(); + + Template::render("user/index", context! {user, users}) +} + +#[derive(FromForm)] +struct UserEditForm { + is_cox: bool, + is_admin: bool, +} + +#[put("/", data = "")] +async fn update( + db: &State, + id: i32, + data: Form, + _user: user::AdminUser, +) -> Redirect { + let new_user = user::ActiveModel { + id: Set(id), + is_cox: Set(data.is_cox), + is_admin: Set(data.is_admin), + ..Default::default() + }; + new_user.update(db.inner()).await.unwrap(); + + Redirect::to("/user") +} + +pub fn routes() -> Vec { + routes![index, update] +} diff --git a/templates/base.html.tera b/templates/base.html.tera index 58b912d..bedfac8 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -37,6 +37,12 @@
+ {% if user %} + {% if user.is_admin %} + USER + {% endif %} + LOGOUT + {% endif %}
{% block content %} diff --git a/templates/index.html.tera b/templates/index.html.tera index 86024b9..d2ac294 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -5,22 +5,30 @@ {% set day = day_with_trip.day %} {% set day_string = day.day | date(format="%Y-%m-%d") %} {% set trips = day_with_trip.trips %} - {{ day.day | date(format="%d.%m.%Y")}} +

{{ day.day | date(format="%d.%m.%Y")}}


{% if day.planned_amount_cox > 0%} - Geplante Steuerpersonen: {{ day.planned_amount_cox}}
+ + {% set cox = trips | filter(attribute="user.is_cox", value=true) %} + {% set amount_cox = cox | length %} + {% set rowers = trips | filter(attribute="user.is_cox", value=false) %} + {% if amount_cox < day.planned_amount_cox %} + {% set cox_left = day.planned_amount_cox - amount_cox %} + Es {{ cox_left | pluralize(singular="wird", plural="werden")}} noch {{ cox_left }} Steuerperson{{ cox_left | pluralize(plural="en")}} gesucht!
+ {% endif %} Geplante Abfahrtszeit: {{ day.planned_starting_time }}
- Angemeldete Personen: + {{ trips | length }} angemeldete Person{{ trips | length | pluralize(plural="en") }}: {{ cox | length }} Steuerperson{{ cox | length | pluralize(plural="en") }} ({% for c in cox %}{{ c.user.name }} {% endfor %}), {{ rowers | length }} Ruderer: +
    - {% for trip in trips %} -
  1. {{ trip.user.name }}
  2. + {% for r in rowers %} +
  3. {{ r.user.name }} (angemeldet seit {{ r.trip.created }})
  4. {% endfor %}
- {% if day.open_registration %} + {% if day.open_registration or user.is_cox %}
+
@@ -43,7 +51,8 @@ {% else %} (Noch) keine Ausfahrt geplant {% endif %} - + + {% if user.is_admin %}
@@ -69,7 +78,7 @@
- + {% endif %}
{% endfor %} diff --git a/templates/name.html.tera b/templates/name.html.tera index 3502458..57e0bc8 100644 --- a/templates/name.html.tera +++ b/templates/name.html.tera @@ -1,11 +1,11 @@ {% extends "base" %} {% block content %} -What's your name?
- - + + +
{% endblock content %} diff --git a/templates/user/index.html.tera b/templates/user/index.html.tera new file mode 100644 index 0000000..858e734 --- /dev/null +++ b/templates/user/index.html.tera @@ -0,0 +1,35 @@ +{% extends "base" %} +{% block content %} + + + + + + + + + + + + {% for user in users %} + + + + + + + + {% endfor %} + +
NameCoxAdminAction
{{user.name}} + + + + + +
+ +{% endblock content %} +