Game & Group Put + Delete Endpoints

This commit is contained in:
Neshura 2023-09-02 20:23:34 +02:00
parent 8fd4321944
commit eb18526f51
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
3 changed files with 442 additions and 119 deletions

View file

@ -12,7 +12,7 @@ use chrono::Local;
use actix_web::{middleware::Logger, web, App, HttpServer, Result}; use actix_web::{middleware::Logger, web, App, HttpServer, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{PgPool, Pool, Postgres, Connection}; use sqlx::{PgPool, Pool, Postgres, Connection};
use utoipa::OpenApi; use utoipa::{OpenApi, openapi::security::{SecurityScheme, ApiKey, ApiKeyValue}, Modify};
use utoipa_swagger_ui::{Config, SwaggerUi, Url}; use utoipa_swagger_ui::{Config, SwaggerUi, Url};
mod db; mod db;
@ -97,6 +97,18 @@ async fn main() -> Result<()> {
println!("DATABASE_URL: {}", env::var("DATABASE_URL").unwrap()); // DBEUG println!("DATABASE_URL: {}", env::var("DATABASE_URL").unwrap()); // DBEUG
struct ApiSecurity;
impl Modify for ApiSecurity {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
let components = openapi.components.as_mut().unwrap(); // we can unwrap safely since there already is components registered.
components.add_security_scheme(
"api_key",
SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("x-api-key"))),
);
}
}
#[derive(OpenApi)] #[derive(OpenApi)]
#[openapi( #[openapi(
paths( paths(
@ -128,25 +140,35 @@ async fn main() -> Result<()> {
v3::list_games, v3::list_games,
v3::get_game_data, v3::get_game_data,
v3::create_game, v3::create_game,
v3::delete_game v3::edit_game,
v3::delete_game,
v3::create_group,
v3::edit_group,
v3::delete_group
), ),
components(schemas( components(schemas(
v3::schemas::AuthParamsOptional,
v3::schemas::AuthParams,
v3::schemas::AuthReturn, v3::schemas::AuthReturn,
v3::schemas::GetGameParam, v3::schemas::GetGameParam,
v3::schemas::PostGameParams, v3::schemas::PostGameParams,
v3::schemas::UpdateGameParams,
v3::schemas::DeleteGameParam, v3::schemas::DeleteGameParam,
v3::schemas::PostGroupParams,
v3::schemas::UpdateGroupParams,
v3::schemas::DeleteGroupParams,
v3::schemas::FullViewData, v3::schemas::FullViewData,
v3::schemas::Ethic, v3::schemas::Ethic,
v3::schemas::EmpireEthic, v3::schemas::EmpireEthic,
v3::schemas::ChellarisGameLegacy,
v3::schemas::ChellarisGameFlat,
v3::schemas::ChellarisGame, v3::schemas::ChellarisGame,
v3::schemas::ChellarisGameLite,
v3::schemas::Species, v3::schemas::Species,
v3::schemas::ChellarisGameGroup, v3::schemas::ChellarisGameGroupLegacy,
v3::schemas::ChellarisGroupFlat,
v3::schemas::Portrait, v3::schemas::Portrait,
v3::schemas::ChellarisEmpire v3::schemas::ChellarisEmpire,
)) v3::schemas::ChellarisEmpireFlat
)),
modifiers(&ApiSecurity)
)] )]
struct ApiDocV3; struct ApiDocV3;
@ -188,7 +210,11 @@ async fn main() -> Result<()> {
.service(v3::list_games) .service(v3::list_games)
.service(v3::get_game_data) .service(v3::get_game_data)
.service(v3::create_game) .service(v3::create_game)
.service(v3::edit_game)
.service(v3::delete_game) .service(v3::delete_game)
.service(v3::create_group)
.service(v3::edit_group)
.service(v3::delete_group)
// Swagger UI // Swagger UI
.service( .service(
SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}")) SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
@ -226,7 +252,7 @@ async fn main() -> Result<()> {
while is_alive.load(Ordering::Relaxed) { while is_alive.load(Ordering::Relaxed) {
let thread = tokio::spawn(async { let thread = tokio::spawn(async {
thread::sleep(Duration::from_millis(100)); sleep(Duration::from_millis(100));
}); });
let _ = thread.await; let _ = thread.await;

View file

@ -3,33 +3,36 @@ use std::{collections::HashMap, vec};
use actix_web::{ use actix_web::{
delete, get, post, put, delete, get, post, put,
web::{self, Json}, web::{self, Json},
HttpResponse, Responder, HttpResponse, Responder, HttpRequest,
}; };
use crate::{db, AppState}; use crate::{db, AppState};
pub(crate) mod schemas; pub(crate) mod schemas;
fn verify_auth(token: &str, data: &AppState) -> schemas::AuthReturn { fn verify_auth(token: Option<&str>, data: &AppState) -> schemas::AuthReturn {
let mut auth_return = schemas::AuthReturn { let mut auth_return = schemas::AuthReturn {
moderator: false, moderator: false,
admin: false, admin: false,
}; };
if token == data.auth_tokens.admin { if let Some(token) = token {
auth_return.admin = true; if token == data.auth_tokens.admin {
auth_return.moderator = true; auth_return.admin = true;
} else if token == data.auth_tokens.moderator { auth_return.moderator = true;
auth_return.moderator = true; } else if token == data.auth_tokens.moderator {
auth_return.moderator = true;
}
} }
return auth_return; return auth_return;
} }
fn get_auth_header<'a>(req: &'a HttpRequest) -> Option<&'a str> {
req.headers().get("x-api-key")?.to_str().ok()
}
#[utoipa::path( #[utoipa::path(
params(
schemas::AuthParams
),
responses( responses(
(status = 200, description = "OK", body = AuthReturn), (status = 200, description = "OK", body = AuthReturn),
), ),
@ -40,31 +43,16 @@ fn verify_auth(token: &str, data: &AppState) -> schemas::AuthReturn {
#[get("/api/v3/auth")] #[get("/api/v3/auth")]
pub(crate) async fn auth( pub(crate) async fn auth(
data: web::Data<AppState>, data: web::Data<AppState>,
params: web::Query<schemas::AuthParamsOptional>, req: HttpRequest,
) -> impl Responder { ) -> impl Responder {
let params: schemas::AuthParamsOptional = params.into_inner(); let auth_token = get_auth_header(&req);
let mut auth_return = schemas::AuthReturn { let auth_return = verify_auth(auth_token, &data);
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) Json(auth_return)
} }
#[utoipa::path( #[utoipa::path(
params(
),
responses( responses(
(status = 200, description = "OK", body = FullViewData), (status = 200, description = "OK", body = FullViewData),
), ),
@ -74,8 +62,6 @@ pub(crate) async fn auth(
)] )]
#[get("/api/v3/full_view_data")] #[get("/api/v3/full_view_data")]
pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder { pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder {
let start = chrono::Local::now(); // DEBUG
// SQL Queries // SQL Queries
// TODO: Optimize by utilizing some SQL magic, for now this has to do // TODO: Optimize by utilizing some SQL magic, for now this has to do
@ -146,7 +132,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
let new_data = schemas::Portrait { let new_data = schemas::Portrait {
id: portrait.id, id: portrait.id,
hires: portrait.hires.clone(), hires: portrait.hires.clone(),
lores: portrait.lores.clone(), lores: Some(portrait.lores.clone()),
}; };
parsed_data parsed_data
@ -161,7 +147,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
// Games Vector and Children // Games Vector and Children
db_games.iter().for_each(|game| { db_games.iter().for_each(|game| {
let new_data = schemas::ChellarisGame { let new_data = schemas::ChellarisGameLegacy {
id: game.id, id: game.id,
name: game.name.clone(), name: game.name.clone(),
empires: HashMap::new(), empires: HashMap::new(),
@ -176,7 +162,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
}); });
db_groups.iter().for_each(|group| { db_groups.iter().for_each(|group| {
let new_data = schemas::ChellarisGameGroup { let new_data = schemas::ChellarisGameGroupLegacy {
id: group.id, id: group.id,
name: group.name.clone(), name: group.name.clone(),
}; };
@ -194,12 +180,12 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
db_empires.iter().for_each(|empire| { db_empires.iter().for_each(|empire| {
let new_data = schemas::ChellarisEmpire { let new_data = schemas::ChellarisEmpire {
id: empire.id, id: empire.id,
gestalt: empire.gestalt.unwrap_or(false), gestalt: empire.gestalt,
machine: false, machine: false,
group: empire.group_id, group: empire.group_id,
empire_portrait: empire.empire_portrait_id, empire_portrait: empire.empire_portrait_id,
empire_portrait_group: empire.empire_portrait_group_id, empire_portrait_group: empire.empire_portrait_group_id,
discord_user: empire.discord_user.clone(), discord_user: None,
ethics: HashMap::new(), ethics: HashMap::new(),
}; };
@ -265,13 +251,13 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
.or_insert(new_data); .or_insert(new_data);
}); });
println!("{:?} ms", (chrono::Local::now() - start).to_std().unwrap()); // DEBUG
Json(parsed_data) Json(parsed_data)
} }
// Data Fetching Endpoints for Admin/Moderator Menu // Data Fetching Endpoints for Admin/Moderator Menu
// Game Endpoints
#[utoipa::path( #[utoipa::path(
params(), params(),
responses( responses(
@ -281,7 +267,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
("api_key" = []) ("api_key" = [])
), ),
)] )]
#[get("/api/v3/list_games")] #[get("/api/v3/games")]
pub(crate) async fn list_games(data: web::Data<AppState>) -> impl Responder { pub(crate) async fn list_games(data: web::Data<AppState>) -> impl Responder {
// SQL Queries // SQL Queries
// TODO: Optimize by utilizing some SQL magic, for now this has to do // TODO: Optimize by utilizing some SQL magic, for now this has to do
@ -291,12 +277,12 @@ pub(crate) async fn list_games(data: web::Data<AppState>) -> impl Responder {
.await .await
.expect("Error Fetching Data from DB"); .expect("Error Fetching Data from DB");
let mut parsed_data: HashMap<i32, schemas::ChellarisGameLite> = HashMap::new(); let mut parsed_data: HashMap<i32, schemas::ChellarisGameFlat> = HashMap::new();
// Data processing // Data processing
// Games Vector // Games Vector
db_games.iter().for_each(|game| { db_games.iter().for_each(|game| {
let new_data = schemas::ChellarisGameLite { let new_data = schemas::ChellarisGameFlat {
id: game.id, id: game.id,
name: game.name.clone(), name: game.name.clone(),
}; };
@ -315,7 +301,7 @@ pub(crate) async fn list_games(data: web::Data<AppState>) -> impl Responder {
schemas::GetGameParam schemas::GetGameParam
), ),
responses( responses(
(status = 200, description = "OK", body = HashMap<i32, ChellarisGameLite>), (status = 200, description = "OK", body = ChellarisGame),
), ),
security( security(
("api_key" = []) ("api_key" = [])
@ -324,49 +310,86 @@ pub(crate) async fn list_games(data: web::Data<AppState>) -> impl Responder {
#[get("/api/v3/game")] #[get("/api/v3/game")]
pub(crate) async fn get_game_data( pub(crate) async fn get_game_data(
data: web::Data<AppState>, data: web::Data<AppState>,
params: web::Query<schemas::GetGameParam>, path_param: web::Query<schemas::GetGameParam>,
req: HttpRequest,
) -> impl Responder { ) -> impl Responder {
let params: schemas::GetGameParam = params.into_inner(); let auth_token = get_auth_header(&req);
let param = path_param.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(auth_token.as_deref(), &data);
// SQL Queries // SQL Queries
// TODO: Optimize by utilizing some SQL magic, for now this has to do // TODO: Optimize by utilizing some SQL magic, for now this has to do
let db_games: Vec<db::schemas::Game>; let db_game: db::schemas::Game = match sqlx::query_as!(
if let Some(game_id) = params.game_id { db::schemas::Game,
db_games = match sqlx::query_as!( "SELECT * FROM public.games WHERE id = $1",
db::schemas::Game, param.game_id
"SELECT * FROM public.games WHERE id = $1 ORDER BY id", )
game_id as i32 .fetch_one(&data.db)
) .await
.fetch_one(&data.db) {
.await Ok(data) => data,
{ Err(_) => return HttpResponse::UnprocessableEntity().finish(),
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<i32, schemas::ChellarisGameLite> = HashMap::new(); let db_empires: Vec<db::schemas::Empire> = sqlx::query_as!(
db::schemas::Empire,
"SELECT * FROM public.empires WHERE group_game_id = $1",
param.game_id
)
.fetch_all(&data.db)
.await
.unwrap_or(vec![]);
// Data processing let db_groups: Vec<db::schemas::GameGroup> = sqlx::query_as!(
// Games Vector db::schemas::GameGroup,
db_games.iter().for_each(|game| { "SELECT * FROM public.game_groups WHERE game_id = $1",
let new_data = schemas::ChellarisGameLite { param.game_id
id: game.id, )
name: game.name.clone(), .fetch_all(&data.db)
.await
.unwrap_or(vec![]);
// Data Processing
let mut parsed_data: schemas::ChellarisGame = schemas::ChellarisGame {
id: db_game.id,
name: db_game.name,
empires: HashMap::new(),
groups: HashMap::new(),
};
db_empires.iter().for_each(|empire| {
let new_empire = schemas::ChellarisEmpireFlat {
id: empire.id,
group: empire.group_id,
name: if user_auth.moderator || user_auth.admin {empire.name.clone()} else {"[REDACTED]".to_string()},
discord_user: if user_auth.moderator || user_auth.admin {empire.discord_user.clone()} else {None},
gestalt: empire.gestalt,
empire_portrait: empire.empire_portrait_id,
empire_portrait_group: empire.empire_portrait_group_id,
}; };
parsed_data parsed_data
.entry(game.id) .empires
.and_modify(|d| *d = new_data.clone()) .entry(empire.id)
.or_insert(new_data); .and_modify(|d| *d = new_empire.clone())
.or_insert(new_empire);
}); });
Json(parsed_data) db_groups.iter().for_each(|group| {
let new_group = schemas::ChellarisGroupFlat {
id: group.id,
name: group.name.clone(),
};
parsed_data
.groups
.entry(group.id)
.and_modify(|d| *d = new_group.clone())
.or_insert(new_group);
});
return HttpResponse::Ok().json(parsed_data);
} }
#[utoipa::path( #[utoipa::path(
@ -384,10 +407,12 @@ pub(crate) async fn get_game_data(
pub(crate) async fn create_game( pub(crate) async fn create_game(
data: web::Data<AppState>, data: web::Data<AppState>,
params: web::Json<schemas::PostGameParams>, params: web::Json<schemas::PostGameParams>,
req: HttpRequest,
) -> impl Responder { ) -> impl Responder {
let auth_token = get_auth_header(&req);
let params = params.into_inner(); let params = params.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(&params.auth.token, &data); let user_auth: schemas::AuthReturn = verify_auth(auth_token.as_deref(), &data);
// SQL Queries // SQL Queries
// TODO: Optimize by utilizing some SQL magic, for now this has to do // TODO: Optimize by utilizing some SQL magic, for now this has to do
@ -407,7 +432,18 @@ pub(crate) async fn create_game(
Err(_) => return HttpResponse::UnprocessableEntity().finish(), Err(_) => return HttpResponse::UnprocessableEntity().finish(),
}; };
let parsed_game: schemas::ChellarisGameLite = schemas::ChellarisGameLite { match sqlx::query!(
"INSERT INTO public.game_groups(name, game_id) VALUES ($1, $2)",
"N/A", db_game.id
)
.execute(&data.db)
.await
{
Ok(_) => {},
Err(_) => return HttpResponse::UnprocessableEntity().finish(),
};
let parsed_game: schemas::ChellarisGameFlat = schemas::ChellarisGameFlat {
id: db_game.id, id: db_game.id,
name: db_game.name, name: db_game.name,
}; };
@ -421,6 +457,61 @@ pub(crate) async fn create_game(
} }
} }
#[utoipa::path(
request_body = UpdateGameParams,
responses(
(status = 200, description = "OK", body = ChellarisGameLite),
(status = 422, description = "Missing Game Name"),
(status = 401, description = "Auth Token Invalid"),
),
security(
("api_key" = [])
),
)]
#[put("/api/v3/game")]
pub(crate) async fn edit_game(
data: web::Data<AppState>,
params: web::Json<schemas::UpdateGameParams>,
req: HttpRequest,
) -> impl Responder {
let auth_token = get_auth_header(&req);
let params = params.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(auth_token.as_deref(), &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,
"UPDATE public.games SET name = $1 WHERE id = $2 RETURNING * ;",
params.game_name, params.game_id
)
.fetch_one(&data.db)
.await
{
Ok(data) => data,
Err(_) => return HttpResponse::UnprocessableEntity().finish(),
};
let parsed_game: schemas::ChellarisGameFlat = schemas::ChellarisGameFlat {
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( #[utoipa::path(
params( params(
schemas::DeleteGameParam, schemas::DeleteGameParam,
@ -438,25 +529,177 @@ pub(crate) async fn create_game(
#[delete("/api/v3/game")] #[delete("/api/v3/game")]
pub(crate) async fn delete_game( pub(crate) async fn delete_game(
data: web::Data<AppState>, data: web::Data<AppState>,
auth_params: web::Json<schemas::AuthParams>, req: HttpRequest,
param: web::Query<schemas::DeleteGameParam>, param: web::Query<schemas::DeleteGameParam>,
) -> impl Responder { ) -> impl Responder {
let auth_params = auth_params.into_inner(); let auth_token = get_auth_header(&req);
let param = param.into_inner(); let param = param.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(&auth_params.token, &data); let user_auth: schemas::AuthReturn = verify_auth(auth_token, &data);
// SQL Queries // SQL Queries
// TODO: Optimize by utilizing some SQL magic, for now this has to do // TODO: Optimize by utilizing some SQL magic, for now this has to do
if user_auth.admin || user_auth.moderator { if user_auth.admin || user_auth.moderator {
match sqlx::query!( match sqlx::query!("DELETE FROM public.games WHERE id = $1", param.game_id)
"DELETE FROM public.games WHERE id = $1", .execute(&data.db)
param.game_id as i32 .await
)
.execute(&data.db)
.await
{ {
Ok(_) => {}, Ok(_) => {}
Err(e) => {
println!("{:#?}", e);
return HttpResponse::UnprocessableEntity().finish();
},
};
return HttpResponse::Ok().into();
} else {
return HttpResponse::Unauthorized().finish();
}
}
// Group Endpoints
#[utoipa::path(
request_body = PostGroupParams,
responses(
(status = 200, description = "OK", body = ChellarisGroupFlat),
(status = 422, description = "Missing Game Name"),
(status = 401, description = "Auth Token Invalid"),
),
security(
("api_key" = [])
),
)]
#[post("/api/v3/group")]
pub(crate) async fn create_group(
data: web::Data<AppState>,
params: web::Json<schemas::PostGroupParams>,
req: HttpRequest,
) -> impl Responder {
let auth_token = get_auth_header(&req);
let params = params.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(auth_token.as_deref(), &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.group_name != "" {
let db_group: db::schemas::GameGroup;
db_group = match sqlx::query_as!(
db::schemas::GameGroup,
"INSERT INTO public.game_groups(name, game_id) VALUES ($1, $2) RETURNING * ",
params.group_name, params.game_id
)
.fetch_one(&data.db)
.await
{
Ok(data) => data,
Err(_) => return HttpResponse::UnprocessableEntity().finish(),
};
let parsed_group: schemas::ChellarisGroupFlat = schemas::ChellarisGroupFlat {
id: db_group.id,
name: db_group.name,
};
return HttpResponse::Ok().json(parsed_group);
} else {
return HttpResponse::UnprocessableEntity().finish();
}
} else {
return HttpResponse::Unauthorized().finish();
}
}
#[utoipa::path(
request_body = UpdateGroupParams,
responses(
(status = 200, description = "OK", body = ChellarisGroupFlat),
(status = 422, description = "Missing Game Name"),
(status = 401, description = "Auth Token Invalid"),
),
security(
("api_key" = [])
),
)]
#[put("/api/v3/group")]
pub(crate) async fn edit_group(
data: web::Data<AppState>,
params: web::Json<schemas::UpdateGroupParams>,
req: HttpRequest,
) -> impl Responder {
let auth_token = get_auth_header(&req);
let params = params.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(auth_token.as_deref(), &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.group_name != "" {
let db_group: db::schemas::GameGroup;
db_group = match sqlx::query_as!(
db::schemas::GameGroup,
"UPDATE public.game_groups SET name = $1 WHERE id = $2 AND game_id = $3 RETURNING * ;",
params.group_name, params.group_id, params.game_id
)
.fetch_one(&data.db)
.await
{
Ok(data) => data,
Err(_) => return HttpResponse::UnprocessableEntity().finish(),
};
let parsed_group: schemas::ChellarisGroupFlat = schemas::ChellarisGroupFlat {
id: db_group.id,
name: db_group.name,
};
return HttpResponse::Ok().json(parsed_group);
} else {
return HttpResponse::UnprocessableEntity().finish();
}
} else {
return HttpResponse::Unauthorized().finish();
}
}
#[utoipa::path(
params(
schemas::DeleteGroupParams,
),
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/group")]
pub(crate) async fn delete_group(
data: web::Data<AppState>,
req: HttpRequest,
param: web::Query<schemas::DeleteGroupParams>,
) -> impl Responder {
let auth_token = get_auth_header(&req);
let param = param.into_inner();
let user_auth: schemas::AuthReturn = verify_auth(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 {
match sqlx::query!("DELETE FROM public.game_groups WHERE id = $1 AND game_id = $2 AND name != 'N/A'", param.group_id, param.game_id)
.execute(&data.db)
.await
{
Ok(_) => {}
Err(_) => return HttpResponse::UnprocessableEntity().finish(), Err(_) => return HttpResponse::UnprocessableEntity().finish(),
}; };
@ -466,12 +709,15 @@ pub(crate) async fn delete_game(
} }
} }
// Empire Endpoints
// Data Manipulation Endpoints // Data Manipulation Endpoints
// Moderator & Admin // Moderator & Admin
// Add/Update/Remove Empire // Add/Update/Remove Empire
// Add/Update/Remove Group // Update Group
// Add/Update/Remove Game // Update Game
// Admin // Admin
// Add/Update/Remove Portrait // Add/Update/Remove Portrait

View file

@ -1,20 +1,8 @@
use std::collections::HashMap; use std::{collections::HashMap};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use utoipa::{ToSchema, IntoParams}; use utoipa::{ToSchema, IntoParams};
#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
pub struct AuthParamsOptional {
#[schema(example = "1357")]
pub token: Option<String>,
}
#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
pub struct AuthParams {
#[schema(example = "1357")]
pub token: String,
}
#[derive(Serialize, Deserialize, ToSchema, Debug)] #[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct AuthReturn { pub struct AuthReturn {
#[schema(example = false)] #[schema(example = false)]
@ -23,14 +11,24 @@ pub struct AuthReturn {
pub admin: bool, pub admin: bool,
} }
// Game Structs
#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] #[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
pub struct GetGameParam { pub struct GetGameParam {
pub game_id: Option<usize>, #[schema(example = 0)]
pub game_id: i32,
} }
#[derive(Serialize, Deserialize, ToSchema, Debug)] #[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct PostGameParams { pub struct PostGameParams {
pub auth: AuthParams, #[schema(example = "Game XY")]
pub game_name: String,
}
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct UpdateGameParams {
#[schema(example = 0)]
pub game_id: i32,
#[schema(example = "Game XY")] #[schema(example = "Game XY")]
pub game_name: String, pub game_name: String,
} }
@ -38,44 +36,97 @@ pub struct PostGameParams {
#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] #[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
pub struct DeleteGameParam { pub struct DeleteGameParam {
#[schema(example = 0)] #[schema(example = 0)]
pub game_id: usize, pub game_id: i32,
} }
#[derive(Serialize, ToSchema, Debug, Clone)] #[derive(Serialize, ToSchema, Debug, Clone)]
pub struct FullViewData { pub struct FullViewData {
pub games: HashMap<i32, ChellarisGame>, pub games: HashMap<i32, ChellarisGameLegacy>,
pub ethics: HashMap<i32, Ethic>, pub ethics: HashMap<i32, Ethic>,
pub species: HashMap<i32, Species>, pub species: HashMap<i32, Species>,
} }
#[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisGameLegacy {
pub id: i32,
pub name: String,
pub groups: HashMap<i32, ChellarisGameGroupLegacy>,
pub empires: HashMap<i32, ChellarisEmpire>,
}
#[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisGameFlat {
pub id: i32,
pub name: String,
}
#[derive(Serialize, ToSchema, Debug, Clone)] #[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisGame { pub struct ChellarisGame {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
pub groups: HashMap<i32, ChellarisGameGroup>, pub empires: HashMap<i32, ChellarisEmpireFlat>,
pub empires: HashMap<i32, ChellarisEmpire>, pub groups: HashMap<i32, ChellarisGroupFlat>
}
// Group Structs
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct PostGroupParams {
#[schema(example = "Group XY")]
pub group_name: String,
#[schema(example = 0)]
pub game_id: i32
}
#[derive(Serialize, Deserialize, ToSchema, Debug)]
pub struct UpdateGroupParams {
#[schema(example = 0)]
pub group_id: i32,
#[schema(example = 0)]
pub game_id: i32,
#[schema(example = "Group XY")]
pub group_name: String
}
#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
pub struct DeleteGroupParams {
#[schema(example = 0)]
pub group_id: i32,
#[schema(example = 0)]
pub game_id: i32,
} }
#[derive(Serialize, ToSchema, Debug, Clone)] #[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisGameLite { pub struct ChellarisGroupFlat {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
} }
#[derive(Serialize, ToSchema, Debug, Clone)] #[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisGameGroup { pub struct ChellarisGameGroupLegacy {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
} }
#[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisEmpireFlat {
pub id: i32,
pub group: i32,
pub name: String,
pub discord_user: Option<String>,
pub gestalt: bool,
pub empire_portrait: Option<i32>,
pub empire_portrait_group: Option<i32>,
}
#[derive(Serialize, ToSchema, Debug, Clone)] #[derive(Serialize, ToSchema, Debug, Clone)]
pub struct ChellarisEmpire { pub struct ChellarisEmpire {
pub id: i32, pub id: i32,
pub gestalt: bool, pub gestalt: bool,
pub machine: bool, pub machine: bool,
pub group: i32, pub group: i32,
pub empire_portrait: i32, pub empire_portrait: Option<i32>,
pub empire_portrait_group: i32, pub empire_portrait_group: Option<i32>,
pub discord_user: Option<String>, pub discord_user: Option<String>,
pub ethics: HashMap<i32, EmpireEthic>, pub ethics: HashMap<i32, EmpireEthic>,
} }