From 432962f5a9572524f2dfc767149dda310b5f8859 Mon Sep 17 00:00:00 2001 From: philipp Date: Thu, 9 Feb 2023 17:08:07 +0100 Subject: [PATCH] push --- db.sqlite | Bin 40960 -> 57344 bytes migration/src/m20230208_114547_create_day.rs | 6 +-- migration/src/m20230209_074936_create_trip.rs | 3 +- src/models/user.rs | 25 +++++++++++ src/rest/mod.rs | 24 ++++++++-- src/rest/restreg.rs | 4 ++ src/rest/restuser.rs | 42 ++++++++++++++++++ templates/base.html.tera | 6 +++ templates/index.html.tera | 25 +++++++---- templates/name.html.tera | 6 +-- templates/user/index.html.tera | 35 +++++++++++++++ 11 files changed, 156 insertions(+), 20 deletions(-) create mode 100644 src/rest/restuser.rs create mode 100644 templates/user/index.html.tera diff --git a/db.sqlite b/db.sqlite index 8289edb9f740e2ffedfa3a6b19d1e682bfdf5da1..c918d5fb4cacad8016e21f0070c42f32e4651eab 100644 GIT binary patch literal 57344 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 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 %} +