diff --git a/src/admin/team/web.rs b/src/admin/team/web.rs index 879de91..87d04fc 100644 --- a/src/admin/team/web.rs +++ b/src/admin/team/web.rs @@ -2,6 +2,7 @@ use super::{CreateError, LastContactTeam, Team}; use crate::{ admin::{route::Route, station::Station}, err, + models::rating::Rating, partials::page, pl, succ, AppState, }; @@ -14,7 +15,7 @@ use axum::{ use maud::{html, Markup, PreEscaped}; use serde::Deserialize; use sqlx::SqlitePool; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use tower_sessions::Session; #[derive(Deserialize)] @@ -94,6 +95,142 @@ async fn delete( Redirect::to("/admin/team") } +async fn quick( + State(db): State>, + session: Session, + axum::extract::Path(id): axum::extract::Path, +) -> Result { + let Some(team) = Team::find_by_id(&db, id).await else { + err!( + session, + "Team mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert" + ); + + return Err(Redirect::to("/admin/team")); + }; + + let stations = team.route(&db).await.stations(&db).await; + + // maybe switch to maud-display impl of team + let content = html! { + h1 { + a href=(format!("/admin/team/{}", team.id)) { "↩️" } + "Bewertungen Team " (team.name) + } + form action=(format!("/admin/team/{}/quick", team.id)) method="post" { + table { + thead { + tr { + th { "Station" } + th { "Punkte" } + } + } + tbody { + @for station in &stations { + tr { + td { + a href=(format!("/admin/station/{}", station.id)) { + (station.name) + } + } + td { + @if let Some(rating) = Rating::find_by_team_and_station(&db, &team, &station).await { + a href=(format!("/s/{}/{}", station.id, station.pw)){ + @if let Some(points) = rating.points { + em data-tooltip="Schon eingetragen" { + (points) + } + } @else { + em data-tooltip="Team gerade bei Station" { "?" } + } + } + } @else { + input type="number" min="0" max="10" name=(station.id); + } + } + + } + } + } + } + input type="submit" value="Speichern"; + } + }; + Ok(page(content, session, true).await) +} + +#[derive(Deserialize, Debug)] +struct QuickUpdate { + #[serde(flatten)] + fields: HashMap, +} +async fn quick_post( + State(db): State>, + session: Session, + axum::extract::Path(id): axum::extract::Path, + Form(form): Form, +) -> impl IntoResponse { + let Some(team) = Team::find_by_id(&db, id).await else { + err!( + session, + "Team mit ID {id} konnte nicht bearbeitet werden, da sie nicht existiert" + ); + + return Redirect::to("/admin/team"); + }; + + let mut ret = String::new(); + let mut amount_succ = 0; + + for (station_id, points) in form.fields.iter() { + let Ok(station_id) = station_id.parse::() else { + ret.push_str(&format!( + "Skipped stationid={station_id} because this id can't be parsed as i64" + )); + continue; + }; + let Ok(points) = points.parse::() else { + ret.push_str(&format!( + "Skipped stationid={station_id} because points {} can't be parsed as i64", + points + )); + continue; + }; + let Some(station) = Station::find_by_id(&db, station_id).await else { + ret.push_str(&format!( + "Skipped stationid={station_id} because this station does not exist" + )); + continue; + }; + if Rating::find_by_team_and_station(&db, &team, &station) + .await + .is_some() + { + ret.push_str(&format!("Skipped rating for station {} because this station already has a rating for team {}", station.name, team.name)); + continue; + } + + Rating::create_quick(&db, &team, &station, points).await; + amount_succ += 1; + } + + if !ret.is_empty() { + // TODO: properly log warnings + println!("{ret}"); + } + + if amount_succ == 0 { + succ!( + session, + "Du hast keine Bewertungen eingegeben... Spaßvogel!" + ); + } else { + succ!(session, "Erfolgreich {amount_succ} Bewertungen eingetragen"); + } + + Redirect::to(&format!("/admin/team/{id}/quick")) +} + async fn view( State(db): State>, session: Session, @@ -239,6 +376,13 @@ async fn view( } } + a href=(format!("/admin/team/{}/quick", team.id)){ + button { + "Stations-Bewertungen für Team " + (team.name) + " eingeben" + } + } }; Ok(page(content, session, true).await) } @@ -599,6 +743,8 @@ pub(super) fn routes() -> Router { .route("/lost", get(lost)) .route("/{id}", get(view)) .route("/{id}/delete", get(delete)) + .route("/{id}/quick", post(quick_post)) + .route("/{id}/quick", get(quick)) .route("/{id}/name", post(update_name)) .route("/{id}/notes", post(update_notes)) .route("/{id}/amount-people", post(update_amount_people)) diff --git a/src/models/rating.rs b/src/models/rating.rs index 11894ec..a89c0c0 100644 --- a/src/models/rating.rs +++ b/src/models/rating.rs @@ -31,6 +31,18 @@ impl Rating { Ok(()) } + pub(crate) async fn create_quick(db: &SqlitePool, team: &Team, station: &Station, points: i64) { + sqlx::query!( + "INSERT INTO rating(team_id, station_id, points, arrived_at, started_at, left_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)", + team.id, + station.id, + points + ) + .execute(db) + .await + .unwrap(); + } + pub(crate) async fn team(&self, db: &SqlitePool) -> Team { Team::find_by_id(db, self.team_id) .await