From a09e5a6ebde466a406d5619267220b0a4b4f15f6 Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Thu, 21 May 2026 22:24:51 -0700 Subject: [PATCH 1/8] Add functions for updating a game --- Cargo.lock | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/db.rs | 29 +++++++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 4d02117..1b3e023 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -587,6 +587,40 @@ dependencies = [ "memchr", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "deranged" version = "0.5.5" @@ -1029,6 +1063,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "http" version = "0.2.12" @@ -1323,6 +1363,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -1376,6 +1422,17 @@ dependencies = [ "hashbrown 0.16.0", ] +[[package]] +name = "inherent" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1554,6 +1611,7 @@ dependencies = [ "r2d2_sqlite", "reqwest", "rusqlite", + "sea-query", "serde", "serde_json", "tempfile", @@ -2206,6 +2264,31 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sea-query" +version = "1.0.0-rc.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e01d76c67146262612a9db50cbc4b4b3236a96a1f04f1744ef2582234187e2" +dependencies = [ + "inherent", + "itoa", + "sea-query-derive", +] + +[[package]] +name = "sea-query-derive" +version = "1.0.0-rc.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d88ad44b6ad9788c8b9476b6b91f94c7461d1e19d39cd8ea37838b1e6ff5aa8" +dependencies = [ + "darling", + "heck", + "proc-macro2", + "quote", + "syn", + "thiserror", +] + [[package]] name = "security-framework" version = "2.11.1" diff --git a/Cargo.toml b/Cargo.toml index 290857c..f270e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ r2d2 = "0.8.10" r2d2_sqlite = "0.31.0" reqwest = "0.12.24" rusqlite = {version="0.37.0", features=["bundled"]} +sea-query = "1.0.0-rc.34" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.145" tera = "1.20.1" diff --git a/src/db.rs b/src/db.rs index 1c3f13c..f94defb 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,6 +1,7 @@ use crate::data::{Game, Player, Team}; use actix_web::{Error, error, web}; use rusqlite::Row; +use sea_query::{Expr, ExprTrait, Query, SqliteQueryBuilder}; use serde_json::{Map, Value}; use std::collections::HashMap; @@ -54,6 +55,16 @@ pub async fn teams(pool: &Pool) -> Result, Error> { .map_err(error::ErrorInternalServerError) } +pub async fn update_game(pool: &Pool, game: Game) -> Result<(), Error> { + let pool = pool.clone(); + let conn = web::block(move || pool.get()) + .await? + .map_err(error::ErrorInternalServerError)?; + web::block(move || update_game_sqlite(conn, game)) + .await? + .map_err(error::ErrorInternalServerError) +} + fn get_all_games(conn: Connection, all_teams: HashMap) -> GamesResult { let mut games_stmt = conn.prepare(GAMES_QUERY)?; games_stmt @@ -72,6 +83,24 @@ fn get_all_games(conn: Connection, all_teams: HashMap) -> GamesRes .and_then(Iterator::collect) } +fn update_game_sqlite(conn: Connection, game: Game) -> Result<(), rusqlite::Error> { + let update_query = Query::update() + .table("games") + .values([("start_time", game.start_time.into()), ("end_time", game.end_time.into())]) + .and_where(Expr::col("code").eq(game.code)) + .to_owned(); + let mut update_stmt = conn.prepare( + &update_query.to_string(SqliteQueryBuilder) + )?; + + let result = update_stmt.query([]); + + match result { + Ok(_) => Ok(()), + Err(error) => Err(error) + } +} + fn get_all_teams(conn: Connection) -> TeamsResult { let mut teams_stmt = conn.prepare(TEAMS_QUERY)?; teams_stmt -- 2.49.0 From 4d07d6aff59b6a767f8f957b14436e189a2faa09 Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Thu, 21 May 2026 22:25:20 -0700 Subject: [PATCH 2/8] Add stub function for game update endpoint --- src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index d72edb0..542649f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -193,6 +193,13 @@ async fn list_of_games(games: web::Data>>>) -> impl Responde .body(games_json) } +#[post("/admin/game/{game_code}")] +async fn update_game(pool: web::Data, form: web::Form) -> impl Responder { + db::update_game(&pool, form.into_inner()).await.unwrap(); + + HttpResponse::Ok() +} + #[post("/admin/query")] async fn admin_query(pool: web::Data, form: web::Form) -> impl Responder { let res: String; @@ -219,7 +226,7 @@ async fn main() -> std::io::Result<()> { games: state.clone(), } .start(); - sync_scores(actor_addr.clone()).await; + //sync_scores(actor_addr.clone()).await; HttpServer::new(move || { App::new() .app_data(web::Data::new(pool.clone())) -- 2.49.0 From fcb6ef2aac1683649f60d83a262aedbb517af834 Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Sat, 23 May 2026 20:16:14 -0700 Subject: [PATCH 3/8] Uncomment sync_scores, format --- src/db.rs | 13 +++++++------ src/main.rs | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/db.rs b/src/db.rs index f94defb..0750fbf 100644 --- a/src/db.rs +++ b/src/db.rs @@ -86,18 +86,19 @@ fn get_all_games(conn: Connection, all_teams: HashMap) -> GamesRes fn update_game_sqlite(conn: Connection, game: Game) -> Result<(), rusqlite::Error> { let update_query = Query::update() .table("games") - .values([("start_time", game.start_time.into()), ("end_time", game.end_time.into())]) + .values([ + ("start_time", game.start_time.into()), + ("end_time", game.end_time.into()), + ]) .and_where(Expr::col("code").eq(game.code)) .to_owned(); - let mut update_stmt = conn.prepare( - &update_query.to_string(SqliteQueryBuilder) - )?; - + let mut update_stmt = conn.prepare(&update_query.to_string(SqliteQueryBuilder))?; + let result = update_stmt.query([]); match result { Ok(_) => Ok(()), - Err(error) => Err(error) + Err(error) => Err(error), } } diff --git a/src/main.rs b/src/main.rs index 542649f..9646e1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -226,7 +226,7 @@ async fn main() -> std::io::Result<()> { games: state.clone(), } .start(); - //sync_scores(actor_addr.clone()).await; + sync_scores(actor_addr.clone()).await; HttpServer::new(move || { App::new() .app_data(web::Data::new(pool.clone())) -- 2.49.0 From 8b0bd694fa2beed696ef596c5cbaa482671b726b Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Sat, 23 May 2026 21:27:02 -0700 Subject: [PATCH 4/8] Register update endpoint, use new form type, add error handling --- src/db.rs | 22 ++++++++++++++++------ src/main.rs | 27 ++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/db.rs b/src/db.rs index 0750fbf..865edf3 100644 --- a/src/db.rs +++ b/src/db.rs @@ -55,12 +55,17 @@ pub async fn teams(pool: &Pool) -> Result, Error> { .map_err(error::ErrorInternalServerError) } -pub async fn update_game(pool: &Pool, game: Game) -> Result<(), Error> { +pub async fn update_game( + pool: &Pool, + code: String, + start_time: String, + end_time: String, +) -> Result<(), Error> { let pool = pool.clone(); let conn = web::block(move || pool.get()) .await? .map_err(error::ErrorInternalServerError)?; - web::block(move || update_game_sqlite(conn, game)) + web::block(move || update_game_sqlite(conn, code, start_time, end_time)) .await? .map_err(error::ErrorInternalServerError) } @@ -83,14 +88,19 @@ fn get_all_games(conn: Connection, all_teams: HashMap) -> GamesRes .and_then(Iterator::collect) } -fn update_game_sqlite(conn: Connection, game: Game) -> Result<(), rusqlite::Error> { +fn update_game_sqlite( + conn: Connection, + code: String, + start_time: String, + end_time: String, +) -> Result<(), rusqlite::Error> { let update_query = Query::update() .table("games") .values([ - ("start_time", game.start_time.into()), - ("end_time", game.end_time.into()), + ("start_time", start_time.into()), + ("end_time", end_time.into()), ]) - .and_where(Expr::col("code").eq(game.code)) + .and_where(Expr::col("code").eq(code)) .to_owned(); let mut update_stmt = conn.prepare(&update_query.to_string(SqliteQueryBuilder))?; diff --git a/src/main.rs b/src/main.rs index 9646e1d..79cf671 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,6 +67,13 @@ struct QueryForm { query: String, } +#[derive(Deserialize, Debug)] +struct UpdateGameForm { + code: String, + start_time: String, + end_time: String, +} + impl Actor for GamesActor { type Context = actix::Context; } @@ -193,11 +200,20 @@ async fn list_of_games(games: web::Data>>>) -> impl Responde .body(games_json) } -#[post("/admin/game/{game_code}")] -async fn update_game(pool: web::Data, form: web::Form) -> impl Responder { - db::update_game(&pool, form.into_inner()).await.unwrap(); - - HttpResponse::Ok() +#[post("/admin/game/update")] +async fn update_game(pool: web::Data, form: web::Form) -> impl Responder { + println!("{form:?}"); + match db::update_game( + &pool, + form.code.clone(), + form.start_time.clone(), + form.end_time.clone(), + ) + .await + { + Ok(_) => HttpResponse::Ok().body("{}"), + Err(err) => HttpResponse::InternalServerError().body(format!("{err:?}")), + } } #[post("/admin/query")] @@ -239,6 +255,7 @@ async fn main() -> std::io::Result<()> { .service(admin_query) .service(list_of_games) .service(get_territories) + .service(update_game) }) .bind(("0.0.0.0", 8080))? .run() -- 2.49.0 From d240cc49e4c2d120e41ebf60bfb99e8bd64a266b Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Sat, 23 May 2026 22:02:39 -0700 Subject: [PATCH 5/8] Fix setup_db.sh --- db/setup_db.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/setup_db.sh b/db/setup_db.sh index 2806ba1..439cc18 100755 --- a/db/setup_db.sh +++ b/db/setup_db.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash cd $(dirname "$0") db_file='../storage/mapbattle.db' -sqlite3 "$dbfile" < db.sql -sqlite3 -csv "$dbfile" ".import init_games.csv games" -sqlite3 -csv "$dbfile" ".import init_teams.csv teams" +sqlite3 "$db_file" < db.sql +sqlite3 -csv "$db_file" ".import init_games.csv games" +sqlite3 -csv "$db_file" ".import init_teams.csv teams" -- 2.49.0 From 3472158fac754c28e5c4189857eda0fb3f451500 Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Sat, 23 May 2026 22:03:33 -0700 Subject: [PATCH 6/8] Grab games from database instead of memory --- src/main.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 79cf671..c2275ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -192,12 +192,17 @@ async fn admin() -> impl Responder { } #[get("/admin/games")] -async fn list_of_games(games: web::Data>>>) -> impl Responder { - let games = games.lock().await; - let games_json = serde_json::to_string(&*games).unwrap(); - HttpResponse::Ok() - .content_type("application/json") - .body(games_json) +async fn list_of_games(pool: web::Data) -> impl Responder { + let games_result = db::games(&pool).await; + match games_result { + Ok(games) => { + let games_json = serde_json::to_string(&*games).unwrap(); + HttpResponse::Ok() + .content_type("application/json") + .body(games_json) + }, + Err(err) => HttpResponse::InternalServerError().body(format!("{err}")) + } } #[post("/admin/game/update")] -- 2.49.0 From 203e880cf0381295079298582215d16c2fe5f059 Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Sat, 23 May 2026 22:14:41 -0700 Subject: [PATCH 7/8] Format. --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index c2275ac..25b9aec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -200,8 +200,8 @@ async fn list_of_games(pool: web::Data) -> impl Responder { HttpResponse::Ok() .content_type("application/json") .body(games_json) - }, - Err(err) => HttpResponse::InternalServerError().body(format!("{err}")) + } + Err(err) => HttpResponse::InternalServerError().body(format!("{err}")), } } -- 2.49.0 From 62275d8582fd4ad702bfc1302b4b20e7cef00e2b Mon Sep 17 00:00:00 2001 From: Zigzagill Date: Sat, 23 May 2026 22:15:29 -0700 Subject: [PATCH 8/8] Remove debug println --- src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 25b9aec..d9ee9fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -207,7 +207,6 @@ async fn list_of_games(pool: web::Data) -> impl Responder { #[post("/admin/game/update")] async fn update_game(pool: web::Data, form: web::Form) -> impl Responder { - println!("{form:?}"); match db::update_game( &pool, form.code.clone(), -- 2.49.0