Compare commits
5 Commits
059976cb98
...
97dbd4fcae
Author | SHA1 | Date | |
---|---|---|---|
97dbd4fcae | |||
a46cf6ed97 | |||
2a0098b0cb | |||
69aed3be27 | |||
79d22a0ad1 |
@@ -16,7 +16,7 @@ use rand::{
|
||||
rng,
|
||||
};
|
||||
use route::Route;
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::{SqliteConnection, SqlitePool};
|
||||
use std::sync::Arc;
|
||||
use team::Team;
|
||||
use tower_sessions::Session;
|
||||
@@ -35,7 +35,9 @@ fn generate_random_alphanumeric(length: usize) -> String {
|
||||
}
|
||||
|
||||
async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
let routes = Route::all(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let routes = Route::all(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -51,7 +53,7 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
|
||||
thead {
|
||||
tr {
|
||||
td { (t!("team")) }
|
||||
@for station in route.stations(&db).await {
|
||||
@for station in route.stations(db).await {
|
||||
td {
|
||||
(station)
|
||||
}
|
||||
@@ -65,7 +67,7 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
|
||||
@let mut rank = 0;
|
||||
@let mut amount_teams_iterated = 0;
|
||||
@let mut prev_points = i64::MAX;
|
||||
@for team in route.teams_ordered_by_points(&db).await {
|
||||
@for team in route.teams_ordered_by_points(db).await {
|
||||
@let mut total_points = 0;
|
||||
({ amount_teams_iterated += 1;"" })
|
||||
tr {
|
||||
@@ -74,9 +76,9 @@ async fn highscore(State(db): State<Arc<SqlitePool>>, session: Session) -> Marku
|
||||
(team.name)
|
||||
}
|
||||
}
|
||||
@for station in route.stations(&db).await {
|
||||
@for station in route.stations(db).await {
|
||||
td {
|
||||
@if let Some(rating) = Rating::find_by_team_and_station(&db, &team, &station).await {
|
||||
@if let Some(rating) = Rating::find_by_team_and_station(db, &team, &station).await {
|
||||
@if let (Some(notes), Some(points)) = (rating.notes, rating.points) {
|
||||
({total_points += points;""})
|
||||
em data-placement="bottom" data-tooltip=(notes) { (points) }
|
||||
@@ -125,7 +127,7 @@ pub enum RunStatus {
|
||||
}
|
||||
|
||||
impl RunStatus {
|
||||
pub async fn curr(db: &SqlitePool) -> Self {
|
||||
pub async fn curr(db: &mut SqliteConnection) -> Self {
|
||||
let stations = Station::all(db).await;
|
||||
if stations.is_empty() {
|
||||
return RunStatus::NoStationsYet;
|
||||
@@ -143,10 +145,12 @@ async fn index(
|
||||
session: Session,
|
||||
auth_session: AuthSession,
|
||||
) -> Markup {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let user = auth_session
|
||||
.user
|
||||
.expect("Can only be called by loggedin people");
|
||||
let status = RunStatus::curr(&db).await;
|
||||
let status = RunStatus::curr(db).await;
|
||||
let content = html! {
|
||||
nav {
|
||||
ul {
|
||||
@@ -201,7 +205,7 @@ async fn index(
|
||||
}
|
||||
},
|
||||
RunStatus::Active => {
|
||||
@let stations = Station::all(&db).await;
|
||||
@let stations = Station::all(db).await;
|
||||
a href="/admin/end-run" onclick=(format!("return confirm('{}');", t!("confirm_end_run"))) {
|
||||
button style="background-color: red;" {
|
||||
(t!("end_run"))
|
||||
@@ -230,7 +234,7 @@ async fn index(
|
||||
}
|
||||
td {
|
||||
ol {
|
||||
@for team in Team::all_with_first_station(&db, &station).await {
|
||||
@for team in Team::all_with_first_station(db, &station).await {
|
||||
li { (team) }
|
||||
}
|
||||
}
|
||||
@@ -241,7 +245,7 @@ async fn index(
|
||||
}
|
||||
},
|
||||
RunStatus::HasEnded => {
|
||||
@let stations = Station::all(&db).await;
|
||||
@let stations = Station::all(db).await;
|
||||
a href="/admin/restart-run" onclick=(format!("return confirm('{}');", t!("confirm_restart_run"))) {
|
||||
button style="background-color: red;" {
|
||||
(t!("restart_run"))
|
||||
@@ -263,7 +267,7 @@ async fn index(
|
||||
td { (station) }
|
||||
td {
|
||||
ol {
|
||||
@for team in Team::all_with_last_station(&db, &station).await {
|
||||
@for team in Team::all_with_last_station(db, &station).await {
|
||||
li { (team) }
|
||||
}
|
||||
}
|
||||
@@ -279,12 +283,16 @@ async fn index(
|
||||
}
|
||||
|
||||
async fn end_run(State(db): State<Arc<SqlitePool>>, session: Session) -> impl IntoResponse {
|
||||
Team::end_run(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
Team::end_run(db).await;
|
||||
suc!(session, t!("run_ended"));
|
||||
Redirect::to("/admin")
|
||||
}
|
||||
async fn restart_run(State(db): State<Arc<SqlitePool>>, session: Session) -> impl IntoResponse {
|
||||
Team::restart_run(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
Team::restart_run(db).await;
|
||||
suc!(session, t!("run_restarted"));
|
||||
Redirect::to("/admin")
|
||||
}
|
||||
|
@@ -3,10 +3,8 @@ use crate::{
|
||||
AppState,
|
||||
};
|
||||
use axum::Router;
|
||||
use futures::future::join_all;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, Row, Sqlite, SqlitePool, Transaction};
|
||||
use std::ops::DerefMut;
|
||||
use sqlx::{FromRow, Row, SqliteConnection};
|
||||
|
||||
mod web;
|
||||
|
||||
@@ -17,29 +15,29 @@ pub(crate) struct Route {
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub(crate) async fn all(db: &SqlitePool) -> Vec<Self> {
|
||||
pub(crate) async fn all(db: &mut SqliteConnection) -> Vec<Self> {
|
||||
sqlx::query_as::<_, Self>("SELECT id, name FROM route;")
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
||||
pub async fn find_by_id(db: &mut SqliteConnection, id: i64) -> Option<Self> {
|
||||
sqlx::query_as!(Self, "SELECT id, name FROM route WHERE id = ?", id)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub(crate) async fn create(db: &SqlitePool, name: &str) -> Result<Self, String> {
|
||||
pub(crate) async fn create(db: &mut SqliteConnection, name: &str) -> Result<Self, String> {
|
||||
let route = sqlx::query!("INSERT INTO route(name) VALUES (?) RETURNING id", name)
|
||||
.fetch_one(db)
|
||||
.fetch_one(&mut *db)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(Self::find_by_id(db, route.id).await.expect("just created"))
|
||||
}
|
||||
|
||||
async fn update_name(&self, db: &SqlitePool, name: &str) {
|
||||
async fn update_name(&self, db: &mut SqliteConnection, name: &str) {
|
||||
sqlx::query!("UPDATE route SET name = ? WHERE id = ?", name, self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
@@ -48,7 +46,7 @@ impl Route {
|
||||
|
||||
pub(crate) async fn add_station(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
) -> Result<(), String> {
|
||||
sqlx::query!(
|
||||
@@ -71,7 +69,7 @@ impl Route {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_station(&self, db: &SqlitePool, station: &Station) -> bool {
|
||||
async fn delete_station(&self, db: &mut SqliteConnection, station: &Station) -> bool {
|
||||
let result = sqlx::query!(
|
||||
"DELETE FROM route_station WHERE route_id = ? AND station_id = ?",
|
||||
self.id,
|
||||
@@ -84,13 +82,13 @@ impl Route {
|
||||
result.rows_affected() > 0
|
||||
}
|
||||
|
||||
async fn move_station_higher(&self, db: &SqlitePool, station: &Station) -> bool {
|
||||
async fn move_station_higher(&self, db: &mut SqliteConnection, station: &Station) -> bool {
|
||||
let result = sqlx::query!(
|
||||
"UPDATE route_station SET pos = pos-3 WHERE route_id = ? AND station_id = ?",
|
||||
self.id,
|
||||
station.id
|
||||
)
|
||||
.execute(db)
|
||||
.execute(&mut *db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -126,7 +124,7 @@ DROP TABLE temp_pos;",
|
||||
true
|
||||
}
|
||||
|
||||
async fn delete(&self, db: &SqlitePool) -> Result<(), String> {
|
||||
async fn delete(&self, db: &mut SqliteConnection) -> Result<(), String> {
|
||||
sqlx::query!("DELETE FROM route WHERE id = ?", self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
@@ -134,7 +132,7 @@ DROP TABLE temp_pos;",
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn stations(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
pub(crate) async fn stations(&self, db: &mut SqliteConnection) -> Vec<Station> {
|
||||
// TODO: switch to macro
|
||||
sqlx::query_as::<_, Station>(
|
||||
"
|
||||
@@ -151,7 +149,7 @@ DROP TABLE temp_pos;",
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn crewless_stations(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
pub(crate) async fn crewless_stations(&self, db: &mut SqliteConnection) -> Vec<Station> {
|
||||
self.stations(db)
|
||||
.await
|
||||
.into_iter()
|
||||
@@ -159,7 +157,7 @@ DROP TABLE temp_pos;",
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) async fn crewful_stations(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
pub(crate) async fn crewful_stations(&self, db: &mut SqliteConnection) -> Vec<Station> {
|
||||
self.stations(db)
|
||||
.await
|
||||
.into_iter()
|
||||
@@ -167,7 +165,7 @@ DROP TABLE temp_pos;",
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn stations_not_in_route(&self, db: &SqlitePool) -> Vec<Station> {
|
||||
async fn stations_not_in_route(&self, db: &mut SqliteConnection) -> Vec<Station> {
|
||||
// TODO: switch to macro
|
||||
sqlx::query_as::<_, Station>(
|
||||
"
|
||||
@@ -187,15 +185,18 @@ DROP TABLE temp_pos;",
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn teams(&self, db: &SqlitePool) -> Vec<Team> {
|
||||
pub(crate) async fn teams(&self, db: &mut SqliteConnection) -> Vec<Team> {
|
||||
Team::all_with_route(db, self).await
|
||||
}
|
||||
|
||||
pub(crate) async fn teams_ordered_by_points(&self, db: &SqlitePool) -> Vec<Team> {
|
||||
pub(crate) async fn teams_ordered_by_points(&self, db: &mut SqliteConnection) -> Vec<Team> {
|
||||
let teams = Team::all_with_route(db, self).await;
|
||||
|
||||
// First, collect all the points
|
||||
let points_futures: Vec<_> = teams.iter().map(|team| team.get_curr_points(db)).collect();
|
||||
let points = join_all(points_futures).await;
|
||||
let mut points = Vec::new();
|
||||
for team in &teams {
|
||||
points.push(team.get_curr_points(&mut *db).await);
|
||||
}
|
||||
|
||||
// Create pairs of (team, points)
|
||||
let mut team_with_points: Vec<_> = teams.into_iter().zip(points).collect();
|
||||
@@ -207,9 +208,9 @@ DROP TABLE temp_pos;",
|
||||
team_with_points.into_iter().map(|(team, _)| team).collect()
|
||||
}
|
||||
|
||||
pub(crate) async fn get_next_first_station_tx(
|
||||
pub(crate) async fn get_next_first_station(
|
||||
&self,
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Option<Station> {
|
||||
let Ok(row) = sqlx::query(&format!(
|
||||
"
|
||||
@@ -226,7 +227,7 @@ DROP TABLE temp_pos;",
|
||||
LIMIT 1",
|
||||
self.id
|
||||
))
|
||||
.fetch_one(db.deref_mut())
|
||||
.fetch_one(&mut *db)
|
||||
.await
|
||||
else {
|
||||
return None; // No station for route exists
|
||||
@@ -234,22 +235,17 @@ DROP TABLE temp_pos;",
|
||||
let next_first_station_id = row.get::<i64, _>("next_first_station_id");
|
||||
|
||||
Some(
|
||||
Station::find_by_id_tx(db, next_first_station_id)
|
||||
Station::find_by_id(db, next_first_station_id)
|
||||
.await
|
||||
.expect("db constraints"),
|
||||
)
|
||||
}
|
||||
pub(crate) async fn get_next_first_station(&self, db: &SqlitePool) -> Option<Station> {
|
||||
let mut transaction = db.begin().await.unwrap();
|
||||
|
||||
let res = self.get_next_first_station_tx(&mut transaction).await;
|
||||
|
||||
transaction.commit().await.unwrap();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub async fn next_station(&self, db: &SqlitePool, target_station: &Station) -> Option<Station> {
|
||||
pub async fn next_station(
|
||||
&self,
|
||||
db: &mut SqliteConnection,
|
||||
target_station: &Station,
|
||||
) -> Option<Station> {
|
||||
let stations = Station::all(db).await;
|
||||
for station in stations {
|
||||
if let Some(prev_station) = self.prev_station(db, &station).await {
|
||||
@@ -261,7 +257,11 @@ DROP TABLE temp_pos;",
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn prev_station(&self, db: &SqlitePool, station: &Station) -> Option<Station> {
|
||||
pub async fn prev_station(
|
||||
&self,
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
) -> Option<Station> {
|
||||
if station.crewless() {
|
||||
return None;
|
||||
}
|
||||
|
@@ -13,7 +13,9 @@ use std::sync::Arc;
|
||||
use tower_sessions::Session;
|
||||
|
||||
async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
let routes = Route::all(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let routes = Route::all(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -28,7 +30,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
ol {
|
||||
@for route in &routes{
|
||||
li {
|
||||
@if route.stations(&db).await.is_empty() {
|
||||
@if route.stations(db).await.is_empty() {
|
||||
em data-tooltip=(t!("route_has_no_station_assigned")) {
|
||||
"⚠️"
|
||||
}
|
||||
@@ -71,7 +73,9 @@ async fn create(
|
||||
session: Session,
|
||||
Form(form): Form<CreateForm>,
|
||||
) -> impl IntoResponse {
|
||||
match Route::create(&db, &form.name).await {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
match Route::create(db, &form.name).await {
|
||||
Ok(_) => suc!(session, t!("route_create_succ", name = form.name)),
|
||||
Err(e) => er!(
|
||||
session,
|
||||
@@ -87,12 +91,14 @@ async fn delete(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(route) = Route::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(route) = Route::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_route", id = id));
|
||||
return Redirect::to("/admin/route");
|
||||
};
|
||||
|
||||
match route.delete(&db).await {
|
||||
match route.delete(db).await {
|
||||
Ok(()) => suc!(session, t!("route_delete_succ", name = route.name)),
|
||||
Err(e) => er!(
|
||||
session,
|
||||
@@ -108,15 +114,17 @@ async fn view(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> Result<Markup, impl IntoResponse> {
|
||||
let Some(route) = Route::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(route) = Route::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_route", id = id));
|
||||
return Err(Redirect::to("/admin/route"));
|
||||
};
|
||||
|
||||
let cur_stations = route.stations(&db).await;
|
||||
let stations_not_in_route = route.stations_not_in_route(&db).await;
|
||||
let cur_stations = route.stations(db).await;
|
||||
let stations_not_in_route = route.stations_not_in_route(db).await;
|
||||
|
||||
let teams = route.teams(&db).await;
|
||||
let teams = route.teams(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -220,12 +228,14 @@ async fn update_name(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<UpdateNameForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(route) = Route::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(route) = Route::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_route", id = id));
|
||||
return Redirect::to("/admin/route");
|
||||
};
|
||||
|
||||
route.update_name(&db, &form.name).await;
|
||||
route.update_name(db, &form.name).await;
|
||||
|
||||
suc!(
|
||||
session,
|
||||
@@ -245,16 +255,18 @@ async fn add_station(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<AddStationForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(route) = Route::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(route) = Route::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_route", id = id));
|
||||
return Redirect::to("/admin/route");
|
||||
};
|
||||
let Some(station) = Station::find_by_id(&db, form.station).await else {
|
||||
let Some(station) = Station::find_by_id(&mut *db, form.station).await else {
|
||||
er!(session, t!("nonexisting_station", id = form.station));
|
||||
return Redirect::to(&format!("/admin/route/{id}"));
|
||||
};
|
||||
|
||||
match route.add_station(&db, &station).await {
|
||||
match route.add_station(db, &station).await {
|
||||
Ok(()) => suc!(
|
||||
session,
|
||||
t!(
|
||||
@@ -282,16 +294,18 @@ async fn delete_station(
|
||||
session: Session,
|
||||
axum::extract::Path((route_id, station_id)): axum::extract::Path<(i64, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(route) = Route::find_by_id(&db, route_id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(route) = Route::find_by_id(db, route_id).await else {
|
||||
er!(session, t!("nonexisting_route", id = route_id));
|
||||
return Redirect::to("/admin/route");
|
||||
};
|
||||
let Some(station) = Station::find_by_id(&db, station_id).await else {
|
||||
let Some(station) = Station::find_by_id(&mut *db, station_id).await else {
|
||||
er!(session, t!("nonexisting_station", id = station_id));
|
||||
return Redirect::to(&format!("/admin/route/{route_id}"));
|
||||
};
|
||||
|
||||
if route.delete_station(&db, &station).await {
|
||||
if route.delete_station(db, &station).await {
|
||||
suc!(
|
||||
session,
|
||||
t!(
|
||||
@@ -319,16 +333,18 @@ async fn move_station_higher(
|
||||
session: Session,
|
||||
axum::extract::Path((route_id, station_id)): axum::extract::Path<(i64, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(route) = Route::find_by_id(&db, route_id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(route) = Route::find_by_id(db, route_id).await else {
|
||||
er!(session, t!("nonexisting_route", id = route_id));
|
||||
return Redirect::to("/admin/route");
|
||||
};
|
||||
let Some(station) = Station::find_by_id(&db, station_id).await else {
|
||||
let Some(station) = Station::find_by_id(&mut *db, station_id).await else {
|
||||
er!(session, t!("nonexisting_station", id = station_id));
|
||||
return Redirect::to(&format!("/admin/route/{route_id}"));
|
||||
};
|
||||
|
||||
if route.move_station_higher(&db, &station).await {
|
||||
if route.move_station_higher(db, &station).await {
|
||||
suc!(
|
||||
session,
|
||||
t!(
|
||||
|
@@ -6,11 +6,9 @@ use crate::{
|
||||
};
|
||||
use axum::Router;
|
||||
use chrono::{DateTime, Local, NaiveDateTime, Utc};
|
||||
use futures::{stream, StreamExt};
|
||||
use maud::{html, Markup, Render};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||
use std::ops::DerefMut;
|
||||
use sqlx::{FromRow, SqliteConnection};
|
||||
|
||||
pub(crate) mod model;
|
||||
pub(crate) mod print;
|
||||
@@ -52,7 +50,7 @@ impl Render for Station {
|
||||
}
|
||||
|
||||
impl Station {
|
||||
pub(crate) async fn all(db: &SqlitePool) -> Vec<Self> {
|
||||
pub(crate) async fn all(db: &mut SqliteConnection) -> Vec<Self> {
|
||||
sqlx::query_as::<_, Self>(
|
||||
"SELECT id, name, notes, amount_people, last_login, ready, pw, lat, lng FROM station;",
|
||||
)
|
||||
@@ -61,18 +59,7 @@ impl Station {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn find_by_id_tx(db: &mut Transaction<'_, Sqlite>, id: i64) -> Option<Self> {
|
||||
sqlx::query_as!(
|
||||
Self,
|
||||
"SELECT id, name, notes, amount_people, last_login, ready, pw, lat, lng FROM station WHERE id = ?",
|
||||
id
|
||||
)
|
||||
.fetch_one(db.deref_mut())
|
||||
.await
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
||||
pub async fn find_by_id(db: &mut SqliteConnection, id: i64) -> Option<Self> {
|
||||
sqlx::query_as!(
|
||||
Self,
|
||||
"SELECT id, name, notes, amount_people, last_login, ready, pw, lat, lng FROM station WHERE id = ?",
|
||||
@@ -90,13 +77,13 @@ impl Station {
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn login(db: &SqlitePool, id: i64, code: &str) -> Option<Self> {
|
||||
pub async fn login(db: &mut SqliteConnection, id: i64, code: &str) -> Option<Self> {
|
||||
let station = sqlx::query_as!(
|
||||
Self,
|
||||
"SELECT id, name, notes, amount_people, last_login, ready, pw, lat, lng FROM station WHERE id = ? AND pw = ?",
|
||||
id, code
|
||||
)
|
||||
.fetch_one(db)
|
||||
.fetch_one(&mut *db)
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
@@ -111,7 +98,7 @@ impl Station {
|
||||
Some(station)
|
||||
}
|
||||
|
||||
pub async fn switch_ready(&self, db: &SqlitePool) {
|
||||
pub async fn switch_ready(&self, db: &mut SqliteConnection) {
|
||||
let new_ready_status = !self.ready;
|
||||
sqlx::query!(
|
||||
"UPDATE station SET ready = ? WHERE id = ?",
|
||||
@@ -123,18 +110,18 @@ impl Station {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) async fn create(db: &SqlitePool, name: &str) -> Result<Self, String> {
|
||||
pub(crate) async fn create(db: &mut SqliteConnection, name: &str) -> Result<Self, String> {
|
||||
let code = generate_random_alphanumeric(8);
|
||||
let station_id = sqlx::query!(
|
||||
"INSERT INTO station(name, pw) VALUES (?, ?) RETURNING id",
|
||||
name,
|
||||
code
|
||||
)
|
||||
.fetch_one(db)
|
||||
.fetch_one(&mut *db)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let station = Station::find_by_id(db, station_id.id)
|
||||
let station = Station::find_by_id(&mut *db, station_id.id)
|
||||
.await
|
||||
.expect("just created");
|
||||
|
||||
@@ -150,7 +137,7 @@ impl Station {
|
||||
|
||||
pub(crate) async fn new_team_waiting(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
@@ -170,7 +157,7 @@ impl Station {
|
||||
|
||||
pub(crate) async fn team_update(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
points: Option<i64>,
|
||||
notes: Option<String>,
|
||||
@@ -180,7 +167,7 @@ impl Station {
|
||||
Some(n) => Some(n),
|
||||
None => None,
|
||||
};
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
let teams = TeamsAtStationLocation::for_station(&mut *db, self).await;
|
||||
|
||||
let waiting_teams: Vec<&Team> = teams.waiting.iter().map(|(team, _)| team).collect();
|
||||
let doing_teams: Vec<&Team> = teams.doing.iter().map(|(team, _)| team).collect();
|
||||
@@ -207,7 +194,7 @@ impl Station {
|
||||
|
||||
pub(crate) async fn remove_team_waiting(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
@@ -223,7 +210,11 @@ impl Station {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn team_starting(&self, db: &SqlitePool, team: &Team) -> Result<(), String> {
|
||||
pub(crate) async fn team_starting(
|
||||
&self,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
|
||||
let waiting_teams: Vec<&Team> = teams.waiting.iter().map(|(team, _)| team).collect();
|
||||
@@ -246,7 +237,7 @@ impl Station {
|
||||
|
||||
pub(crate) async fn remove_team_doing(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
@@ -273,7 +264,11 @@ impl Station {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn team_finished(&self, db: &SqlitePool, team: &Team) -> Result<(), String> {
|
||||
pub(crate) async fn team_finished(
|
||||
&self,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
|
||||
let doing_teams: Vec<&Team> = teams.doing.iter().map(|(team, _)| team).collect();
|
||||
@@ -296,7 +291,7 @@ impl Station {
|
||||
|
||||
pub(crate) async fn remove_team_left(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
let teams = TeamsAtStationLocation::for_station(db, self).await;
|
||||
@@ -325,7 +320,7 @@ impl Station {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete(&self, db: &SqlitePool) -> Result<(), String> {
|
||||
async fn delete(&self, db: &mut SqliteConnection) -> Result<(), String> {
|
||||
sqlx::query!("DELETE FROM station WHERE id = ?", self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
@@ -333,7 +328,7 @@ impl Station {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn routes(&self, db: &SqlitePool) -> Vec<Route> {
|
||||
async fn routes(&self, db: &mut SqliteConnection) -> Vec<Route> {
|
||||
sqlx::query_as::<_, Route>(
|
||||
"
|
||||
SELECT r.id, r.name
|
||||
@@ -349,7 +344,7 @@ impl Station {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn is_in_route(&self, db: &SqlitePool, route: &Route) -> bool {
|
||||
pub async fn is_in_route(&self, db: &mut SqliteConnection, route: &Route) -> bool {
|
||||
for r in self.routes(db).await {
|
||||
if r.id == route.id {
|
||||
return true;
|
||||
@@ -367,7 +362,7 @@ impl Station {
|
||||
Some(datetime_utc.with_timezone(&Local))
|
||||
}
|
||||
|
||||
pub(crate) async fn teams(&self, db: &SqlitePool) -> Vec<Team> {
|
||||
pub(crate) async fn teams(&self, db: &mut SqliteConnection) -> Vec<Team> {
|
||||
sqlx::query_as::<_, Team>(
|
||||
"SELECT DISTINCT t.id, t.name, t.notes, t.amount_people, t.first_station_id, t.last_station_id, t.route_id
|
||||
FROM team t
|
||||
@@ -381,7 +376,7 @@ ORDER BY LOWER(t.name);",
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn left_teams(&self, db: &SqlitePool) -> Vec<Team> {
|
||||
pub(crate) async fn left_teams(&self, db: &mut SqliteConnection) -> Vec<Team> {
|
||||
sqlx::query_as::<_, Team>(
|
||||
"SELECT t.id, t.name, t.notes, t.amount_people, t.first_station_id, t.last_station_id, t.route_id
|
||||
FROM team t
|
||||
@@ -395,24 +390,20 @@ AND r.left_at IS NOT NULL;",
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn teams_on_the_way(&self, db: &SqlitePool) -> Vec<TeamOnTheWay> {
|
||||
pub async fn teams_on_the_way(&self, db: &mut SqliteConnection) -> Vec<TeamOnTheWay> {
|
||||
let mut ret = Vec::new();
|
||||
|
||||
let teams = self.teams(db).await;
|
||||
let teams = self.teams(&mut *db).await;
|
||||
|
||||
let missing_teams: Vec<Team> = stream::iter(teams)
|
||||
.filter_map(|entry| async move {
|
||||
if entry.been_at_station(db, self).await {
|
||||
None
|
||||
} else {
|
||||
Some(entry)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await;
|
||||
let mut missing_teams = Vec::new();
|
||||
for team in teams {
|
||||
if !team.been_at_station(&mut *db, self).await {
|
||||
missing_teams.push(team);
|
||||
}
|
||||
}
|
||||
|
||||
for team in missing_teams {
|
||||
let route = team.route(db).await;
|
||||
let route = team.route(&mut *db).await;
|
||||
let Some(prev_station) = route.prev_station(db, self).await else {
|
||||
continue;
|
||||
};
|
||||
@@ -433,7 +424,7 @@ AND r.left_at IS NOT NULL;",
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn some_team_has_last_station_id(db: &SqlitePool) -> bool {
|
||||
pub async fn some_team_has_last_station_id(db: &mut SqliteConnection) -> bool {
|
||||
sqlx::query_scalar!("SELECT 1 FROM team WHERE last_station_id IS NOT NULL")
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::Station;
|
||||
use serde::Serialize;
|
||||
use sqlx::SqlitePool;
|
||||
use std::ops::DerefMut;
|
||||
use sqlx::Acquire;
|
||||
use sqlx::SqliteConnection;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, PartialEq, Serialize)]
|
||||
@@ -11,14 +11,14 @@ pub(crate) enum UpdateAmountPeopleError {
|
||||
}
|
||||
|
||||
impl Station {
|
||||
pub(crate) async fn update_name(&self, db: &SqlitePool, name: &str) {
|
||||
pub(crate) async fn update_name(&self, db: &mut SqliteConnection, name: &str) {
|
||||
sqlx::query!("UPDATE station SET name = ? WHERE id = ?", name, self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) async fn update_notes(&self, db: &SqlitePool, notes: &str) {
|
||||
pub(crate) async fn update_notes(&self, db: &mut SqliteConnection, notes: &str) {
|
||||
sqlx::query!("UPDATE station SET notes = ? WHERE id = ?", notes, self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
@@ -27,7 +27,7 @@ impl Station {
|
||||
|
||||
pub(crate) async fn update_amount_people(
|
||||
&self,
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
amount_people: i64,
|
||||
) -> Result<(), UpdateAmountPeopleError> {
|
||||
let mut transaction = db.begin().await.unwrap();
|
||||
@@ -37,18 +37,18 @@ impl Station {
|
||||
amount_people,
|
||||
self.id
|
||||
)
|
||||
.execute(transaction.deref_mut())
|
||||
.execute(&mut *transaction)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
if amount_people == 0 {
|
||||
let teams = self.teams(db).await;
|
||||
let teams = self.teams(&mut transaction).await;
|
||||
for team in teams {
|
||||
let route = team.route(db).await;
|
||||
let Some(station) = route.get_next_first_station_tx(&mut transaction).await else {
|
||||
let route = team.route(&mut transaction).await;
|
||||
let Some(station) = route.get_next_first_station(&mut transaction).await else {
|
||||
return Err(UpdateAmountPeopleError::LastStationCantBeCrewlessIfTeamExists);
|
||||
};
|
||||
team.update_first_station_tx(&mut transaction, &station)
|
||||
team.update_first_station(transaction.as_mut(), &station)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ impl Station {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn update_amount_people_reset(&self, db: &SqlitePool) {
|
||||
pub(crate) async fn update_amount_people_reset(&self, db: &mut SqliteConnection) {
|
||||
sqlx::query!(
|
||||
"UPDATE station SET amount_people = NULL WHERE id = ?",
|
||||
self.id
|
||||
@@ -68,7 +68,7 @@ impl Station {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) async fn update_location(&self, db: &SqlitePool, lat: f64, lng: f64) {
|
||||
pub(crate) async fn update_location(&self, db: &mut SqliteConnection, lat: f64, lng: f64) {
|
||||
sqlx::query!(
|
||||
"UPDATE station SET lat = ?, lng = ? WHERE id = ?",
|
||||
lat,
|
||||
@@ -80,7 +80,7 @@ impl Station {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) async fn update_location_clear(&self, db: &SqlitePool) {
|
||||
pub(crate) async fn update_location_clear(&self, db: &mut SqliteConnection) {
|
||||
sqlx::query!(
|
||||
"UPDATE station SET lat = NULL, lng=NULL WHERE id = ?",
|
||||
self.id
|
||||
@@ -103,30 +103,30 @@ mod test {
|
||||
#[sqlx::test]
|
||||
async fn succ_update_not_last_crewful_station() {
|
||||
let pool = testdb!();
|
||||
let db = &mut *pool.acquire().await.unwrap();
|
||||
|
||||
let station = Station::create(&pool, "Teststation").await.unwrap();
|
||||
let crew_station = Station::create(&pool, "Bemannte Teststation")
|
||||
.await
|
||||
.unwrap();
|
||||
let route = Route::create(&pool, "Testroute").await.unwrap();
|
||||
route.add_station(&pool, &station).await.unwrap();
|
||||
route.add_station(&pool, &crew_station).await.unwrap();
|
||||
let _ = Team::create(&pool, "Testteam", &route).await.unwrap();
|
||||
let station = Station::create(db, "Teststation").await.unwrap();
|
||||
let crew_station = Station::create(db, "Bemannte Teststation").await.unwrap();
|
||||
let route = Route::create(db, "Testroute").await.unwrap();
|
||||
route.add_station(db, &station).await.unwrap();
|
||||
route.add_station(db, &crew_station).await.unwrap();
|
||||
let _ = Team::create(db, "Testteam", &route).await.unwrap();
|
||||
|
||||
assert_eq!(station.update_amount_people(&pool, 0).await, Ok(()));
|
||||
assert_eq!(station.update_amount_people(db, 0).await, Ok(()));
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn fail_update_last_crewful_station() {
|
||||
let pool = testdb!();
|
||||
let db = &mut *pool.acquire().await.unwrap();
|
||||
|
||||
let station = Station::create(&pool, "Teststation").await.unwrap();
|
||||
let route = Route::create(&pool, "Testroute").await.unwrap();
|
||||
route.add_station(&pool, &station).await.unwrap();
|
||||
let _ = Team::create(&pool, "Testteam", &route).await.unwrap();
|
||||
let station = Station::create(db, "Teststation").await.unwrap();
|
||||
let route = Route::create(db, "Testroute").await.unwrap();
|
||||
route.add_station(db, &station).await.unwrap();
|
||||
let _ = Team::create(db, "Testteam", &route).await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
station.update_amount_people(&pool, 0).await,
|
||||
station.update_amount_people(db, 0).await,
|
||||
Err(UpdateAmountPeopleError::LastStationCantBeCrewlessIfTeamExists)
|
||||
);
|
||||
}
|
||||
|
@@ -73,9 +73,9 @@ pub(crate) async fn station_pdf(stations: Vec<Station>) -> Vec<u8> {
|
||||
|
||||
write!(
|
||||
content,
|
||||
r#")
|
||||
r")
|
||||
|
||||
#create_card_grid(cards)"#
|
||||
#create_card_grid(cards)"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -92,7 +92,9 @@ pub(crate) async fn station_pdf(stations: Vec<Station>) -> Vec<u8> {
|
||||
}
|
||||
|
||||
async fn index(State(db): State<Arc<SqlitePool>>) -> impl IntoResponse {
|
||||
let stations = Station::all(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let stations = Station::all(db).await;
|
||||
let pdf = station_pdf(stations).await;
|
||||
|
||||
(
|
||||
|
@@ -54,15 +54,14 @@ impl TypstWrapperWorld {
|
||||
source: Source::detached(source),
|
||||
time: time::OffsetDateTime::now_utc(),
|
||||
cache_directory: std::env::var_os("CACHE_DIRECTORY")
|
||||
.map(|os_path| os_path.into())
|
||||
.unwrap_or(std::env::temp_dir()),
|
||||
.map_or(std::env::temp_dir(), std::convert::Into::into),
|
||||
http: ureq::Agent::new_with_defaults(),
|
||||
files: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A File that will be stored in the HashMap.
|
||||
/// A File that will be stored in the `HashMap`.
|
||||
#[derive(Clone, Debug)]
|
||||
struct FileEntry {
|
||||
bytes: Bytes,
|
||||
|
@@ -15,6 +15,7 @@ use axum::{
|
||||
use maud::{html, Markup};
|
||||
use serde::Deserialize;
|
||||
use sqlx::SqlitePool;
|
||||
use std::fmt::Write;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tower_sessions::Session;
|
||||
|
||||
@@ -28,7 +29,9 @@ async fn create(
|
||||
session: Session,
|
||||
Form(form): Form<CreateForm>,
|
||||
) -> impl IntoResponse {
|
||||
match Station::create(&db, &form.name).await {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
match Station::create(db, &form.name).await {
|
||||
Ok(_) => suc!(session, t!("station_create_succ", name = form.name)),
|
||||
Err(e) => er!(
|
||||
session,
|
||||
@@ -48,12 +51,14 @@ async fn delete(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
match station.delete(&db).await {
|
||||
match station.delete(db).await {
|
||||
Ok(()) => suc!(session, t!("station_delete_succ", name = station.name)),
|
||||
Err(e) => er!(
|
||||
session,
|
||||
@@ -73,12 +78,14 @@ async fn view(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> Result<Markup, impl IntoResponse> {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Err(Redirect::to("/admin/station"));
|
||||
};
|
||||
|
||||
let ratings = Rating::for_station(&db, &station).await;
|
||||
let ratings = Rating::for_station(db, &station).await;
|
||||
|
||||
// maybe switch to maud-display impl of station
|
||||
let content = html! {
|
||||
@@ -226,7 +233,7 @@ async fn view(
|
||||
tr {
|
||||
td {
|
||||
a href=(format!("/admin/team/{}", rating.team_id)) {
|
||||
(rating.team(&db).await.name)
|
||||
(rating.team(db).await.name)
|
||||
}
|
||||
}
|
||||
td {
|
||||
@@ -348,12 +355,14 @@ async fn update_name(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<UpdateNameForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
station.update_name(&db, &form.name).await;
|
||||
station.update_name(db, &form.name).await;
|
||||
|
||||
suc!(
|
||||
session,
|
||||
@@ -373,12 +382,14 @@ async fn update_notes(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<UpdateNotesForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
station.update_notes(&db, &form.notes).await;
|
||||
station.update_notes(db, &form.notes).await;
|
||||
|
||||
suc!(session, t!("station_new_notes", station = station.name));
|
||||
|
||||
@@ -395,18 +406,20 @@ async fn update_amount_people(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<UpdateAmountPeopleForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
match station.update_amount_people(&db, form.amount_people).await {
|
||||
match station.update_amount_people(db, form.amount_people).await {
|
||||
Ok(()) => suc!(
|
||||
session,
|
||||
t!("station_new_crew_amount", station = station.name)
|
||||
),
|
||||
Err(UpdateAmountPeopleError::LastStationCantBeCrewlessIfTeamExists) => {
|
||||
er!(session, t!("last_station_has_to_be_crewful"))
|
||||
er!(session, t!("last_station_has_to_be_crewful"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,12 +431,14 @@ async fn update_amount_people_reset(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(&mut *db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
station.update_amount_people_reset(&db).await;
|
||||
station.update_amount_people_reset(db).await;
|
||||
|
||||
suc!(
|
||||
session,
|
||||
@@ -438,12 +453,14 @@ async fn quick(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> Result<Markup, impl IntoResponse> {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Err(Redirect::to("/admin/station"));
|
||||
};
|
||||
|
||||
let teams = station.teams(&db).await;
|
||||
let teams = station.teams(db).await;
|
||||
|
||||
// maybe switch to maud-display impl of team
|
||||
let content = html! {
|
||||
@@ -470,7 +487,7 @@ async fn quick(
|
||||
}
|
||||
}
|
||||
td {
|
||||
@if let Some(rating) = Rating::find_by_team_and_station(&db, team, &station).await {
|
||||
@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")) {
|
||||
@@ -506,7 +523,9 @@ async fn quick_post(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<QuickUpdate>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
@@ -516,25 +535,27 @@ async fn quick_post(
|
||||
|
||||
for (team_id, points) in &form.fields {
|
||||
let Ok(team_id) = team_id.parse::<i64>() else {
|
||||
ret.push_str(&format!(
|
||||
let _ = write!(
|
||||
ret,
|
||||
"Skipped team_id={team_id} because this id can't be parsed as i64"
|
||||
));
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Ok(points) = points.parse::<i64>() else {
|
||||
ret.push_str(&format!(
|
||||
"Skipped team_id={team_id} because points {} can't be parsed as i64",
|
||||
points
|
||||
));
|
||||
let _ = write!(
|
||||
ret,
|
||||
"Skipped team_id={team_id} because {points} points can't be parsed as i64",
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
ret.push_str(&format!(
|
||||
let Some(team) = Team::find_by_id(db, team_id).await else {
|
||||
let _ = write!(
|
||||
ret,
|
||||
"Skipped team_id={team_id} because this team does not exist"
|
||||
));
|
||||
);
|
||||
continue;
|
||||
};
|
||||
if Rating::find_by_team_and_station(&db, &team, &station)
|
||||
if Rating::find_by_team_and_station(db, &team, &station)
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
@@ -548,7 +569,7 @@ async fn quick_post(
|
||||
continue;
|
||||
}
|
||||
|
||||
Rating::create_quick(&db, &team, &station, points).await;
|
||||
Rating::create_quick(db, &team, &station, points).await;
|
||||
amount_succ += 1;
|
||||
}
|
||||
|
||||
@@ -577,12 +598,14 @@ async fn update_location(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<UpdateLocationForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
station.update_location(&db, form.lat, form.lng).await;
|
||||
station.update_location(db, form.lat, form.lng).await;
|
||||
|
||||
suc!(session, t!("location_changed", station = station.name));
|
||||
|
||||
@@ -594,12 +617,14 @@ async fn update_location_clear(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_station", id = id));
|
||||
return Redirect::to("/admin/station");
|
||||
};
|
||||
|
||||
station.update_location_clear(&db).await;
|
||||
station.update_location_clear(db).await;
|
||||
|
||||
suc!(session, t!("location_deleted", station = station.name));
|
||||
|
||||
@@ -607,7 +632,9 @@ async fn update_location_clear(
|
||||
}
|
||||
|
||||
async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
let stations = Station::all(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let stations = Station::all(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -641,7 +668,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
}
|
||||
tbody {
|
||||
@for station in &stations {
|
||||
@let status = TeamsAtStationLocation::for_station(&db, station).await;
|
||||
@let status = TeamsAtStationLocation::for_station(db, station).await;
|
||||
tr {
|
||||
td {
|
||||
@if station.ready {
|
||||
@@ -649,7 +676,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
small { "🟢 " }
|
||||
}
|
||||
}
|
||||
@if station.routes(&db).await.is_empty() {
|
||||
@if station.routes(db).await.is_empty() {
|
||||
a href="/admin/route" {
|
||||
em data-tooltip=(t!("station_warning_not_assigned_route")) {
|
||||
"⚠️ "
|
||||
@@ -667,8 +694,8 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
}
|
||||
td {
|
||||
em data-tooltip=(t!("station_team_progress", arrived=status.total_teams-status.not_yet_here.len() as i64, total=status.total_teams, waiting= status.waiting.len(), active=status.doing.len() )) {
|
||||
@if status.not_yet_here.len() == 0 {
|
||||
@if status.waiting.len() == 0 && status.doing.len() == 0 {
|
||||
@if status.not_yet_here.is_empty() {
|
||||
@if status.waiting.is_empty() && status.doing.is_empty() {
|
||||
"✅"
|
||||
}@else{
|
||||
"🔜"
|
||||
|
@@ -7,8 +7,7 @@ use axum::Router;
|
||||
use chrono::{DateTime, Local, NaiveDateTime, Utc};
|
||||
use maud::{html, Markup, Render};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, Sqlite, SqlitePool, Transaction};
|
||||
use std::ops::DerefMut;
|
||||
use sqlx::{FromRow, SqliteConnection};
|
||||
|
||||
mod web;
|
||||
|
||||
@@ -41,7 +40,7 @@ pub(crate) struct LastContactTeam {
|
||||
}
|
||||
|
||||
impl LastContactTeam {
|
||||
pub(crate) async fn all_sort_missing(db: &SqlitePool) -> Vec<Self> {
|
||||
pub(crate) async fn all_sort_missing(db: &mut SqliteConnection) -> Vec<Self> {
|
||||
let rows = sqlx::query_as::<_, (i64, i64, Option<NaiveDateTime>)>(
|
||||
"SELECT
|
||||
t.id AS team_id,
|
||||
@@ -65,13 +64,15 @@ LEFT JOIN station s ON last_contact.station_id = s.id
|
||||
ORDER BY
|
||||
last_contact.last_contact_time DESC",
|
||||
)
|
||||
.fetch_all(db)
|
||||
.fetch_all(&mut *db)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut ret = Vec::new();
|
||||
for (team_id, station_id, last_contact_time) in rows {
|
||||
ret.push(LastContactTeam {
|
||||
team: Team::find_by_id(db, team_id).await.expect("db constraints"),
|
||||
team: Team::find_by_id(&mut *db, team_id)
|
||||
.await
|
||||
.expect("db constraints"),
|
||||
station: Station::find_by_id(db, station_id).await,
|
||||
last_contact_time,
|
||||
});
|
||||
@@ -95,7 +96,7 @@ pub(crate) enum CreateError {
|
||||
}
|
||||
|
||||
impl Team {
|
||||
pub(crate) async fn all(db: &SqlitePool) -> Vec<Self> {
|
||||
pub(crate) async fn all(db: &mut SqliteConnection) -> Vec<Self> {
|
||||
sqlx::query_as::<_, Self>(
|
||||
"SELECT id, name, notes, amount_people, first_station_id, last_station_id, route_id FROM team ORDER BY name;",
|
||||
)
|
||||
@@ -104,7 +105,7 @@ impl Team {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn all_with_route(db: &SqlitePool, route: &Route) -> Vec<Self> {
|
||||
pub(crate) async fn all_with_route(db: &mut SqliteConnection, route: &Route) -> Vec<Self> {
|
||||
sqlx::query_as!(
|
||||
Team,
|
||||
"SELECT id, name, notes, amount_people, first_station_id, last_station_id, route_id FROM team WHERE route_id = ?;",
|
||||
@@ -115,7 +116,10 @@ impl Team {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn all_with_first_station(db: &SqlitePool, station: &Station) -> Vec<Self> {
|
||||
pub(crate) async fn all_with_first_station(
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
) -> Vec<Self> {
|
||||
sqlx::query_as!(
|
||||
Team,
|
||||
"select id, name, notes, amount_people, first_station_id, last_station_id, route_id from team where first_station_id = ?;",
|
||||
@@ -126,7 +130,10 @@ impl Team {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) async fn all_with_last_station(db: &SqlitePool, station: &Station) -> Vec<Self> {
|
||||
pub(crate) async fn all_with_last_station(
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
) -> Vec<Self> {
|
||||
sqlx::query_as!(
|
||||
Team,
|
||||
"select id, name, notes, amount_people, first_station_id, last_station_id, route_id from team where last_station_id = ?;",
|
||||
@@ -137,7 +144,7 @@ impl Team {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
||||
pub async fn find_by_id(db: &mut SqliteConnection, id: i64) -> Option<Self> {
|
||||
sqlx::query_as!(
|
||||
Self,
|
||||
"SELECT id, name, notes, amount_people, first_station_id, last_station_id, route_id FROM team WHERE id = ?",
|
||||
@@ -149,7 +156,7 @@ impl Team {
|
||||
}
|
||||
|
||||
pub(crate) async fn create(
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
name: &str,
|
||||
route: &Route,
|
||||
) -> Result<i64, CreateError> {
|
||||
@@ -171,14 +178,14 @@ impl Team {
|
||||
Ok(result.id.unwrap())
|
||||
}
|
||||
|
||||
async fn update_name(&self, db: &SqlitePool, name: &str) {
|
||||
async fn update_name(&self, db: &mut SqliteConnection, name: &str) {
|
||||
sqlx::query!("UPDATE team SET name = ? WHERE id = ?", name, self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn update_end_station(&self, db: &SqlitePool, station: &Station) {
|
||||
async fn update_end_station(&self, db: &mut SqliteConnection, station: &Station) {
|
||||
sqlx::query!(
|
||||
"UPDATE team SET last_station_id = ? WHERE id = ?",
|
||||
station.id,
|
||||
@@ -189,14 +196,14 @@ impl Team {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn update_notes(&self, db: &SqlitePool, notes: &str) {
|
||||
async fn update_notes(&self, db: &mut SqliteConnection, notes: &str) {
|
||||
sqlx::query!("UPDATE team SET notes = ? WHERE id = ?", notes, self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn update_amount_people(&self, db: &SqlitePool, amount_people: i64) {
|
||||
async fn update_amount_people(&self, db: &mut SqliteConnection, amount_people: i64) {
|
||||
sqlx::query!(
|
||||
"UPDATE team SET amount_people = ? WHERE id = ?",
|
||||
amount_people,
|
||||
@@ -207,7 +214,7 @@ impl Team {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn update_route(&self, db: &SqlitePool, route: &Route) -> Result<String, ()> {
|
||||
async fn update_route(&self, db: &mut SqliteConnection, route: &Route) -> Result<String, ()> {
|
||||
let Some(station) = route.get_next_first_station(db).await else {
|
||||
return Err(());
|
||||
};
|
||||
@@ -225,7 +232,7 @@ impl Team {
|
||||
Ok(station.name)
|
||||
}
|
||||
|
||||
pub(crate) async fn update_first_station(&self, db: &SqlitePool, station: &Station) {
|
||||
pub(crate) async fn update_first_station(&self, db: &mut SqliteConnection, station: &Station) {
|
||||
sqlx::query!(
|
||||
"UPDATE team SET first_station_id = ? WHERE id = ?",
|
||||
station.id,
|
||||
@@ -236,22 +243,7 @@ impl Team {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) async fn update_first_station_tx(
|
||||
&self,
|
||||
db: &mut Transaction<'_, Sqlite>,
|
||||
station: &Station,
|
||||
) {
|
||||
sqlx::query!(
|
||||
"UPDATE team SET first_station_id = ? WHERE id = ?",
|
||||
station.id,
|
||||
self.id
|
||||
)
|
||||
.execute(db.deref_mut())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn update_last_station(&self, db: &SqlitePool, station: &Station) {
|
||||
async fn update_last_station(&self, db: &mut SqliteConnection, station: &Station) {
|
||||
sqlx::query!(
|
||||
"UPDATE team SET last_station_id = ? WHERE id = ?",
|
||||
station.id,
|
||||
@@ -262,14 +254,14 @@ impl Team {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn update_amount_people_reset(&self, db: &SqlitePool) {
|
||||
async fn update_amount_people_reset(&self, db: &mut SqliteConnection) {
|
||||
sqlx::query!("UPDATE team SET amount_people = NULL WHERE id = ?", self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn delete(&self, db: &SqlitePool) -> Result<(), String> {
|
||||
async fn delete(&self, db: &mut SqliteConnection) -> Result<(), String> {
|
||||
sqlx::query!("DELETE FROM team WHERE id = ?", self.id)
|
||||
.execute(db)
|
||||
.await
|
||||
@@ -277,13 +269,13 @@ impl Team {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn first_station(&self, db: &SqlitePool) -> Station {
|
||||
pub async fn first_station(&self, db: &mut SqliteConnection) -> Station {
|
||||
Station::find_by_id(db, self.first_station_id)
|
||||
.await
|
||||
.expect("db constraints")
|
||||
}
|
||||
|
||||
pub async fn last_station(&self, db: &SqlitePool) -> Option<Station> {
|
||||
pub async fn last_station(&self, db: &mut SqliteConnection) -> Option<Station> {
|
||||
if let Some(last_station_id) = self.last_station_id {
|
||||
Station::find_by_id(db, last_station_id).await
|
||||
} else {
|
||||
@@ -291,13 +283,13 @@ impl Team {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn route(&self, db: &SqlitePool) -> Route {
|
||||
pub async fn route(&self, db: &mut SqliteConnection) -> Route {
|
||||
Route::find_by_id(db, self.route_id)
|
||||
.await
|
||||
.expect("db constraints")
|
||||
}
|
||||
|
||||
pub async fn get_curr_points(&self, db: &SqlitePool) -> i64 {
|
||||
pub async fn get_curr_points(&self, db: &mut SqliteConnection) -> i64 {
|
||||
sqlx::query!(
|
||||
"SELECT IFNULL(sum(points), 0) as points FROM rating WHERE team_id = ?",
|
||||
self.id
|
||||
@@ -308,13 +300,13 @@ impl Team {
|
||||
.points
|
||||
}
|
||||
|
||||
pub async fn been_at_station(&self, db: &SqlitePool, station: &Station) -> bool {
|
||||
pub async fn been_at_station(&self, db: &mut SqliteConnection, station: &Station) -> bool {
|
||||
Rating::find_by_team_and_station(db, self, station)
|
||||
.await
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub(crate) async fn end_station(&self, db: &SqlitePool) -> Station {
|
||||
pub(crate) async fn end_station(&self, db: &mut SqliteConnection) -> Station {
|
||||
match LastContactTeam::all_sort_missing(db)
|
||||
.await
|
||||
.into_iter()
|
||||
@@ -355,7 +347,7 @@ impl Team {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn end_run(db: &SqlitePool) {
|
||||
pub async fn end_run(db: &mut SqliteConnection) {
|
||||
// set `last_station_id` to the next station where `left_at` is not null
|
||||
let teams = Team::all(db).await;
|
||||
for team in teams {
|
||||
@@ -364,7 +356,7 @@ impl Team {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn restart_run(db: &SqlitePool) {
|
||||
pub async fn restart_run(db: &mut SqliteConnection) {
|
||||
sqlx::query!("UPDATE team SET last_station_id = null")
|
||||
.execute(db)
|
||||
.await
|
||||
|
@@ -14,7 +14,8 @@ use axum::{
|
||||
};
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
use serde::Deserialize;
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::{SqliteConnection, SqlitePool};
|
||||
use std::fmt::Write;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tower_sessions::Session;
|
||||
|
||||
@@ -29,13 +30,15 @@ async fn create(
|
||||
session: Session,
|
||||
Form(form): Form<CreateForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(route) = Route::find_by_id(&db, form.route_id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 {
|
||||
let id = match Team::create(db, &form.name, &route).await {
|
||||
Ok(id) => {
|
||||
suc!(session, t!("team_created", team = form.name));
|
||||
id
|
||||
@@ -70,12 +73,14 @@ async fn delete(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(team) = Team::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 {
|
||||
match team.delete(db).await {
|
||||
Ok(()) => suc!(session, t!("team_deleted", team = team.name)),
|
||||
Err(e) => er!(
|
||||
session,
|
||||
@@ -86,7 +91,12 @@ async fn delete(
|
||||
Redirect::to("/admin/team")
|
||||
}
|
||||
|
||||
async fn quick(db: Arc<SqlitePool>, team: &Team, stations: Vec<Station>, redirect: &str) -> Markup {
|
||||
async fn quick(
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
stations: Vec<Station>,
|
||||
redirect: &str,
|
||||
) -> Markup {
|
||||
html! {
|
||||
h1 {
|
||||
a href=(format!("/admin/team/{}", team.id)) { "↩️" }
|
||||
@@ -114,7 +124,7 @@ async fn quick(db: Arc<SqlitePool>, team: &Team, stations: Vec<Station>, redirec
|
||||
}
|
||||
}
|
||||
td {
|
||||
@if let Some(rating) = Rating::find_by_team_and_station(&db, team, station).await {
|
||||
@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")) {
|
||||
@@ -142,12 +152,14 @@ async fn quick_crewless(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 stations: Vec<Station> = team.route(db).await.crewless_stations(db).await;
|
||||
|
||||
let content = quick(db, &team, stations, "/crewless").await;
|
||||
|
||||
@@ -159,12 +171,14 @@ async fn quick_all(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 stations = team.route(db).await.stations(db).await;
|
||||
|
||||
let content = quick(db, &team, stations, "").await;
|
||||
|
||||
@@ -183,7 +197,9 @@ async fn quick_post(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(team) = Team::find_by_id(db, id).await else {
|
||||
er!(session, t!("nonexisting_team", id = id));
|
||||
return Redirect::to("/admin/team");
|
||||
};
|
||||
@@ -193,24 +209,27 @@ async fn quick_post(
|
||||
|
||||
for (station_id, points) in &form.fields {
|
||||
let Ok(station_id) = station_id.parse::<i64>() else {
|
||||
ret.push_str(&format!(
|
||||
let _ = write!(
|
||||
ret,
|
||||
"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",
|
||||
));
|
||||
let _ = write!(
|
||||
ret,
|
||||
"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!(
|
||||
let Some(station) = Station::find_by_id(&mut *db, station_id).await else {
|
||||
let _ = write!(
|
||||
ret,
|
||||
"Skipped stationid={station_id} because this station does not exist"
|
||||
));
|
||||
);
|
||||
continue;
|
||||
};
|
||||
if Rating::find_by_team_and_station(&db, &team, &station)
|
||||
if Rating::find_by_team_and_station(db, &team, &station)
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
@@ -224,7 +243,7 @@ async fn quick_post(
|
||||
continue;
|
||||
}
|
||||
|
||||
Rating::create_quick(&db, &team, &station, points).await;
|
||||
Rating::create_quick(db, &team, &station, points).await;
|
||||
amount_succ += 1;
|
||||
}
|
||||
|
||||
@@ -247,15 +266,17 @@ async fn view(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 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;
|
||||
let stations = team.route(db).await.crewful_stations(db).await;
|
||||
|
||||
// maybe switch to maud-display impl of team
|
||||
let content = html! {
|
||||
@@ -335,8 +356,8 @@ async fn view(
|
||||
tr {
|
||||
th scope="row" { (t!("route")) };
|
||||
td {
|
||||
a href=(format!("/admin/route/{}", &team.route(&db).await.id)) {
|
||||
(&team.route(&db).await.name)
|
||||
a href=(format!("/admin/route/{}", &team.route(db).await.id)) {
|
||||
(&team.route(db).await.name)
|
||||
}
|
||||
@if routes.len() > 1 {
|
||||
details {
|
||||
@@ -344,7 +365,7 @@ async fn view(
|
||||
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 {
|
||||
@if route.id != team.route(db).await.id {
|
||||
option value=(route.id) {
|
||||
(route.name)
|
||||
}
|
||||
@@ -377,7 +398,7 @@ async fn view(
|
||||
@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();
|
||||
@let amount_start_teams = Team::all_with_first_station(db, station).await.len();
|
||||
@if amount_start_teams > 0 {
|
||||
@if amount_start_teams == 1 {
|
||||
" ("
|
||||
@@ -456,12 +477,14 @@ async fn update_name(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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;
|
||||
team.update_name(db, &form.name).await;
|
||||
|
||||
suc!(
|
||||
session,
|
||||
@@ -481,12 +504,14 @@ async fn update_notes(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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;
|
||||
team.update_notes(db, &form.notes).await;
|
||||
|
||||
suc!(session, t!("notes_edited", team = team.name));
|
||||
|
||||
@@ -503,12 +528,14 @@ async fn update_amount_people(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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;
|
||||
team.update_amount_people(db, form.amount_people).await;
|
||||
|
||||
suc!(session, t!("amount_teammembers_edited", team = team.name));
|
||||
|
||||
@@ -525,18 +552,20 @@ async fn update_route(
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
Form(form): Form<UpdateRouteForm>,
|
||||
) -> impl IntoResponse {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
// TODO: move sanity checks into mod.rs
|
||||
let Some(team) = Team::find_by_id(&db, id).await else {
|
||||
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 {
|
||||
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 {
|
||||
match team.update_route(db, &route).await {
|
||||
Ok(new_first_station_name) => suc!(
|
||||
session,
|
||||
t!(
|
||||
@@ -569,12 +598,14 @@ async fn update_first_station(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 {
|
||||
let Some(station) = Station::find_by_id(&mut *db, form.first_station_id).await else {
|
||||
er!(
|
||||
session,
|
||||
t!("nonexisting_station", id = form.first_station_id)
|
||||
@@ -583,21 +614,22 @@ async fn update_first_station(
|
||||
return Redirect::to(&format!("/admin/team/{id}"));
|
||||
};
|
||||
|
||||
if !station.is_in_route(&db, &team.route(&db).await).await {
|
||||
let route = team.route(db).await;
|
||||
if !station.is_in_route(db, &route).await {
|
||||
er!(
|
||||
session,
|
||||
t!(
|
||||
"first_station_not_edited_not_on_route",
|
||||
station = station.name,
|
||||
team = team.name,
|
||||
route = team.route(&db).await.name
|
||||
route = team.route(db).await.name
|
||||
)
|
||||
);
|
||||
|
||||
return Redirect::to(&format!("/admin/team/{id}"));
|
||||
}
|
||||
|
||||
team.update_first_station(&db, &station).await;
|
||||
team.update_first_station(db, &station).await;
|
||||
|
||||
suc!(
|
||||
session,
|
||||
@@ -621,12 +653,14 @@ async fn update_last_station(
|
||||
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 {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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 {
|
||||
let Some(station) = Station::find_by_id(&mut *db, form.last_station_id).await else {
|
||||
er!(
|
||||
session,
|
||||
t!("nonexisting_station", id = form.last_station_id)
|
||||
@@ -634,21 +668,22 @@ async fn update_last_station(
|
||||
return Redirect::to(&format!("/admin/team/{id}"));
|
||||
};
|
||||
|
||||
if !station.is_in_route(&db, &team.route(&db).await).await {
|
||||
let route = team.route(db).await;
|
||||
if !station.is_in_route(db, &route).await {
|
||||
er!(
|
||||
session,
|
||||
t!(
|
||||
"last_station_not_edited_not_on_route",
|
||||
station = station.name,
|
||||
team = team.name,
|
||||
route = team.route(&db).await.name
|
||||
route = team.route(db).await.name
|
||||
)
|
||||
);
|
||||
|
||||
return Redirect::to(&format!("/admin/team/{id}"));
|
||||
}
|
||||
|
||||
team.update_last_station(&db, &station).await;
|
||||
team.update_last_station(db, &station).await;
|
||||
|
||||
suc!(
|
||||
session,
|
||||
@@ -667,12 +702,14 @@ async fn update_amount_people_reset(
|
||||
session: Session,
|
||||
axum::extract::Path(id): axum::extract::Path<i64>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(team) = Team::find_by_id(&db, id).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
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;
|
||||
team.update_amount_people_reset(db).await;
|
||||
|
||||
suc!(session, t!("amount_teammembers_edited", team = team.name));
|
||||
|
||||
@@ -680,7 +717,9 @@ async fn update_amount_people_reset(
|
||||
}
|
||||
|
||||
async fn lost(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
let losts = LastContactTeam::all_sort_missing(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let losts = LastContactTeam::all_sort_missing(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -731,8 +770,10 @@ async fn lost(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
}
|
||||
|
||||
async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
let teams = Team::all(&db).await;
|
||||
let routes = Route::all(&db).await;
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let teams = Team::all(db).await;
|
||||
let routes = Route::all(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -792,7 +833,7 @@ async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||
@for route in &routes {
|
||||
h2 { (route.name) }
|
||||
ol {
|
||||
@for team in &route.teams(&db).await{
|
||||
@for team in &route.teams(db).await{
|
||||
li {
|
||||
a href=(format!("/admin/team/{}", team.id)){
|
||||
(team.name)
|
||||
|
@@ -302,7 +302,7 @@ pub async fn start(listener: TcpListener, db: SqlitePool) {
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Kick-off typst compilation, to reduce wait time for 1st load
|
||||
let stations = Station::all(&db).await;
|
||||
let stations = Station::all(&mut db.acquire().await.unwrap()).await;
|
||||
station_pdf(stations).await;
|
||||
});
|
||||
|
||||
|
@@ -4,7 +4,7 @@ use crate::{
|
||||
};
|
||||
use chrono::{DateTime, Local, NaiveDateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{FromRow, SqlitePool};
|
||||
use sqlx::{FromRow, SqliteConnection};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
||||
@@ -20,7 +20,7 @@ pub(crate) struct Rating {
|
||||
|
||||
impl Rating {
|
||||
pub(crate) async fn create(
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
@@ -35,7 +35,12 @@ impl Rating {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn create_quick(db: &SqlitePool, team: &Team, station: &Station, points: i64) {
|
||||
pub(crate) async fn create_quick(
|
||||
db: &mut SqliteConnection,
|
||||
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,
|
||||
@@ -47,19 +52,19 @@ impl Rating {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) async fn team(&self, db: &SqlitePool) -> Team {
|
||||
pub(crate) async fn team(&self, db: &mut SqliteConnection) -> Team {
|
||||
Team::find_by_id(db, self.team_id)
|
||||
.await
|
||||
.expect("db constraints")
|
||||
}
|
||||
|
||||
pub(crate) async fn station(&self, db: &SqlitePool) -> Station {
|
||||
pub(crate) async fn station(&self, db: &mut SqliteConnection) -> Station {
|
||||
Station::find_by_id(db, self.station_id)
|
||||
.await
|
||||
.expect("db constraints")
|
||||
}
|
||||
|
||||
pub(crate) async fn for_station(db: &SqlitePool, station: &Station) -> Vec<Self> {
|
||||
pub(crate) async fn for_station(db: &mut SqliteConnection, station: &Station) -> Vec<Self> {
|
||||
sqlx::query_as::<_, Self>("SELECT team_id, station_id, points, notes, arrived_at, started_at, left_at FROM rating WHERE station_id = ?;")
|
||||
.bind(station.id)
|
||||
.fetch_all(db)
|
||||
@@ -68,7 +73,7 @@ impl Rating {
|
||||
}
|
||||
|
||||
pub(crate) async fn update(
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
team: &Team,
|
||||
points: Option<i64>,
|
||||
@@ -88,7 +93,7 @@ impl Rating {
|
||||
}
|
||||
|
||||
pub(crate) async fn delete(
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
team: &Team,
|
||||
) -> Result<(), String> {
|
||||
@@ -103,7 +108,7 @@ impl Rating {
|
||||
Ok(())
|
||||
}
|
||||
pub async fn find_by_team_and_station(
|
||||
db: &SqlitePool,
|
||||
db: &mut SqliteConnection,
|
||||
team: &Team,
|
||||
station: &Station,
|
||||
) -> Option<Self> {
|
||||
@@ -152,7 +157,10 @@ pub(crate) struct TeamsAtStationLocation {
|
||||
}
|
||||
|
||||
impl TeamsAtStationLocation {
|
||||
pub(crate) async fn for_station(db: &SqlitePool, station: &Station) -> TeamsAtStationLocation {
|
||||
pub(crate) async fn for_station(
|
||||
db: &mut SqliteConnection,
|
||||
station: &Station,
|
||||
) -> TeamsAtStationLocation {
|
||||
let teams = station.teams(db).await;
|
||||
let total_teams = teams.len() as i64;
|
||||
|
||||
@@ -165,27 +173,24 @@ impl TeamsAtStationLocation {
|
||||
let mut done = true;
|
||||
|
||||
for team in teams {
|
||||
match Rating::find_by_team_and_station(db, &team, station).await {
|
||||
Some(rating) => {
|
||||
if rating.left_at.is_some() {
|
||||
if rating.points.is_some() {
|
||||
left_and_rated.push((team, rating));
|
||||
} else {
|
||||
done = false;
|
||||
left_not_yet_rated.push((team, rating));
|
||||
}
|
||||
} else if rating.started_at.is_some() {
|
||||
done = false;
|
||||
doing.push((team, rating));
|
||||
if let Some(rating) = Rating::find_by_team_and_station(db, &team, station).await {
|
||||
if rating.left_at.is_some() {
|
||||
if rating.points.is_some() {
|
||||
left_and_rated.push((team, rating));
|
||||
} else {
|
||||
done = false;
|
||||
waiting.push((team, rating));
|
||||
left_not_yet_rated.push((team, rating));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
} else if rating.started_at.is_some() {
|
||||
done = false;
|
||||
not_yet_here.push(team)
|
||||
doing.push((team, rating));
|
||||
} else {
|
||||
done = false;
|
||||
waiting.push((team, rating));
|
||||
}
|
||||
} else {
|
||||
done = false;
|
||||
not_yet_here.push(team);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,9 +208,9 @@ impl TeamsAtStationLocation {
|
||||
not_yet_here_by_route,
|
||||
waiting,
|
||||
doing,
|
||||
done,
|
||||
left_not_yet_rated,
|
||||
left_and_rated,
|
||||
done,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,9 @@ async fn view(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code)): axum::extract::Path<(i64, String)>,
|
||||
) -> Markup {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
let content = html! {
|
||||
article class="error" {
|
||||
(t!("invalid_rating_code"))
|
||||
@@ -30,9 +32,9 @@ async fn view(
|
||||
return partials::page(content, session, false).await;
|
||||
};
|
||||
|
||||
let teams = TeamsAtStationLocation::for_station(&db, &station).await;
|
||||
let teams_on_the_way = station.teams_on_the_way(&db).await;
|
||||
let status = RunStatus::curr(&db).await;
|
||||
let teams = TeamsAtStationLocation::for_station(db, &station).await;
|
||||
let teams_on_the_way = station.teams_on_the_way(db).await;
|
||||
let status = RunStatus::curr(db).await;
|
||||
|
||||
let content = html! {
|
||||
h1 {
|
||||
@@ -47,7 +49,7 @@ async fn view(
|
||||
"👋"
|
||||
(t!("station_info"))
|
||||
" "
|
||||
@let first_teams = Team::all_with_first_station(&db, &station).await;
|
||||
@let first_teams = Team::all_with_first_station(db, &station).await;
|
||||
@if first_teams.is_empty() {
|
||||
(t!("station_has_no_teams_to_take_to_start"))
|
||||
} @else{
|
||||
@@ -145,7 +147,7 @@ async fn view(
|
||||
}
|
||||
@if status == RunStatus::HasEnded {
|
||||
(t!("station_done"))
|
||||
@let teams_to_take_home = Team::all_with_last_station(&db, &station).await;
|
||||
@let teams_to_take_home = Team::all_with_last_station(db, &station).await;
|
||||
@if !teams_to_take_home.is_empty() {
|
||||
@if teams_to_take_home.len() == 1 {
|
||||
(t!("take_home_the_following_team"))
|
||||
@@ -379,12 +381,14 @@ async fn ready(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code)): axum::extract::Path<(i64, String)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
station.switch_ready(&db).await;
|
||||
station.switch_ready(db).await;
|
||||
|
||||
suc!(session, t!("succ_change"));
|
||||
Redirect::to(&format!("/s/{id}/{code}"))
|
||||
@@ -400,16 +404,18 @@ async fn new_waiting(
|
||||
axum::extract::Path((id, code)): axum::extract::Path<(i64, String)>,
|
||||
Form(form): Form<NewWaitingForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
let Some(team) = Team::find_by_id(&db, form.team_id).await else {
|
||||
let Some(team) = Team::find_by_id(db, form.team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = form.team_id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station.new_team_waiting(&db, &team).await {
|
||||
match station.new_team_waiting(db, &team).await {
|
||||
Ok(()) => suc!(session, t!("team_added_to_waiting", team = team.name)),
|
||||
Err(e) => err!(session, "{e}"),
|
||||
}
|
||||
@@ -422,17 +428,19 @@ async fn remove_waiting(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code, team_id)): axum::extract::Path<(i64, String, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
let Some(team) = Team::find_by_id(db, team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = team_id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station.remove_team_waiting(&db, &team).await {
|
||||
match station.remove_team_waiting(db, &team).await {
|
||||
Ok(()) => suc!(session, t!("team_removed_from_waiting", team = team.name)),
|
||||
Err(e) => err!(session, "{e}"),
|
||||
}
|
||||
@@ -445,17 +453,18 @@ async fn team_starting(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code, team_id)): axum::extract::Path<(i64, String, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
let Some(station) = Station::login(&mut *db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
let Some(team) = Team::find_by_id(&mut *db, team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = team_id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station.team_starting(&db, &team).await {
|
||||
match station.team_starting(&mut *db, &team).await {
|
||||
Ok(()) => suc!(session, t!("team_added_to_active", team = team.name)),
|
||||
Err(e) => err!(session, "{e}"),
|
||||
}
|
||||
@@ -468,17 +477,19 @@ async fn remove_doing(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code, team_id)): axum::extract::Path<(i64, String, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
let Some(team) = Team::find_by_id(db, team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station.remove_team_doing(&db, &team).await {
|
||||
match station.remove_team_doing(db, &team).await {
|
||||
Ok(()) => suc!(session, t!("team_removed_from_active", team = team.name)),
|
||||
Err(e) => err!(session, "{e}"),
|
||||
}
|
||||
@@ -491,17 +502,19 @@ async fn team_finished(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code, team_id)): axum::extract::Path<(i64, String, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
let Some(team) = Team::find_by_id(db, team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station.team_finished(&db, &team).await {
|
||||
match station.team_finished(db, &team).await {
|
||||
Ok(()) => suc!(session, t!("team_added_to_finished", team = team.name)),
|
||||
Err(e) => err!(session, "{e}"),
|
||||
}
|
||||
@@ -514,17 +527,19 @@ async fn remove_left(
|
||||
session: Session,
|
||||
axum::extract::Path((id, code, team_id)): axum::extract::Path<(i64, String, i64)>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
let Some(team) = Team::find_by_id(db, team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station.remove_team_left(&db, &team).await {
|
||||
match station.remove_team_left(db, &team).await {
|
||||
Ok(()) => suc!(session, t!("team_removed_from_finished", team = team.name)),
|
||||
Err(e) => err!(session, "{e}"),
|
||||
}
|
||||
@@ -543,17 +558,18 @@ async fn team_update(
|
||||
axum::extract::Path((id, code, team_id)): axum::extract::Path<(i64, String, i64)>,
|
||||
Form(form): Form<TeamUpdateForm>,
|
||||
) -> impl IntoResponse {
|
||||
let Some(station) = Station::login(&db, id, &code).await else {
|
||||
let db = &mut *db.acquire().await.unwrap();
|
||||
let Some(station) = Station::login(db, id, &code).await else {
|
||||
er!(session, t!("invalid_rating_code"));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
let Some(team) = Team::find_by_id(&db, team_id).await else {
|
||||
let Some(team) = Team::find_by_id(db, team_id).await else {
|
||||
er!(session, t!("nonexisting_team", id = id));
|
||||
return Redirect::to("/s/{id}/{code}");
|
||||
};
|
||||
|
||||
match station
|
||||
.team_update(&db, &team, form.points, form.notes)
|
||||
.team_update(db, &team, form.points, form.notes)
|
||||
.await
|
||||
{
|
||||
Ok(()) => suc!(session, t!("rating_updated", team = team.name)),
|
||||
@@ -587,8 +603,9 @@ mod test {
|
||||
#[sqlx::test]
|
||||
async fn test_wrong_station() {
|
||||
let pool = testdb!();
|
||||
let db = &mut *pool.acquire().await.unwrap();
|
||||
|
||||
Station::create(&pool, "Teststation").await.unwrap();
|
||||
Station::create(db, "Teststation").await.unwrap();
|
||||
|
||||
let server = TestServer::new(router(pool)).unwrap();
|
||||
|
||||
@@ -600,9 +617,10 @@ mod test {
|
||||
#[sqlx::test]
|
||||
async fn test_correct_station() {
|
||||
let pool = testdb!();
|
||||
let db = &mut *pool.acquire().await.unwrap();
|
||||
|
||||
Station::create(&pool, "42-Station").await.unwrap();
|
||||
let stations = Station::all(&pool).await;
|
||||
Station::create(db, "42-Station").await.unwrap();
|
||||
let stations = Station::all(db).await;
|
||||
let station = stations.last().unwrap();
|
||||
|
||||
let server = TestServer::new(router(pool)).unwrap();
|
||||
|
Reference in New Issue
Block a user