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))
|
|
}
|