feature: crewless stations; Fixes #2
This commit is contained in:
parent
fb867ff6f2
commit
f5a2901b16
@ -45,6 +45,11 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
|
||||
td {
|
||||
a href=(format!("/admin/station/{}", station.id)){
|
||||
(station.name)
|
||||
@if station.crewless() {
|
||||
em data-tooltip="Station ohne Stationsbetreuer" data-placement="bottom" {
|
||||
small { "🤖" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +150,22 @@ DROP TABLE temp_pos;",
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn crewless_stations(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
self.stations(db)
|
||||
.await
|
||||
.into_iter()
|
||||
.filter(|s| s.crewless())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) async fn crewful_stations(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
self.stations(db)
|
||||
.await
|
||||
.into_iter()
|
||||
.filter(|s| !s.crewless())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn stations_not_in_route(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
// TODO: switch to macro
|
||||
sqlx::query_as::<_, Station>(
|
||||
@ -200,6 +216,7 @@ DROP TABLE temp_pos;",
|
||||
JOIN route_station rs ON s.id = rs.station_id
|
||||
LEFT JOIN 'team' g ON s.id = g.first_station_id
|
||||
WHERE rs.route_id = {}
|
||||
AND (s.amount_people != 0 OR s.amount_people is NULL)
|
||||
GROUP BY s.id
|
||||
ORDER BY team_count ASC, s.id ASC
|
||||
LIMIT 1",
|
||||
|
@ -1,12 +1,12 @@
|
||||
use super::Route;
|
||||
use crate::{AppState, admin::station::Station, err, page, succ};
|
||||
use crate::{admin::station::Station, err, page, succ, AppState};
|
||||
use axum::{
|
||||
Form, Router,
|
||||
extract::State,
|
||||
response::{IntoResponse, Redirect},
|
||||
routing::{get, post},
|
||||
Form, Router,
|
||||
};
|
||||
use maud::{Markup, PreEscaped, html};
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
use serde::Deserialize;
|
||||
use sqlx::SqlitePool;
|
||||
use std::sync::Arc;
|
||||
@ -162,6 +162,11 @@ async fn view(
|
||||
@for (idx, station) in cur_stations.into_iter().enumerate() {
|
||||
li {
|
||||
(station.name)
|
||||
@if station.crewless() {
|
||||
em data-tooltip="Station ohne Stationsbetreuer" {
|
||||
small { "🤖" }
|
||||
}
|
||||
}
|
||||
@if idx > 0 {
|
||||
a href=(format!("/admin/route/{}/move-station-higher/{}", route.id, station.id)){
|
||||
em data-tooltip=(format!("{} nach vor reihen", station.name)) {
|
||||
|
@ -16,7 +16,7 @@ pub(crate) struct Station {
|
||||
pub(crate) id: i64,
|
||||
pub(crate) name: String,
|
||||
notes: Option<String>,
|
||||
amount_people: Option<i64>,
|
||||
pub(crate) amount_people: Option<i64>,
|
||||
last_login: Option<NaiveDateTime>, // TODO use proper timestamp (NaiveDateTime?)
|
||||
pub(crate) pw: String,
|
||||
pub(crate) ready: bool,
|
||||
@ -45,6 +45,13 @@ impl Station {
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn crewless(&self) -> bool {
|
||||
if let Some(amount_people) = self.amount_people {
|
||||
return amount_people == 0;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn login(db: &SqlitePool, id: i64, code: &str) -> Option<Self> {
|
||||
let station = sqlx::query_as!(
|
||||
Self,
|
||||
|
@ -126,15 +126,17 @@ async fn view(
|
||||
}
|
||||
}
|
||||
}
|
||||
tr {
|
||||
th scope="row" { "Stations-Link" };
|
||||
td {
|
||||
a href=(format!("/s/{}/{}", station.id, station.pw)) {
|
||||
"Login-Link"
|
||||
@if !station.crewless() {
|
||||
tr {
|
||||
th scope="row" { "Stations-Link" };
|
||||
td {
|
||||
a href=(format!("/s/{}/{}", station.id, station.pw)) {
|
||||
"Login-Link"
|
||||
|
||||
}
|
||||
article class="warning" {
|
||||
(format!("Diesen Link nur Betreuern der Station {} geben! Mit diesem Link erhält man die Berechtigung, Teams zu bewerten.", station.name))
|
||||
}
|
||||
article class="warning" {
|
||||
(format!("Diesen Link nur Betreuern der Station {} geben! Mit diesem Link erhält man die Berechtigung, Teams zu bewerten.", station.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -161,12 +163,14 @@ async fn view(
|
||||
}
|
||||
}
|
||||
}
|
||||
tr {
|
||||
th scope="row" { "Letzter Zugriff eines Stationsbetreuers" };
|
||||
td {
|
||||
@match station.local_last_login() {
|
||||
Some(last_login) => (last_login),
|
||||
None => "noch nicht eingeloggt :-(",
|
||||
@if !station.crewless() {
|
||||
tr {
|
||||
th scope="row" { "Letzter Zugriff eines Stationsbetreuers" };
|
||||
td {
|
||||
@match station.local_last_login() {
|
||||
Some(last_login) => (last_login),
|
||||
None => "noch nicht eingeloggt :-(",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -672,6 +676,11 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
a href=(format!("/admin/station/{}", station.id)){
|
||||
(station.name)
|
||||
}
|
||||
@if station.crewless() {
|
||||
em data-tooltip="Station ohne Stationsbetreuer" {
|
||||
small { "🤖" }
|
||||
}
|
||||
}
|
||||
}
|
||||
td {
|
||||
em data-tooltip=(format!("{}/{} Teams (davon {} wartend + {} aktiv)", status.total_teams-status.not_yet_here.len() as i64, status.total_teams, status.waiting.len(), status.doing.len())) {
|
||||
|
@ -95,29 +95,14 @@ async fn delete(
|
||||
Redirect::to("/admin/team")
|
||||
}
|
||||
|
||||
async fn quick(
|
||||
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 {
|
||||
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! {
|
||||
async fn quick(db: Arc<SqlitePool>, team: &Team, stations: Vec<Station>, redirect: &str) -> Markup {
|
||||
html! {
|
||||
h1 {
|
||||
a href=(format!("/admin/team/{}", team.id)) { "↩️" }
|
||||
"Bewertungen Team " (team.name)
|
||||
}
|
||||
form action=(format!("/admin/team/{}/quick", team.id)) method="post" {
|
||||
input type="hidden" name="redirect" value=(redirect);
|
||||
table {
|
||||
thead {
|
||||
tr {
|
||||
@ -155,12 +140,53 @@ async fn quick(
|
||||
}
|
||||
input type="submit" value="Speichern";
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
err!(
|
||||
session,
|
||||
"Team mit ID {id} konnte nicht geöffnet werden, da sie nicht existiert"
|
||||
);
|
||||
|
||||
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 {
|
||||
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;
|
||||
|
||||
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>,
|
||||
}
|
||||
@ -228,7 +254,7 @@ async fn quick_post(
|
||||
succ!(session, "Erfolgreich {amount_succ} Bewertungen eingetragen");
|
||||
}
|
||||
|
||||
Redirect::to(&format!("/admin/team/{id}/quick"))
|
||||
Redirect::to(&format!("/admin/team/{id}/quick{}", form.redirect))
|
||||
}
|
||||
|
||||
async fn view(
|
||||
@ -247,7 +273,7 @@ async fn view(
|
||||
let first_station = team.first_station(&db).await;
|
||||
let routes = Route::all(&db).await;
|
||||
|
||||
let stations = team.route(&db).await.stations(&db).await;
|
||||
let stations = team.route(&db).await.crewful_stations(&db).await;
|
||||
|
||||
// maybe switch to maud-display impl of team
|
||||
let content = html! {
|
||||
@ -378,9 +404,13 @@ async fn view(
|
||||
}
|
||||
a href=(format!("/admin/team/{}/quick", team.id)){
|
||||
button {
|
||||
"Stations-Bewertungen für Team "
|
||||
(team.name)
|
||||
" eingeben"
|
||||
"Bewertungen"
|
||||
}
|
||||
}
|
||||
hr;
|
||||
a href=(format!("/admin/team/{}/quick/crewless", team.id)){
|
||||
button {
|
||||
"Unbemannte Bewertungen"
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -743,7 +773,8 @@ pub(super) fn routes() -> Router<AppState> {
|
||||
.route("/lost", get(lost))
|
||||
.route("/{id}", get(view))
|
||||
.route("/{id}/delete", get(delete))
|
||||
.route("/{id}/quick", get(quick))
|
||||
.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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user