diff --git a/.gitignore b/.gitignore index 0af23b5..ecdc5b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /target -config.toml \ No newline at end of file +config.toml + +.env \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8cf9a0d..93c78fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -403,6 +403,8 @@ dependencies = [ "actix-web", "chrono", "ctrlc", + "dotenv", + "dotenv_codegen", "env_logger", "schemars", "serde", @@ -592,6 +594,35 @@ dependencies = [ "winapi", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dotenv_codegen" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56966279c10e4f8ee8c22123a15ed74e7c8150b658b26c619c53f4a56eb4a8aa" +dependencies = [ + "dotenv_codegen_implementation", + "proc-macro-hack", +] + +[[package]] +name = "dotenv_codegen_implementation" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e737a3522cd45f6adc19b644ce43ef53e1e9045f2d2de425c1f468abd4cf33" +dependencies = [ + "dotenv", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -1404,6 +1435,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.66" diff --git a/Cargo.toml b/Cargo.toml index f0df546..4d071ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,8 @@ edition = "2021" actix-web = "4.3.1" chrono = "0.4.26" ctrlc = "3.4.0" +dotenv = "0.15.0" +dotenv_codegen = "0.15.0" env_logger = "0.10.0" schemars = "0.8.10" serde = { version = "1.0.185", features = ["derive"] } diff --git a/src/db/mod.rs b/src/db/mod.rs index e906b9e..7c8e632 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -2,20 +2,4 @@ use std::error::Error; use sqlx::{Postgres, postgres::PgConnectOptions, PgPool, Pool}; -use crate::{PostgresConfig}; - -pub(crate) mod schemas; - -pub(crate) async fn connect_postgres(config: PostgresConfig) -> Result, Box> { - - let connection_settings = PgConnectOptions::new() - .host(&config.host) - .port(config.port) - .username(&config.user) - .password(&config.password) - .database(&config.db); - - let pool = PgPool::connect_with(connection_settings).await?; - - return Ok(pool); -} \ No newline at end of file +pub(crate) mod schemas; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a4e3796..bc60d64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,11 @@ -use std::{error::Error, fs, net::Ipv4Addr, net::Ipv6Addr, thread, time::Duration, sync::{Mutex, Arc, atomic::{AtomicBool, Ordering}}}; +#[macro_use] +extern crate dotenv_codegen; +extern crate dotenv; + +use dotenv::dotenv; +use tokio::time::sleep; + +use std::{env, error::Error, fs, net::Ipv4Addr, net::Ipv6Addr, thread, time::Duration, sync::{Mutex, Arc, atomic::{AtomicBool, Ordering}}}; use chrono::Local; @@ -8,8 +15,6 @@ use sqlx::{PgPool, Pool, Postgres, Connection}; use utoipa::OpenApi; use utoipa_swagger_ui::{Config, SwaggerUi, Url}; -use crate::db::connect_postgres; - mod db; mod v2; mod v3; @@ -34,19 +39,9 @@ macro_rules! api_base_3 { #[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct ConfigToml { - database: PostgresConfig, auth: AuthenticationTokens, } -#[derive(Serialize, Deserialize, Debug, Clone)] -pub(crate) struct PostgresConfig { - host: String, - port: u16, - user: String, - password: String, - db: String, -} - #[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct AuthenticationTokens { moderator: String, @@ -71,21 +66,13 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc, shutdown: Ar }; match conn.ping().await { - Ok(_) => {eprintln!("Pinged DB Server at {}", Local::now().format("%H:%M:%S"))}, - Err(_) => todo!(), + Ok(_) => {println!("Pinged DB Server at {}", Local::now().format("%H:%M:%S"))}, + Err(_) => {println!("Error pinging Server"); break;}, }; let passed = (Local::now() - start).to_std().expect(&format!("Unable to get Time Difference for '{}' and '{}'", start, Local::now())); - thread::sleep(Duration::from_secs(5) - passed); - if shutdown.load(Ordering::Relaxed) { - break; - } - thread::sleep(Duration::from_secs(10) - passed); - if shutdown.load(Ordering::Relaxed) { - break; - } - thread::sleep(Duration::from_secs(15) - passed); + sleep(Duration::from_secs(15) - passed).await; } is_alive.store(false, Ordering::Relaxed); } @@ -93,6 +80,7 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc, shutdown: Ar #[actix_web::main] async fn main() -> Result<()> { env_logger::init(); + dotenv().ok(); let shutdown: Arc = Arc::new(AtomicBool::new(false)); @@ -107,6 +95,8 @@ async fn main() -> Result<()> { let config: ConfigToml = toml::from_str(&toml_str).expect("Failed to parse config.toml"); + println!("DATABASE_URL: {}", env::var("DATABASE_URL").unwrap()); // DBEUG + #[derive(OpenApi)] #[openapi( paths( @@ -134,12 +124,24 @@ async fn main() -> Result<()> { #[openapi( paths( v3::full_view_data, + v3::auth, + v3::list_games, + v3::get_game_data, + v3::create_game, + v3::delete_game ), components(schemas( + v3::schemas::AuthParamsOptional, + v3::schemas::AuthParams, + v3::schemas::AuthReturn, + v3::schemas::GetGameParam, + v3::schemas::PostGameParams, + v3::schemas::DeleteGameParam, v3::schemas::FullViewData, v3::schemas::Ethic, v3::schemas::EmpireEthic, v3::schemas::ChellarisGame, + v3::schemas::ChellarisGameLite, v3::schemas::Species, v3::schemas::ChellarisGameGroup, v3::schemas::Portrait, @@ -157,7 +159,7 @@ async fn main() -> Result<()> { loop { let db_auth_tokens = config.auth.clone(); - let pool = connect_postgres(config.database.clone()).await.unwrap(); + let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap(); let pool_copy = pool.clone(); let swagger_config = Config::new(openapi_urls.clone()); @@ -182,6 +184,11 @@ async fn main() -> Result<()> { .service(v2::portraits) // API v3 Endpoints .service(v3::full_view_data) + .service(v3::auth) + .service(v3::list_games) + .service(v3::get_game_data) + .service(v3::create_game) + .service(v3::delete_game) // Swagger UI .service( SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}")) @@ -202,7 +209,7 @@ async fn main() -> Result<()> { .run(); let server_thread = tokio::spawn(async { - eprintln!("Awaiting server"); + println!("Awaiting server"); let _ = server.await; println!("Stopped awaiting server"); }); diff --git a/src/v2/mod.rs b/src/v2/mod.rs index 6145383..80c9353 100644 --- a/src/v2/mod.rs +++ b/src/v2/mod.rs @@ -13,7 +13,7 @@ pub(crate) mod schemas; ("api_key" = []) ), )] -#[get("/empire_ethics")] +#[get("/api/v2/empire_ethics")] pub(crate) async fn empire_ethics( data: web::Data ) -> impl Responder { @@ -51,7 +51,7 @@ pub(crate) async fn empire_ethics( ("api_key" = []) ), )] -#[get("/empires")] +#[get("/api/v2/empires")] pub(crate) async fn empires( data: web::Data, params: web::Query @@ -98,7 +98,7 @@ pub(crate) async fn empires( ("api_key" = []) ), )] -#[get("/ethics")] +#[get("/api/v2/ethics")] pub(crate) async fn ethics( data: web::Data ) -> impl Responder { @@ -132,7 +132,7 @@ pub(crate) async fn ethics( ("api_key" = []) ), )] -#[get("/game_groups")] +#[get("/api/v2/game_groups")] pub(crate) async fn game_groups( data: web::Data ) -> impl Responder { @@ -166,7 +166,7 @@ pub(crate) async fn game_groups( ("api_key" = []) ), )] -#[get("/games")] +#[get("/api/v2/games")] pub(crate) async fn games( data: web::Data ) -> impl Responder { @@ -199,7 +199,7 @@ pub(crate) async fn games( ("api_key" = []) ), )] -#[get("/portrait_groups")] +#[get("/api/v2/portrait_groups")] pub(crate) async fn portrait_groups( data: web::Data ) -> impl Responder { @@ -232,7 +232,7 @@ pub(crate) async fn portrait_groups( ("api_key" = []) ), )] -#[get("/portraits")] +#[get("/api/v2/portraits")] pub(crate) async fn portraits( data: web::Data ) -> impl Responder { diff --git a/src/v3/mod.rs b/src/v3/mod.rs index 39f107e..20b41e5 100644 --- a/src/v3/mod.rs +++ b/src/v3/mod.rs @@ -1,11 +1,66 @@ -use std::{vec, collections::HashMap}; +use std::{collections::HashMap, vec}; -use actix_web::{web::{self, Json}, Responder, get}; +use actix_web::{ + delete, get, post, put, + web::{self, Json}, + HttpResponse, Responder, +}; -use crate::{AppState, db}; +use crate::{db, AppState}; pub(crate) mod schemas; +fn verify_auth(token: &str, data: &AppState) -> schemas::AuthReturn { + let mut auth_return = schemas::AuthReturn { + moderator: false, + admin: false, + }; + + if token == data.auth_tokens.admin { + auth_return.admin = true; + auth_return.moderator = true; + } else if token == data.auth_tokens.moderator { + auth_return.moderator = true; + } + + return auth_return; +} + +#[utoipa::path( + params( + schemas::AuthParams + ), + responses( + (status = 200, description = "OK", body = AuthReturn), + ), + security( + ("api_key" = []) + ), +)] +#[get("/api/v3/auth")] +pub(crate) async fn auth( + data: web::Data, + params: web::Query, +) -> impl Responder { + let params: schemas::AuthParamsOptional = params.into_inner(); + + let mut auth_return = schemas::AuthReturn { + moderator: false, + admin: false, + }; + + if let Some(auth_token) = params.token.clone() { + if auth_token == data.auth_tokens.admin { + auth_return.admin = true; + auth_return.moderator = true; + } else if auth_token == data.auth_tokens.moderator { + auth_return.moderator = true; + } + } + + Json(auth_return) +} + #[utoipa::path( params( @@ -17,56 +72,53 @@ pub(crate) mod schemas; ("api_key" = []) ), )] -#[get("/full_view_data")] -pub(crate) async fn full_view_data( - data: web::Data -) -> impl Responder { +#[get("/api/v3/full_view_data")] +pub(crate) async fn full_view_data(data: web::Data) -> impl Responder { let start = chrono::Local::now(); // DEBUG // SQL Queries // TODO: Optimize by utilizing some SQL magic, for now this has to do - let db_games: Vec = sqlx::query_as( - "SELECT * FROM public.games ORDER BY id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_games: Vec = sqlx::query_as("SELECT * FROM public.games ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); - let db_groups: Vec = sqlx::query_as( - "SELECT * FROM public.game_groups ORDER BY id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_groups: Vec = + sqlx::query_as("SELECT * FROM public.game_groups ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); - let db_empires: Vec = sqlx::query_as( - "SELECT * FROM public.empires ORDER BY id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_empires: Vec = + sqlx::query_as("SELECT * FROM public.empires ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); - let db_ethics: Vec = sqlx::query_as( - "SELECT * FROM public.ethics ORDER BY id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_ethics: Vec = + sqlx::query_as("SELECT * FROM public.ethics ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); - let db_empire_ethics: Vec = sqlx::query_as( - "SELECT * FROM public.empire_ethics ORDER BY empires_id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_empire_ethics: Vec = + sqlx::query_as("SELECT * FROM public.empire_ethics ORDER BY empires_id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); - let db_portrait_groups: Vec = sqlx::query_as( - "SELECT * FROM public.portrait_groups ORDER BY id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_portrait_groups: Vec = + sqlx::query_as("SELECT * FROM public.portrait_groups ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); - let db_portraits: Vec = sqlx::query_as( - "SELECT * FROM public.portraits ORDER BY id", - ) - .fetch_all(&data.db) - .await.expect("Error Fetching Data from DB"); + let db_portraits: Vec = + sqlx::query_as("SELECT * FROM public.portraits ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); let mut parsed_data: schemas::FullViewData = schemas::FullViewData { games: HashMap::new(), @@ -83,7 +135,11 @@ pub(crate) async fn full_view_data( portraits: HashMap::new(), }; - parsed_data.species.entry(species.id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + parsed_data + .species + .entry(species.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); db_portraits.iter().for_each(|portrait| { @@ -93,7 +149,14 @@ pub(crate) async fn full_view_data( lores: portrait.lores.clone(), }; - parsed_data.species.get_mut(&portrait.group_id).unwrap().portraits.entry(portrait.id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + parsed_data + .species + .get_mut(&portrait.group_id) + .unwrap() + .portraits + .entry(portrait.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); // Games Vector and Children @@ -105,7 +168,11 @@ pub(crate) async fn full_view_data( groups: HashMap::new(), }; - parsed_data.games.entry(game.id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + parsed_data + .games + .entry(game.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); db_groups.iter().for_each(|group| { @@ -114,14 +181,21 @@ pub(crate) async fn full_view_data( name: group.name.clone(), }; - parsed_data.games.get_mut(&group.game_id).unwrap().groups.entry(group.id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + parsed_data + .games + .get_mut(&group.game_id) + .unwrap() + .groups + .entry(group.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); db_empires.iter().for_each(|empire| { let new_data = schemas::ChellarisEmpire { id: empire.id, gestalt: empire.gestalt.unwrap_or(false), - machine: false, // TODO overwrite this later on with correct data + machine: false, group: empire.group_id, empire_portrait: empire.empire_portrait_id, empire_portrait_group: empire.empire_portrait_group_id, @@ -129,7 +203,14 @@ pub(crate) async fn full_view_data( ethics: HashMap::new(), }; - parsed_data.games.get_mut(&empire.group_game_id).unwrap().empires.entry(empire.id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + parsed_data + .games + .get_mut(&empire.group_game_id) + .unwrap() + .empires + .entry(empire.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); // Ethics Vector @@ -140,26 +221,259 @@ pub(crate) async fn full_view_data( machine: ethic.machine_ethic, }; - parsed_data.ethics.entry(ethic.id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + parsed_data + .ethics + .entry(ethic.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); - println!("{:#?}", parsed_data.ethics); // DEBUG - db_empire_ethics.iter().for_each(|empire_ethic| { let game_id = empire_ethic.empires_group_game_id; let id = empire_ethic.empires_id; let new_data = schemas::EmpireEthic { id: empire_ethic.ethics_id, - displayName: parsed_data.ethics[&empire_ethic.ethics_id].displayName.clone(), + displayName: parsed_data.ethics[&empire_ethic.ethics_id] + .displayName + .clone(), machine: parsed_data.ethics[&empire_ethic.ethics_id].machine, fanatic: empire_ethic.ethics_fanatic, }; - parsed_data.games.get_mut(&game_id).unwrap().empires.get_mut(&id).unwrap().ethics.entry(empire_ethic.ethics_id).and_modify(|d| *d = new_data.clone()).or_insert(new_data); + if new_data.machine { + parsed_data + .games + .get_mut(&game_id) + .unwrap() + .empires + .get_mut(&id) + .unwrap() + .machine = true; + } + + parsed_data + .games + .get_mut(&game_id) + .unwrap() + .empires + .get_mut(&id) + .unwrap() + .ethics + .entry(empire_ethic.ethics_id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); }); println!("{:?} ms", (chrono::Local::now() - start).to_std().unwrap()); // DEBUG - + Json(parsed_data) } + +// Data Fetching Endpoints for Admin/Moderator Menu + +#[utoipa::path( + params(), + responses( + (status = 200, description = "OK", body = HashMap), + ), + security( + ("api_key" = []) + ), +)] +#[get("/api/v3/list_games")] +pub(crate) async fn list_games(data: web::Data) -> impl Responder { + // SQL Queries + // TODO: Optimize by utilizing some SQL magic, for now this has to do + + let db_games: Vec = sqlx::query_as("SELECT * FROM public.games ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); + + let mut parsed_data: HashMap = HashMap::new(); + + // Data processing + // Games Vector + db_games.iter().for_each(|game| { + let new_data = schemas::ChellarisGameLite { + id: game.id, + name: game.name.clone(), + }; + + parsed_data + .entry(game.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); + }); + + Json(parsed_data) +} + +#[utoipa::path( + params( + schemas::GetGameParam + ), + responses( + (status = 200, description = "OK", body = HashMap), + ), + security( + ("api_key" = []) + ), +)] +#[get("/api/v3/game")] +pub(crate) async fn get_game_data( + data: web::Data, + params: web::Query, +) -> impl Responder { + let params: schemas::GetGameParam = params.into_inner(); + + // SQL Queries + // TODO: Optimize by utilizing some SQL magic, for now this has to do + let db_games: Vec; + if let Some(game_id) = params.game_id { + db_games = match sqlx::query_as!( + db::schemas::Game, + "SELECT * FROM public.games WHERE id = $1 ORDER BY id", + game_id as i32 + ) + .fetch_one(&data.db) + .await + { + Ok(data) => vec![data], + Err(_) => vec![], + }; + } else { + db_games = sqlx::query_as("SELECT * FROM public.games ORDER BY id") + .fetch_all(&data.db) + .await + .expect("Error Fetching Data from DB"); + } + + let mut parsed_data: HashMap = HashMap::new(); + + // Data processing + // Games Vector + db_games.iter().for_each(|game| { + let new_data = schemas::ChellarisGameLite { + id: game.id, + name: game.name.clone(), + }; + + parsed_data + .entry(game.id) + .and_modify(|d| *d = new_data.clone()) + .or_insert(new_data); + }); + + Json(parsed_data) +} + +#[utoipa::path( + request_body = PostGameParams, + responses( + (status = 200, description = "OK", body = ChellarisGameLite), + (status = 422, description = "Missing Game Name"), + (status = 401, description = "Auth Token Invalid"), + ), + security( + ("api_key" = []) + ), +)] +#[post("/api/v3/game")] +pub(crate) async fn create_game( + data: web::Data, + params: web::Json, +) -> impl Responder { + let params = params.into_inner(); + + let user_auth: schemas::AuthReturn = verify_auth(¶ms.auth.token, &data); + + // SQL Queries + // TODO: Optimize by utilizing some SQL magic, for now this has to do + if user_auth.admin || user_auth.moderator { + if params.game_name != "" { + let db_game: db::schemas::Game; + + db_game = match sqlx::query_as!( + db::schemas::Game, + "INSERT INTO public.games(name) VALUES ($1) RETURNING * ", + params.game_name + ) + .fetch_one(&data.db) + .await + { + Ok(data) => data, + Err(_) => return HttpResponse::UnprocessableEntity().finish(), + }; + + let parsed_game: schemas::ChellarisGameLite = schemas::ChellarisGameLite { + id: db_game.id, + name: db_game.name, + }; + + return HttpResponse::Ok().json(parsed_game); + } else { + return HttpResponse::UnprocessableEntity().finish(); + } + } else { + return HttpResponse::Unauthorized().finish(); + } +} + +#[utoipa::path( + params( + schemas::DeleteGameParam, + ), + request_body = AuthParams, + responses( + (status = 200, description = "OK"), + (status = 422, description = "Missing Game ID"), + (status = 401, description = "Auth Token Invalid"), + ), + security( + ("api_key" = []) + ), +)] +#[delete("/api/v3/game")] +pub(crate) async fn delete_game( + data: web::Data, + auth_params: web::Json, + param: web::Query, +) -> impl Responder { + let auth_params = auth_params.into_inner(); + let param = param.into_inner(); + + let user_auth: schemas::AuthReturn = verify_auth(&auth_params.token, &data); + + // SQL Queries + // TODO: Optimize by utilizing some SQL magic, for now this has to do + if user_auth.admin || user_auth.moderator { + match sqlx::query!( + "DELETE FROM public.games WHERE id = $1", + param.game_id as i32 + ) + .execute(&data.db) + .await + { + Ok(_) => {}, + Err(_) => return HttpResponse::UnprocessableEntity().finish(), + }; + + return HttpResponse::Ok().into(); + } else { + return HttpResponse::Unauthorized().finish(); + } +} + +// Data Manipulation Endpoints + +// Moderator & Admin +// Add/Update/Remove Empire +// Add/Update/Remove Group +// Add/Update/Remove Game + +// Admin +// Add/Update/Remove Portrait +// Add/Update/Remove Species +// Add/Update/Remove Ethics diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs index 6b3fe9b..9dcb69b 100644 --- a/src/v3/schemas.rs +++ b/src/v3/schemas.rs @@ -4,10 +4,43 @@ use serde::{Serialize, Deserialize}; use utoipa::{ToSchema, IntoParams}; #[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] -pub struct AuthParams { +pub struct AuthParamsOptional { + #[schema(example = "1357")] pub token: Option, } +#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] +pub struct AuthParams { + #[schema(example = "1357")] + pub token: String, +} + +#[derive(Serialize, Deserialize, ToSchema, Debug)] +pub struct AuthReturn { + #[schema(example = false)] + pub moderator: bool, + #[schema(example = false)] + pub admin: bool, +} + +#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] +pub struct GetGameParam { + pub game_id: Option, +} + +#[derive(Serialize, Deserialize, ToSchema, Debug)] +pub struct PostGameParams { + pub auth: AuthParams, + #[schema(example = "Game XY")] + pub game_name: String, +} + +#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] +pub struct DeleteGameParam { + #[schema(example = 0)] + pub game_id: usize, +} + #[derive(Serialize, ToSchema, Debug, Clone)] pub struct FullViewData { pub games: HashMap, @@ -23,6 +56,12 @@ pub struct ChellarisGame { pub empires: HashMap, } +#[derive(Serialize, ToSchema, Debug, Clone)] +pub struct ChellarisGameLite { + pub id: i32, + pub name: String, +} + #[derive(Serialize, ToSchema, Debug, Clone)] pub struct ChellarisGameGroup { pub id: i32, @@ -68,4 +107,5 @@ pub struct Portrait { pub id: i32, pub hires: String, pub lores: Option, -} \ No newline at end of file +} +