824 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			824 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use super::{CreateError, LastContactTeam, Team};
 | 
						|
use crate::{
 | 
						|
    admin::{route::Route, station::Station},
 | 
						|
    er,
 | 
						|
    models::rating::Rating,
 | 
						|
    partials::page,
 | 
						|
    suc, AppState,
 | 
						|
};
 | 
						|
use axum::{
 | 
						|
    extract::State,
 | 
						|
    response::{IntoResponse, Redirect},
 | 
						|
    routing::{get, post},
 | 
						|
    Form, Router,
 | 
						|
};
 | 
						|
use maud::{html, Markup, PreEscaped};
 | 
						|
use serde::Deserialize;
 | 
						|
use sqlx::SqlitePool;
 | 
						|
use std::{collections::HashMap, sync::Arc};
 | 
						|
use tower_sessions::Session;
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct CreateForm {
 | 
						|
    name: String,
 | 
						|
    route_id: i64,
 | 
						|
}
 | 
						|
 | 
						|
async fn create(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    Form(form): Form<CreateForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(route) = Route::find_by_id(&db, form.route_id).await else {
 | 
						|
        er!(session, t!("nonexisting_route", id = form.route_id));
 | 
						|
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    let id = match Team::create(&db, &form.name, &route).await {
 | 
						|
        Ok(id) => {
 | 
						|
            suc!(session, t!("team_created", team = form.name));
 | 
						|
            id
 | 
						|
        }
 | 
						|
        Err(CreateError::DuplicateName(e)) => {
 | 
						|
            er!(
 | 
						|
                session,
 | 
						|
                t!("team_not_created_duplicate_name", team = form.name, err = e)
 | 
						|
            );
 | 
						|
 | 
						|
            return Redirect::to("/admin/team");
 | 
						|
        }
 | 
						|
        Err(CreateError::NoStationForRoute) => {
 | 
						|
            er!(
 | 
						|
                session,
 | 
						|
                t!(
 | 
						|
                    "team_not_created_no_station_in_route",
 | 
						|
                    team = form.name,
 | 
						|
                    route = route.name
 | 
						|
                )
 | 
						|
            );
 | 
						|
 | 
						|
            return Redirect::to("/admin/team");
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
async fn delete(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    match team.delete(&db).await {
 | 
						|
        Ok(()) => suc!(session, t!("team_deleted", team = team.name)),
 | 
						|
        Err(e) => er!(
 | 
						|
            session,
 | 
						|
            t!("team_not_deleted_already_in_use", team = team.name, err = e)
 | 
						|
        ),
 | 
						|
    }
 | 
						|
 | 
						|
    Redirect::to("/admin/team")
 | 
						|
}
 | 
						|
 | 
						|
async fn quick(db: Arc<SqlitePool>, team: &Team, stations: Vec<Station>, redirect: &str) -> Markup {
 | 
						|
    html! {
 | 
						|
        h1 {
 | 
						|
            a href=(format!("/admin/team/{}", team.id)) { "↩️" }
 | 
						|
            (t!("ratings"))
 | 
						|
            " "
 | 
						|
            (t!("team"))
 | 
						|
            " "
 | 
						|
            (team.name)
 | 
						|
        }
 | 
						|
        form action=(format!("/admin/team/{}/quick", team.id)) method="post" {
 | 
						|
            input type="hidden" name="redirect" value=(redirect);
 | 
						|
            table {
 | 
						|
                thead {
 | 
						|
                    tr {
 | 
						|
                        th { (t!("station")) }
 | 
						|
                        th { (t!("points")) }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                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=(t!("already_entered")) {
 | 
						|
                                                (points)
 | 
						|
                                            }
 | 
						|
                                        } @else {
 | 
						|
                                            em data-tooltip=(t!("team_currently_at_station")) { "?" }
 | 
						|
                                        }
 | 
						|
                                    }
 | 
						|
                                } @else {
 | 
						|
                                    input type="number" min="0" max="10" name=(station.id);
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            input type="submit" value=(t!("save"));
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
async fn quick_crewless(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
) -> Result<Markup, impl IntoResponse> {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Err(Redirect::to("/admin/team"));
 | 
						|
    };
 | 
						|
 | 
						|
    let stations: Vec<Station> = team.route(&db).await.crewless_stations(&db).await;
 | 
						|
 | 
						|
    let content = quick(db, &team, stations, "/crewless").await;
 | 
						|
 | 
						|
    Ok(page(content, session, true).await)
 | 
						|
}
 | 
						|
 | 
						|
async fn quick_all(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
) -> Result<Markup, impl IntoResponse> {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Err(Redirect::to("/admin/team"));
 | 
						|
    };
 | 
						|
 | 
						|
    let stations = team.route(&db).await.stations(&db).await;
 | 
						|
 | 
						|
    let content = quick(db, &team, stations, "").await;
 | 
						|
 | 
						|
    Ok(page(content, session, true).await)
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize, Debug)]
 | 
						|
struct QuickUpdate {
 | 
						|
    redirect: String,
 | 
						|
    #[serde(flatten)]
 | 
						|
    fields: HashMap<String, String>,
 | 
						|
}
 | 
						|
async fn quick_post(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<QuickUpdate>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    let mut ret = String::new();
 | 
						|
    let mut amount_succ = 0;
 | 
						|
 | 
						|
    for (station_id, points) in &form.fields {
 | 
						|
        let Ok(station_id) = station_id.parse::<i64>() else {
 | 
						|
            ret.push_str(&format!(
 | 
						|
                "Skipped stationid={station_id} because this id can't be parsed as i64"
 | 
						|
            ));
 | 
						|
            continue;
 | 
						|
        };
 | 
						|
        let Ok(points) = points.parse::<i64>() else {
 | 
						|
            ret.push_str(&format!(
 | 
						|
                "Skipped stationid={station_id} because points {points} can't be parsed as i64",
 | 
						|
            ));
 | 
						|
            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()
 | 
						|
        {
 | 
						|
            let msg: String = t!(
 | 
						|
                "error_rating_team_already_rated",
 | 
						|
                team = team.name,
 | 
						|
                station = station.name
 | 
						|
            )
 | 
						|
            .into();
 | 
						|
            ret.push_str(&msg);
 | 
						|
            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 {
 | 
						|
        suc!(session, t!("funny_you_entered_no_rating"));
 | 
						|
    } else {
 | 
						|
        suc!(session, t!("entered_n_ratings", amount = amount_succ));
 | 
						|
    }
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}/quick{}", form.redirect))
 | 
						|
}
 | 
						|
 | 
						|
async fn view(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
) -> Result<Markup, impl IntoResponse> {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Err(Redirect::to("/admin/team"));
 | 
						|
    };
 | 
						|
    let first_station = team.first_station(&db).await;
 | 
						|
    let last_station = team.last_station(&db).await;
 | 
						|
    let routes = Route::all(&db).await;
 | 
						|
 | 
						|
    let stations = team.route(&db).await.crewful_stations(&db).await;
 | 
						|
 | 
						|
    // maybe switch to maud-display impl of team
 | 
						|
    let content = html! {
 | 
						|
        h1 {
 | 
						|
            a href="/admin/team" { "↩️" }
 | 
						|
            (t!("team"))
 | 
						|
            " "
 | 
						|
            (team.name)
 | 
						|
        }
 | 
						|
        article {
 | 
						|
            details {
 | 
						|
                summary {
 | 
						|
                    (t!("edit_teamname"))
 | 
						|
                    " ✏️"
 | 
						|
                }
 | 
						|
                form action=(format!("/admin/team/{}/name", team.id)) method="post" {
 | 
						|
                    input type="text" name="name" value=(team.name) required;
 | 
						|
                    input type="submit" value=(t!("save"));
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
        table {
 | 
						|
            tbody {
 | 
						|
                tr {
 | 
						|
                    th scope="row" { (t!("notes")) };
 | 
						|
                    td {
 | 
						|
                        @match &team.notes {
 | 
						|
                            Some(notes) => {
 | 
						|
                                (notes)
 | 
						|
                                details {
 | 
						|
                                summary { "✏️" }
 | 
						|
                                form action=(format!("/admin/team/{}/notes", team.id)) method="post" {
 | 
						|
                                        textarea name="notes" required rows="10" { (notes) };
 | 
						|
                                        input type="submit" value=(t!("save"));
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                            },
 | 
						|
                            None => details {
 | 
						|
                                summary { (t!("add_new_note")) }
 | 
						|
                                form action=(format!("/admin/team/{}/notes", team.id)) method="post" {
 | 
						|
                                        textarea name="notes" required rows="10" {};
 | 
						|
                                        input type="submit" value=(t!("save"));
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                tr {
 | 
						|
                    th scope="row" { (t!("amount_teammembers")) };
 | 
						|
                    td {
 | 
						|
                        @match team.amount_people {
 | 
						|
                            Some(amount) => (amount),
 | 
						|
                            None => "?",
 | 
						|
                        }
 | 
						|
                                details {
 | 
						|
                                summary { "✏️" }
 | 
						|
                                form action=(format!("/admin/team/{}/amount-people", team.id)) method="post" {
 | 
						|
                                    input type="number" name="amount_people" min="0" max="10";
 | 
						|
                                    input type="submit" value=(t!("save"));
 | 
						|
                            }
 | 
						|
                                a href=(format!("/admin/team/{}/amount-people-reset", team.id)) {
 | 
						|
                                    button class="error" {
 | 
						|
                                        em data-tooltip=(t!("not_sure_about_amount_team")) {
 | 
						|
                                            "?"
 | 
						|
                                        }
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                tr {
 | 
						|
                    th scope="row" { (t!("route")) };
 | 
						|
                    td {
 | 
						|
                            a href=(format!("/admin/route/{}", &team.route(&db).await.id)) {
 | 
						|
                                (&team.route(&db).await.name)
 | 
						|
                            }
 | 
						|
                        @if routes.len() > 1 {
 | 
						|
                            details {
 | 
						|
                                summary { "✏️" }
 | 
						|
                                form action=(format!("/admin/team/{}/update-route", team.id)) method="post" {
 | 
						|
                                        select name="route_id" aria-label=(t!("select_route")) required {
 | 
						|
                                            @for route in &routes {
 | 
						|
                                                @if route.id != team.route(&db).await.id {
 | 
						|
                                                    option value=(route.id) {
 | 
						|
                                                        (route.name)
 | 
						|
                                                    }
 | 
						|
                                                }
 | 
						|
                                            }
 | 
						|
                                        }
 | 
						|
                                        input type="submit" value=(t!("save"));
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                tr {
 | 
						|
                    th scope="row" {
 | 
						|
                        (t!("first_station"))
 | 
						|
                        article {
 | 
						|
                            (t!("first_station_expl"))
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
                    td {
 | 
						|
                        a href=(format!("/admin/station/{}", first_station.id)) {
 | 
						|
                            (first_station.name)
 | 
						|
                        }
 | 
						|
                        @if stations.len() > 1 {
 | 
						|
                            details {
 | 
						|
                                summary { "✏️" }
 | 
						|
                                form action=(format!("/admin/team/{}/update-first-station", team.id)) method="post" {
 | 
						|
                                        select name="first_station_id" aria-label=(t!("select_station")) required {
 | 
						|
                                            @for station in &stations {
 | 
						|
                                                @if station.id != first_station.id {
 | 
						|
                                                    option value=(station.id) {
 | 
						|
                                                        (station.name)
 | 
						|
                                                        @let amount_start_teams = Team::all_with_first_station(&db, station).await.len();
 | 
						|
                                                        @if amount_start_teams > 0 {
 | 
						|
                                                            @if amount_start_teams == 1 {
 | 
						|
                                                                (t!("already_has_1_start_team"))
 | 
						|
                                                            }@else{
 | 
						|
                                                                (t!("already_has_n_start_team", amount=amount_start_teams))
 | 
						|
                                                            }
 | 
						|
                                                        }
 | 
						|
                                                    }
 | 
						|
                                                }
 | 
						|
                                            }
 | 
						|
                                        }
 | 
						|
                                        input type="submit" value=(t!("save"));
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                @if let Some(last_station) = last_station {
 | 
						|
                    tr {
 | 
						|
                        th scope="row" {
 | 
						|
                            (t!("last_station"))
 | 
						|
                        };
 | 
						|
                        td {
 | 
						|
                            a href=(format!("/admin/station/{}", last_station.id)) {
 | 
						|
                                (last_station.name)
 | 
						|
                            }
 | 
						|
                            @if stations.len() > 1 {
 | 
						|
                                details {
 | 
						|
                                    summary { "✏️" }
 | 
						|
                                    form action=(format!("/admin/team/{}/update-last-station", team.id)) method="post" {
 | 
						|
                                            select name="last_station_id" aria-label=(t!("select_station")) required {
 | 
						|
                                                @for station in &stations {
 | 
						|
                                                    @if station.id != last_station.id {
 | 
						|
                                                        option value=(station.id) {
 | 
						|
                                                            (station.name)
 | 
						|
                                                        }
 | 
						|
                                                    }
 | 
						|
                                                }
 | 
						|
                                            }
 | 
						|
                                            input type="submit" value=(t!("save"));
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
        a href=(format!("/admin/team/{}/quick", team.id)){
 | 
						|
            button {
 | 
						|
                (t!("ratings"))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        hr;
 | 
						|
        a href=(format!("/admin/team/{}/quick/crewless", team.id)){
 | 
						|
            button {
 | 
						|
                (t!("rate_crewless_stations"))
 | 
						|
            }
 | 
						|
        }
 | 
						|
    };
 | 
						|
    Ok(page(content, session, true).await)
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct UpdateNameForm {
 | 
						|
    name: String,
 | 
						|
}
 | 
						|
async fn update_name(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<UpdateNameForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    team.update_name(&db, &form.name).await;
 | 
						|
 | 
						|
    suc!(
 | 
						|
        session,
 | 
						|
        t!("new_team_name", old = team.name, new = form.name)
 | 
						|
    );
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct UpdateNotesForm {
 | 
						|
    notes: String,
 | 
						|
}
 | 
						|
async fn update_notes(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<UpdateNotesForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    team.update_notes(&db, &form.notes).await;
 | 
						|
 | 
						|
    suc!(session, t!("notes_edited", team = team.name));
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct UpdateAmountPeopleForm {
 | 
						|
    amount_people: i64,
 | 
						|
}
 | 
						|
async fn update_amount_people(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<UpdateAmountPeopleForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    team.update_amount_people(&db, form.amount_people).await;
 | 
						|
 | 
						|
    suc!(session, t!("amount_teammembers_edited", team = team.name));
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct UpdateRouteForm {
 | 
						|
    route_id: i64,
 | 
						|
}
 | 
						|
async fn update_route(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<UpdateRouteForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    // TODO: move sanity checks into mod.rs
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    let Some(route) = Route::find_by_id(&db, form.route_id).await else {
 | 
						|
        er!(session, t!("nonexisting_route", id = form.route_id));
 | 
						|
        return Redirect::to(&format!("/admin/team/{id}"));
 | 
						|
    };
 | 
						|
 | 
						|
    match team.update_route(&db, &route).await {
 | 
						|
        Ok(new_first_station_name) => suc!(
 | 
						|
            session,
 | 
						|
            t!(
 | 
						|
                "route_edited",
 | 
						|
                team = team.name,
 | 
						|
                route = route.name,
 | 
						|
                first_station = new_first_station_name
 | 
						|
            )
 | 
						|
        ),
 | 
						|
        Err(()) => er!(
 | 
						|
            session,
 | 
						|
            t!(
 | 
						|
                "team_not_edited_route_has_no_stations",
 | 
						|
                team = team.name,
 | 
						|
                route = route.name
 | 
						|
            )
 | 
						|
        ),
 | 
						|
    }
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct UpdateFirstStationForm {
 | 
						|
    first_station_id: i64,
 | 
						|
}
 | 
						|
async fn update_first_station(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<UpdateFirstStationForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    let Some(station) = Station::find_by_id(&db, form.first_station_id).await else {
 | 
						|
        er!(
 | 
						|
            session,
 | 
						|
            t!("nonexisting_station", id = form.first_station_id)
 | 
						|
        );
 | 
						|
 | 
						|
        return Redirect::to(&format!("/admin/team/{id}"));
 | 
						|
    };
 | 
						|
 | 
						|
    if !station.is_in_route(&db, &team.route(&db).await).await {
 | 
						|
        er!(
 | 
						|
            session,
 | 
						|
            t!(
 | 
						|
                "first_station_not_edited_not_on_route",
 | 
						|
                station = station.name,
 | 
						|
                team = team.name,
 | 
						|
                route = team.route(&db).await.name
 | 
						|
            )
 | 
						|
        );
 | 
						|
 | 
						|
        return Redirect::to(&format!("/admin/team/{id}"));
 | 
						|
    }
 | 
						|
 | 
						|
    team.update_first_station(&db, &station).await;
 | 
						|
 | 
						|
    suc!(
 | 
						|
        session,
 | 
						|
        t!(
 | 
						|
            "changed_first_station",
 | 
						|
            team = team.name,
 | 
						|
            station = station.name
 | 
						|
        )
 | 
						|
    );
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize)]
 | 
						|
struct UpdateLastStationForm {
 | 
						|
    last_station_id: i64,
 | 
						|
}
 | 
						|
async fn update_last_station(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
    Form(form): Form<UpdateLastStationForm>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    let Some(station) = Station::find_by_id(&db, form.last_station_id).await else {
 | 
						|
        er!(
 | 
						|
            session,
 | 
						|
            t!("nonexisting_station", id = form.last_station_id)
 | 
						|
        );
 | 
						|
        return Redirect::to(&format!("/admin/team/{id}"));
 | 
						|
    };
 | 
						|
 | 
						|
    if !station.is_in_route(&db, &team.route(&db).await).await {
 | 
						|
        er!(
 | 
						|
            session,
 | 
						|
            t!(
 | 
						|
                "last_station_not_edited_not_on_route",
 | 
						|
                station = station.name,
 | 
						|
                team = team.name,
 | 
						|
                route = team.route(&db).await.name
 | 
						|
            )
 | 
						|
        );
 | 
						|
 | 
						|
        return Redirect::to(&format!("/admin/team/{id}"));
 | 
						|
    }
 | 
						|
 | 
						|
    team.update_last_station(&db, &station).await;
 | 
						|
 | 
						|
    suc!(
 | 
						|
        session,
 | 
						|
        t!(
 | 
						|
            "changed_last_station",
 | 
						|
            team = team.name,
 | 
						|
            station = station.name
 | 
						|
        )
 | 
						|
    );
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
async fn update_amount_people_reset(
 | 
						|
    State(db): State<Arc<SqlitePool>>,
 | 
						|
    session: Session,
 | 
						|
    axum::extract::Path(id): axum::extract::Path<i64>,
 | 
						|
) -> impl IntoResponse {
 | 
						|
    let Some(team) = Team::find_by_id(&db, id).await else {
 | 
						|
        er!(session, t!("nonexisting_team", id = id));
 | 
						|
        return Redirect::to("/admin/team");
 | 
						|
    };
 | 
						|
 | 
						|
    team.update_amount_people_reset(&db).await;
 | 
						|
 | 
						|
    suc!(session, t!("amount_teammembers_edited", team = team.name));
 | 
						|
 | 
						|
    Redirect::to(&format!("/admin/team/{id}"))
 | 
						|
}
 | 
						|
 | 
						|
async fn lost(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
 | 
						|
    let losts = LastContactTeam::all_sort_missing(&db).await;
 | 
						|
 | 
						|
    let content = html! {
 | 
						|
        h1 {
 | 
						|
            a href="/admin/team" { "↩️" }
 | 
						|
            (t!("last_contact_team"))
 | 
						|
        }
 | 
						|
        div class="overflow-auto" {
 | 
						|
            table {
 | 
						|
                thead {
 | 
						|
                    tr {
 | 
						|
                        td { (t!("team")) }
 | 
						|
                        td { (t!("time")) }
 | 
						|
                        td { (t!("station")) }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                tbody {
 | 
						|
                    @for lost in &losts {
 | 
						|
                        tr {
 | 
						|
                            td {
 | 
						|
                                a href=(format!("/admin/team/{}", lost.team.id)) {
 | 
						|
                                    (lost.team.name)
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                            td {
 | 
						|
                                @if let Some(time) = lost.local_last_contact() {
 | 
						|
                                    (time)
 | 
						|
                                }@else{
 | 
						|
                                    (t!("not_yet_seen"))
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                            td {
 | 
						|
                                @if let Some(station) = &lost.station {
 | 
						|
                                    a href=(format!("/admin/station/{}", station.id)) {
 | 
						|
                                        (station.name)
 | 
						|
                                    }
 | 
						|
                                }@else{
 | 
						|
                                    (t!("not_yet_seen"))
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    page(content, session, false).await
 | 
						|
}
 | 
						|
 | 
						|
async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
 | 
						|
    let teams = Team::all(&db).await;
 | 
						|
    let routes = Route::all(&db).await;
 | 
						|
 | 
						|
    let content = html! {
 | 
						|
        h1 {
 | 
						|
            a href="/admin" { "↩️" }
 | 
						|
            (t!("teams"))
 | 
						|
        }
 | 
						|
        article {
 | 
						|
            em { (t!("teams")) }
 | 
						|
            "sind eine Menge an Personen, die verschiedene "
 | 
						|
            a href="/admin/station" { "Stationen" }
 | 
						|
            " ablaufen. Welche Stationen, entscheidet sich je nachdem, welcher "
 | 
						|
            a href="/admin/route" { "Route" }
 | 
						|
            " sie zugewiesen sind."
 | 
						|
        }
 | 
						|
        @if teams.is_empty() {
 | 
						|
            article class="warning" {
 | 
						|
                (t!("no_teams"))
 | 
						|
                @if !routes.is_empty() {
 | 
						|
                    (t!("change_that_below"))
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        article {
 | 
						|
            h2 { (t!("new_team")) }
 | 
						|
            @if routes.is_empty() {
 | 
						|
                article class="error" {
 | 
						|
                    (t!("route_needed_before_creating_teams"))
 | 
						|
                    (PreEscaped(" → "))
 | 
						|
                    a role="button" href="/admin/route" {
 | 
						|
                        (t!("create_route"))
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            } @else {
 | 
						|
                form action="/admin/team" method="post" {
 | 
						|
                    @if routes.len() == 1 {
 | 
						|
                        fieldset role="group" {
 | 
						|
                            input type="text" name="name" placeholder=(t!("teamname")) required;
 | 
						|
                            input type="hidden" name="route_id" value=(routes[0].id) ;
 | 
						|
                            input type="submit" value="Neues Team";
 | 
						|
                        }
 | 
						|
                    } @else {
 | 
						|
                        input type="text" name="name" placeholder=(t!("teamname")) required;
 | 
						|
                        select name="route_id" aria-label=(t!("select_route")) required {
 | 
						|
                            @for route in &routes {
 | 
						|
                                option value=(route.id) {
 | 
						|
                                    (route.name)
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        input type="submit" value=(t!("new_team"));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        a href="/admin/team/lost" {
 | 
						|
            button class="outline" {
 | 
						|
                (t!("have_i_lost_groups"))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        @for route in &routes {
 | 
						|
            h2 { (route.name) }
 | 
						|
            ol {
 | 
						|
                @for team in &route.teams(&db).await{
 | 
						|
                    li {
 | 
						|
                         a href=(format!("/admin/team/{}", team.id)){
 | 
						|
                            (team.name)
 | 
						|
                         }
 | 
						|
                         a href=(format!("/admin/team/{}/delete", team.id))
 | 
						|
                           onclick=(format!("return confirm('{}');", t!("confirm_delete_team"))) {
 | 
						|
                             "🗑️"
 | 
						|
                         }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    };
 | 
						|
    page(content, session, false).await
 | 
						|
}
 | 
						|
 | 
						|
pub(super) fn routes() -> Router<AppState> {
 | 
						|
    Router::new()
 | 
						|
        .route("/", get(index))
 | 
						|
        .route("/", post(create))
 | 
						|
        .route("/lost", get(lost))
 | 
						|
        .route("/{id}", get(view))
 | 
						|
        .route("/{id}/delete", get(delete))
 | 
						|
        .route("/{id}/quick", get(quick_all))
 | 
						|
        .route("/{id}/quick/crewless", get(quick_crewless))
 | 
						|
        .route("/{id}/quick", post(quick_post))
 | 
						|
        .route("/{id}/name", post(update_name))
 | 
						|
        .route("/{id}/notes", post(update_notes))
 | 
						|
        .route("/{id}/amount-people", post(update_amount_people))
 | 
						|
        .route("/{id}/amount-people-reset", get(update_amount_people_reset))
 | 
						|
        .route("/{id}/update-route", post(update_route))
 | 
						|
        .route("/{id}/update-first-station", post(update_first_station))
 | 
						|
        .route("/{id}/update-last-station", post(update_last_station))
 | 
						|
}
 |