feat(api): build bingo card generation
This commit is contained in:
87
Cargo.lock
generated
87
Cargo.lock
generated
@ -439,7 +439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@ -632,7 +632,7 @@ dependencies = [
|
||||
"hkdf",
|
||||
"pem-rfc7468",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"sec1",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
@ -697,7 +697,7 @@ version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@ -756,9 +756,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@ -766,15 +766,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@ -794,27 +794,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
@ -875,7 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
@ -1202,7 +1202,6 @@ dependencies = [
|
||||
name = "ice-bingo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"axum-auth",
|
||||
"axum-core",
|
||||
@ -1210,6 +1209,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"config",
|
||||
"openidconnect",
|
||||
"rand 0.9.1",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1450,7 +1450,7 @@ dependencies = [
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
@ -1501,7 +1501,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"getrandom 0.2.15",
|
||||
"http 0.2.12",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.11.27",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1543,7 +1543,7 @@ dependencies = [
|
||||
"oauth2",
|
||||
"p256",
|
||||
"p384",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rsa",
|
||||
"serde",
|
||||
"serde-value",
|
||||
@ -1834,8 +1834,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1845,7 +1855,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1857,6 +1877,15 @@ dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.6"
|
||||
@ -2001,7 +2030,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"signature",
|
||||
"spki",
|
||||
"subtle",
|
||||
@ -2371,7 +2400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2541,7 +2570,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rsa",
|
||||
"serde",
|
||||
"sha1",
|
||||
@ -2581,7 +2610,7 @@ dependencies = [
|
||||
"md-5",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
@ -22,4 +22,4 @@ reqwest = { version = "0.12.15", features = ["json"] }
|
||||
strum = { version = "0.27.1", features = ["derive"] }
|
||||
strum_macros = "0.27.1"
|
||||
chrono = { version = "0.4.41", features = ["alloc"] }
|
||||
async-trait = "0.1.88"
|
||||
rand = "0.9.1"
|
94
src/api/bingo_card.rs
Normal file
94
src/api/bingo_card.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use std::sync::Arc;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::rng;
|
||||
use sqlx::PgPool;
|
||||
use sqlx::postgres::PgQueryResult;
|
||||
use uuid::Uuid;
|
||||
use crate::model;
|
||||
use crate::model::bingo_card::BingoCard;
|
||||
use crate::model::database::BingoCardField;
|
||||
use crate::model::database::Train;
|
||||
|
||||
pub(crate) async fn get(id: Uuid, db: Arc<PgPool>) -> sqlx::Result<BingoCard> {
|
||||
let card = sqlx::query_as!(
|
||||
crate::model::database::BingoCard,
|
||||
"SELECT uuid as id FROM bingo_cards WHERE uuid = $1",
|
||||
id,
|
||||
).fetch_one(db.as_ref()).await?;
|
||||
let mut raw_fields = get_fields_with_train(card.id, db.clone())
|
||||
.await?;
|
||||
raw_fields.sort_by(|a, b| (a.y * 5 + a.x).partial_cmp(&(b.y * 5 + b.x)).unwrap());
|
||||
raw_fields.truncate(24);
|
||||
raw_fields.shrink_to_fit();
|
||||
let fields: [Train; 24] = raw_fields
|
||||
.into_iter()
|
||||
.map(|field| field.train)
|
||||
.collect::<Vec<Train>>()
|
||||
.try_into()
|
||||
.unwrap_or_else(|v: Vec<Train>| panic!("Expected a Vec of length 24 but it was {}", v.len()));
|
||||
Ok(BingoCard {
|
||||
id: card.id,
|
||||
fields
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_fields_with_train(id: Uuid, db: Arc<PgPool>) -> sqlx::Result<Vec<BingoCardField>> {
|
||||
sqlx::query_as(
|
||||
"SELECT c.uuid, c.x_pos, c.y_pos, c.card_uuid, t.uuid, t.tz_id, t.name FROM bingo_card c LEFT JOIN triebzug t ON t.uuid = c.triebzug WHERE card_uuid = $1"
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_all(db.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn generate(db: Arc<PgPool>) -> sqlx::Result<BingoCard> {
|
||||
let card_id = Uuid::new_v4();
|
||||
let mut all_trains = fetch_all(db.clone()).await?;
|
||||
all_trains.shuffle(&mut rng());
|
||||
all_trains.truncate(24);
|
||||
all_trains.shrink_to_fit();
|
||||
let trains = all_trains.to_owned();
|
||||
let fields = trains
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, train)| BingoCardField {
|
||||
uuid: Uuid::new_v4(),
|
||||
x: (idx as i32).rem_euclid(5),
|
||||
y: (idx as i32).div_euclid(5),
|
||||
train,
|
||||
card_id
|
||||
})
|
||||
.collect::<Vec<BingoCardField>>();
|
||||
let card = model::database::BingoCard {
|
||||
id: card_id,
|
||||
};
|
||||
save_card(card, db.clone()).await?;
|
||||
for field in fields {
|
||||
save_card_field(field, db.clone()).await?;
|
||||
}
|
||||
get(card_id, db.clone()).await
|
||||
}
|
||||
|
||||
async fn save_card(card: model::database::BingoCard, db: Arc<PgPool>) -> sqlx::Result<PgQueryResult> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO bingo_cards VALUES ($1, NOW(), NOW() + interval '7 day')",
|
||||
card.id
|
||||
).execute(db.as_ref()).await
|
||||
}
|
||||
|
||||
async fn save_card_field(field: BingoCardField, db: Arc<PgPool>) -> sqlx::Result<PgQueryResult> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO bingo_card VALUES ($1, $2, $3, $4, $5)",
|
||||
field.uuid,
|
||||
field.x,
|
||||
field.y,
|
||||
field.train.uuid,
|
||||
field.card_id
|
||||
).execute(db.as_ref()).await
|
||||
}
|
||||
|
||||
async fn fetch_all(db: Arc<PgPool>) -> sqlx::Result<Vec<Train>> {
|
||||
sqlx::query_as("SELECT * FROM triebzug")
|
||||
.fetch_all(db.as_ref())
|
||||
.await
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub(crate) mod handlers;
|
||||
mod db_vendo_navigator;
|
||||
pub(crate) mod bingo_card;
|
||||
mod db_vendo_navigator;
|
||||
|
@ -22,6 +22,8 @@ async fn main() {
|
||||
let state: AppState = AppState::new(config.clone()).await.unwrap();
|
||||
migrate(state.clone()).await.expect("Database migration failed");
|
||||
|
||||
crate::api::bingo_card::generate(state.db.clone()).await.unwrap();
|
||||
|
||||
let router = build_router(state);
|
||||
let listener = listen(config).await;
|
||||
axum::serve::serve(listener, router).await.unwrap()
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::model::train::Train;
|
||||
use crate::model::database::Train;
|
||||
|
||||
struct BingoCard {
|
||||
id: uuid::Uuid,
|
||||
fields: [Train; 24],
|
||||
pub struct BingoCard {
|
||||
pub id: uuid::Uuid,
|
||||
pub fields: [Train; 24],
|
||||
}
|
@ -11,4 +11,22 @@ pub struct Train {
|
||||
pub uuid: Uuid,
|
||||
pub tz_id: i32,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Debug, Clone)]
|
||||
pub struct BingoCardField {
|
||||
pub uuid: Uuid,
|
||||
#[sqlx(rename = "x_pos")]
|
||||
pub x: i32,
|
||||
#[sqlx(rename = "y_pos")]
|
||||
pub y: i32,
|
||||
#[sqlx(rename = "card_uuid")]
|
||||
pub card_id: Uuid,
|
||||
#[sqlx(flatten, rename = "triebzug")]
|
||||
pub train: Train,
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Debug, Clone)]
|
||||
pub struct BingoCard {
|
||||
pub id: Uuid,
|
||||
}
|
@ -2,7 +2,7 @@ pub mod uic;
|
||||
pub mod db_vendo_navigator_api;
|
||||
pub(crate) mod travelynx;
|
||||
pub(crate) mod traewelling;
|
||||
mod bingo_card;
|
||||
mod train;
|
||||
pub(crate) mod bingo_card;
|
||||
pub(crate) mod train;
|
||||
pub(crate) mod app;
|
||||
pub(crate) mod database;
|
@ -7,8 +7,8 @@ CREATE TABLE IF NOT EXISTS triebzug (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bingo_cards (
|
||||
uuid UUID PRIMARY KEY,
|
||||
start_time INT NOT NULL,
|
||||
end_time INT NOT NULL
|
||||
start_time TIMESTAMP NOT NULL,
|
||||
end_time TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bingo_card (
|
||||
|
Reference in New Issue
Block a user