diff --git a/src/model/logbook.rs b/src/model/logbook.rs index b3e4253..805c4ae 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -226,6 +226,38 @@ ORDER BY departure DESC ret } + pub async fn completed_with_user( + db: &SqlitePool, + user: &User, + ) -> Vec { + let logs = sqlx::query_as( + &format!(" + SELECT id, boat_id, shipmaster, steering_person, shipmaster_only_steering, departure, arrival, destination, distance_in_km, comments, logtype + FROM logbook + JOIN rower ON logbook.id = rower.logbook_id + WHERE arrival is not null AND rower_id = {} + ORDER BY departure DESC + ", user.id) + ) + .fetch_all(db) + .await + .unwrap(); //TODO: fixme + + let mut ret = Vec::new(); + for log in logs { + ret.push(LogbookWithBoatAndRowers { + rowers: Rower::for_log(db, &log).await, + boat: Boat::find_by_id(db, log.boat_id as i32).await.unwrap(), + shipmaster_user: User::find_by_id(db, log.shipmaster as i32).await.unwrap(), + steering_user: User::find_by_id(db, log.steering_person as i32) + .await + .unwrap(), + logbook: log, + }); + } + ret + } + pub async fn completed(db: &SqlitePool) -> Vec { let year = chrono::Utc::now().year(); let logs = sqlx::query_as( diff --git a/src/model/user.rs b/src/model/user.rs index ba7a4b7..00d66a6 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -225,28 +225,6 @@ impl User { .count } - pub async fn rowed_km(&self, db: &SqlitePool) -> i32 { - sqlx::query!( - "SELECT COALESCE(SUM(distance_in_km),0) as rowed_km - FROM ( - SELECT distance_in_km - FROM logbook - WHERE shipmaster = ?1 - UNION - SELECT l.distance_in_km - FROM logbook l - INNER JOIN rower r ON r.logbook_id = l.id - WHERE r.rower_id = ?1 - - );", - self.id, - ) - .fetch_one(db) - .await - .unwrap() - .rowed_km - } - pub async fn has_role(&self, db: &SqlitePool, role: &str) -> bool { if sqlx::query!( "SELECT * FROM user_role WHERE user_id=? AND role_id = (SELECT id FROM role WHERE name = ?)", @@ -379,6 +357,22 @@ ORDER BY last_access DESC .unwrap() } + pub async fn all_with_role(db: &SqlitePool, role: &Role) -> Vec { + sqlx::query_as!( + Self, + " +SELECT id, name, pw, deleted, last_access, dob, weight, sex, member_since_date, birthdate, mail, nickname, notes, phone, address, family_id +FROM user u +JOIN user_role ur ON u.id = ur.user_id +WHERE ur.role_id = ? AND deleted = 0 +ORDER BY name; + ", role.id + ) + .fetch_all(db) + .await + .unwrap() + } + pub async fn all_payer_groups(db: &SqlitePool) -> Vec { sqlx::query_as!( Self, diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index dd2f4d1..82eb4e3 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -2,20 +2,38 @@ use std::collections::HashMap; use crate::model::{ family::Family, + logbook::Logbook, role::Role, user::{AdminUser, User, UserWithRoles, VorstandUser}, }; use futures::future::join_all; use rocket::{ form::Form, - get, post, - request::FlashMessage, + get, + http::Status, + post, + request::{FlashMessage, FromRequest, Outcome}, response::{Flash, Redirect}, - routes, FromForm, Route, State, + routes, FromForm, Request, Route, State, }; use rocket_dyn_templates::{tera::Context, Template}; use sqlx::SqlitePool; +// Custom request guard to extract the Referer header +struct Referer(String); + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for Referer { + type Error = (); + + async fn from_request(request: &'r Request<'_>) -> Outcome { + match request.headers().get_one("Referer") { + Some(referer) => Outcome::Success(Referer(referer.to_string())), + None => Outcome::Error((Status::BadRequest, ())), + } + } +} + #[get("/user")] async fn index( db: &State, @@ -111,11 +129,43 @@ async fn fees( Template::render("admin/user/fees", context.into_json()) } +#[get("/user/scheckbuch")] +async fn scheckbuch( + db: &State, + user: VorstandUser, + flash: Option>, +) -> Template { + let mut context = Context::new(); + + let scheckbooks = Role::find_by_name(db, "scheckbuch").await.unwrap(); + let scheckbooks = User::all_with_role(db, &scheckbooks).await; + let mut scheckbooks_with_roles = Vec::new(); + for s in scheckbooks { + scheckbooks_with_roles.push(( + Logbook::completed_with_user(db, &s).await, + UserWithRoles::from_user(s, db).await, + )) + } + + context.insert("scheckbooks", &scheckbooks_with_roles); + + if let Some(msg) = flash { + context.insert("flash", &msg.into_inner()); + } + context.insert( + "loggedin_user", + &UserWithRoles::from_user(user.into(), db).await, + ); + + Template::render("admin/user/scheckbuch", context.into_json()) +} + #[get("/user/fees/paid?")] async fn fees_paid( db: &State, _admin: AdminUser, user_ids: Vec, + referer: Referer, ) -> Flash { let mut res = String::new(); for user_id in user_ids { @@ -133,7 +183,7 @@ async fn fees_paid( res.truncate(res.len() - 3); // remove ' + ' from the end Flash::success( - Redirect::to("/admin/user/fees"), + Redirect::to(referer.0), format!("Zahlungsstatus von {} erfolgreich geändert", res), ) } @@ -234,6 +284,7 @@ pub fn routes() -> Vec { create, delete, fees, - fees_paid + fees_paid, + scheckbuch ] } diff --git a/src/tera/planned.rs b/src/tera/planned.rs index 4268e3a..468bd05 100644 --- a/src/tera/planned.rs +++ b/src/tera/planned.rs @@ -10,6 +10,7 @@ use tera::Context; use crate::model::{ log::Log, + logbook::Logbook, tripdetails::TripDetails, triptype::TripType, user::{AllowedForPlannedTripsUser, User, UserWithRoles}, @@ -31,6 +32,11 @@ async fn index( context.insert("trip_types", &triptypes); } + if user.has_role(db, "scheckbuch").await { + let last_trips = Logbook::completed_with_user(db, &user).await; + context.insert("last_trips", &last_trips); + } + let days = user.get_days(db).await; if let Some(msg) = flash { diff --git a/templates/admin/list/result.html.tera b/templates/admin/list/result.html.tera index bc4c6b3..ae43182 100644 --- a/templates/admin/list/result.html.tera +++ b/templates/admin/list/result.html.tera @@ -4,10 +4,8 @@ {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %}

List - Result

-
    - {% for person in result%} -
  1. {{person}}
  2. - {% endfor %} -
+
    + {% for person in result %}
  1. {{ person }}
  2. {% endfor %} +
{% endblock content %} diff --git a/templates/admin/user/scheckbuch.html.tera b/templates/admin/user/scheckbuch.html.tera new file mode 100644 index 0000000..9353549 --- /dev/null +++ b/templates/admin/user/scheckbuch.html.tera @@ -0,0 +1,43 @@ +{% import "includes/macros" as macros %} +{% import "includes/forms/log" as log %} +{% extends "base" %} +{% block content %} +
+ {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} +

Scheckbücher

+ +
+ + +
+ +
+
+ {% for scheckbook in scheckbooks %} + {% set user = scheckbook.1 %} + {% set trips = scheckbook.0 %} +
+
+
+ {{ user.name }} - {{ trips | length }} Ausfahrten + {% for trip in trips %} +
  • {{ log::show_old(log=trip, state="completed", only_ones=false, index=loop.index) }}
  • + {% endfor %} +
    + {% if "admin" in loggedin_user.roles %} + Zahlungsstatus ändern + {% endif %} +
    +
    + {% endfor %} +
    +
    +{% endblock content %} diff --git a/templates/includes/forms/log.html.tera b/templates/includes/forms/log.html.tera index d8fbddf..f376879 100644 --- a/templates/includes/forms/log.html.tera +++ b/templates/includes/forms/log.html.tera @@ -181,7 +181,9 @@ {% endif %}
    {{ log.boat.name }} ({{ log.shipmaster_user.name -}} - {% if log.shipmaster_only_steering %}- handgesteuert{% endif -%} + {% if log.shipmaster_only_steering %} + - handgesteuert + {% endif -%} ) {% if state == "completed" and log.departure | date(format='%d.%m.%Y') == log.arrival | date(format='%d.%m.%Y') %} diff --git a/templates/index.html.tera b/templates/index.html.tera index c537657..dec52f8 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -89,6 +89,9 @@
  • Übersicht User Gebühren
  • +
  • + Scheckbuch +
  • User
  • diff --git a/templates/planned.html.tera b/templates/planned.html.tera index 7f61482..bb4219d 100644 --- a/templates/planned.html.tera +++ b/templates/planned.html.tera @@ -1,9 +1,26 @@ {% import "includes/macros" as macros %} +{% import "includes/forms/log" as log %} {% extends "base" %} {% block content %}
    {% if flash %}{{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }}{% endif %} - {% if "paid" not in loggedin_user.roles %} + {% if "scheckbuch" in loggedin_user.roles %} +
    + +
    + {% endif %} + {% if "paid" not in loggedin_user.roles and "Donau Linz" in loggedin_user.roles %}