Add new "v1" API, rename "v2" and "v3" to legacy
This commit is contained in:
parent
134581f8ad
commit
b3347a6e53
3 changed files with 487 additions and 13 deletions
75
src/main.rs
75
src/main.rs
|
@ -25,15 +25,21 @@ macro_rules! api_base {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! api_base_1 {
|
||||||
|
() => {
|
||||||
|
"/api/v1"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! api_base_2 {
|
macro_rules! api_base_2 {
|
||||||
() => {
|
() => {
|
||||||
"/api/v2"
|
"/api/v2-l"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! api_base_3 {
|
macro_rules! api_base_3 {
|
||||||
() => {
|
() => {
|
||||||
"/api/v3"
|
"/api/v3-l"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,9 +214,27 @@ async fn main() -> Result<()> {
|
||||||
)]
|
)]
|
||||||
struct ApiDocV3;
|
struct ApiDocV3;
|
||||||
|
|
||||||
|
#[derive(OpenApi)]
|
||||||
|
#[openapi(
|
||||||
|
paths(
|
||||||
|
v1::get_user,
|
||||||
|
v1::create_user,
|
||||||
|
v1::update_user,
|
||||||
|
v1::delete_user
|
||||||
|
),
|
||||||
|
components(schemas(
|
||||||
|
v1::schemas::GetUserParams,
|
||||||
|
v1::schemas::UpdateUserParams,
|
||||||
|
v1::schemas::DeleteUserParams,
|
||||||
|
v1::schemas::User
|
||||||
|
))
|
||||||
|
)]
|
||||||
|
struct ApiDocV1;
|
||||||
|
|
||||||
let openapi_urls = vec![
|
let openapi_urls = vec![
|
||||||
Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
|
Url::new("v1", concat!(api_base_1!(), "/openapi.json")),
|
||||||
Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
|
Url::new("v2-L", concat!(api_base_2!(), "/openapi.json")),
|
||||||
|
Url::new("v3-L", concat!(api_base_3!(), "/openapi.json")),
|
||||||
];
|
];
|
||||||
|
|
||||||
let is_alive: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
|
let is_alive: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
|
||||||
|
@ -218,15 +242,31 @@ async fn main() -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
let db_auth_tokens = config.auth.clone();
|
let db_auth_tokens = config.auth.clone();
|
||||||
let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap();
|
let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap();
|
||||||
|
|
||||||
let pool_copy = pool.clone();
|
let pool_copy = pool.clone();
|
||||||
|
let shutdown_clone = shutdown.clone();
|
||||||
|
|
||||||
let swagger_config = Config::new(openapi_urls.clone());
|
let swagger_config = Config::new(openapi_urls.clone());
|
||||||
|
|
||||||
let mut openapi_v2 = ApiDocV2::openapi();
|
let mut openapi_v1 = ApiDocV1::openapi();
|
||||||
openapi_v2.info.title = "Chellaris Rust API".to_string();
|
openapi_v1.info.title = "Chellaris Rust API v1".to_string();
|
||||||
|
|
||||||
let mut openapi_v3 = ApiDocV3::openapi();
|
let mut openapi_v2_l = ApiDocV2::openapi();
|
||||||
openapi_v3.info.title = "Chellaris Rust API".to_string();
|
openapi_v2_l.info.title = "Legacy Chellaris Rust API v2".to_string();
|
||||||
|
|
||||||
|
let mut openapi_v3_l = ApiDocV3::openapi();
|
||||||
|
openapi_v3_l.info.title = "Legacy Chellaris Rust API v3".to_string();
|
||||||
|
|
||||||
|
println!("Serving API on: ");
|
||||||
|
println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080);
|
||||||
|
println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080);
|
||||||
|
|
||||||
|
let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone) });
|
||||||
|
tokio::spawn(async move {
|
||||||
|
actix_web::rt::signal::ctrl_c().await.unwrap();
|
||||||
|
println!("Ctrl-C received, killing Server");
|
||||||
|
abort()
|
||||||
|
});
|
||||||
|
|
||||||
let server = HttpServer::new(move || {
|
let server = HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
|
@ -257,17 +297,26 @@ async fn main() -> Result<()> {
|
||||||
.service(v3::delete_empire)
|
.service(v3::delete_empire)
|
||||||
.service(v3::get_ethics)
|
.service(v3::get_ethics)
|
||||||
.service(v3::get_phenotypes)
|
.service(v3::get_phenotypes)
|
||||||
|
// API v1 Endpoints
|
||||||
|
.service(v1::get_user)
|
||||||
|
.service(v1::create_user)
|
||||||
|
.service(v1::update_user)
|
||||||
|
.service(v1::delete_user)
|
||||||
// Swagger UI
|
// Swagger UI
|
||||||
.service(
|
.service(
|
||||||
SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
|
SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
|
||||||
.urls(vec![
|
.urls(vec![
|
||||||
(
|
(
|
||||||
Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
|
Url::new("v1", concat!(api_base_1!(), "/openapi.json")),
|
||||||
openapi_v2.clone(),
|
openapi_v1.clone(),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
|
Url::new("v2-l", concat!(api_base_2!(), "/openapi.json")),
|
||||||
openapi_v3.clone(),
|
openapi_v2_l.clone(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Url::new("v3-l", concat!(api_base_3!(), "/openapi.json")),
|
||||||
|
openapi_v3_l.clone(),
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.config(swagger_config.clone()),
|
.config(swagger_config.clone()),
|
||||||
|
|
360
src/v1/mod.rs
Normal file
360
src/v1/mod.rs
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
use crate::{db, AppState};
|
||||||
|
use actix_web::web::Json;
|
||||||
|
use actix_web::{delete, get, post, put, web, HttpRequest, HttpResponse, Responder};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use rand::distributions::Alphanumeric;
|
||||||
|
use rand::{Rng, thread_rng};
|
||||||
|
use sqlx::QueryBuilder;
|
||||||
|
|
||||||
|
pub(crate) mod schemas;
|
||||||
|
|
||||||
|
fn get_auth_header<'a>(req: &'a HttpRequest) -> Option<&'a str> {
|
||||||
|
req.headers().get("x-api-key")?.to_str().ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn verify_user_auth(data: &web::Data<AppState>, auth_token: &str, user_token: &str, table: schemas::TablePermission, permissions_only: bool) -> bool {
|
||||||
|
let user: db::schemas::User = match sqlx::query_as!(
|
||||||
|
db::schemas::User,
|
||||||
|
"SELECT * FROM public.users WHERE token = $1",
|
||||||
|
auth_token
|
||||||
|
)
|
||||||
|
.fetch_one(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if user.token == user_token && !permissions_only {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
match table {
|
||||||
|
schemas::TablePermission::Game => {
|
||||||
|
return user.data_permissions;
|
||||||
|
},
|
||||||
|
schemas::TablePermission::Empire => {
|
||||||
|
return user.empire_permissions;
|
||||||
|
},
|
||||||
|
schemas::TablePermission::Data => {
|
||||||
|
return user.data_permissions;
|
||||||
|
},
|
||||||
|
schemas::TablePermission::User => {
|
||||||
|
return user.user_permissions;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User Endpoints
|
||||||
|
#[utoipa::path(
|
||||||
|
request_body = schemas::GetUserParams,
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "OK", body = User),
|
||||||
|
(status = 403, description = "Unauthorized"),
|
||||||
|
(status = 500, description = "Internal Server Error")
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("api_key" = [])
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
#[get("/api/v1/user")]
|
||||||
|
async fn get_user(
|
||||||
|
data: web::Data<AppState>,
|
||||||
|
params: web::Json<schemas::GetUserParams>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> impl Responder {
|
||||||
|
let auth_header = get_auth_header(&req);
|
||||||
|
let params = params.into_inner();
|
||||||
|
|
||||||
|
let auth_token: String;
|
||||||
|
|
||||||
|
match auth_header {
|
||||||
|
Some(token) => auth_token = token.to_string(),
|
||||||
|
None => return HttpResponse::Unauthorized().finish(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let auth = verify_user_auth(&data, &auth_token, ¶ms.user_token, schemas::TablePermission::User, false).await;
|
||||||
|
|
||||||
|
if auth {
|
||||||
|
let user: db::schemas::User = match sqlx::query_as!(
|
||||||
|
db::schemas::User,
|
||||||
|
"SELECT * FROM public.users WHERE token = $1",
|
||||||
|
params.user_token
|
||||||
|
)
|
||||||
|
.fetch_one(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return HttpResponse::InternalServerError().finish(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut permissions: HashMap<String, bool> = HashMap::new();
|
||||||
|
|
||||||
|
permissions.insert("game_permissions".to_string(), user.game_permissions);
|
||||||
|
permissions.insert("empire_permissions".to_string(), user.empire_permissions);
|
||||||
|
permissions.insert("data_permissions".to_string(), user.data_permissions);
|
||||||
|
permissions.insert("user_permissions".to_string(), user.user_permissions);
|
||||||
|
|
||||||
|
let return_data = schemas::User {
|
||||||
|
user_token: user.token,
|
||||||
|
discord_handle: user.discord_id,
|
||||||
|
profile_picture: user.picture_url,
|
||||||
|
permissions: permissions
|
||||||
|
};
|
||||||
|
|
||||||
|
return HttpResponse::Ok().json(return_data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return HttpResponse::Unauthorized().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "OK", body = User),
|
||||||
|
(status = 500, description = "Internal Server Error")
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
#[post("/api/v1/user")]
|
||||||
|
pub(crate) async fn create_user(
|
||||||
|
data: web::Data<AppState>,
|
||||||
|
) -> impl Responder {
|
||||||
|
let user: db::schemas::User;
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let user_tokens = match sqlx::query_scalar!(
|
||||||
|
"SELECT token FROM public.users"
|
||||||
|
)
|
||||||
|
.fetch_all(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return HttpResponse::InternalServerError().finish(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_token: String;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut chars: String = (0..6).map(|_| rng.sample(Alphanumeric) as char).collect();
|
||||||
|
chars = chars.to_uppercase();
|
||||||
|
if !user_tokens.contains(&chars) {
|
||||||
|
new_token = chars;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("looping");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user = match sqlx::query_as!(
|
||||||
|
db::schemas::User,
|
||||||
|
"INSERT INTO public.users(token, game_permissions, empire_permissions, data_permissions, user_permissions) VALUES ($1, $2, $3, $4, $5) RETURNING * ",
|
||||||
|
new_token,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
|
||||||
|
)
|
||||||
|
.fetch_one(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return HttpResponse::InternalServerError().finish(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return HttpResponse::Ok().json(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
request_body = UpdateUserParams,
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "OK"),
|
||||||
|
(status = 403, description = "Unauthorized"),
|
||||||
|
(status = 500, description = "Internal Server Error")
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("api_key" = [])
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
#[put("/api/v1/user")]
|
||||||
|
pub(crate) async fn update_user(
|
||||||
|
data: web::Data<AppState>,
|
||||||
|
params: web::Json<schemas::UpdateUserParams>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> impl Responder {
|
||||||
|
let auth_header = get_auth_header(&req);
|
||||||
|
let params = params.into_inner();
|
||||||
|
|
||||||
|
let auth_token: String;
|
||||||
|
|
||||||
|
match auth_header {
|
||||||
|
Some(token) => auth_token = token.to_string(),
|
||||||
|
None => return HttpResponse::Unauthorized().finish(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut elevated_auth = false;
|
||||||
|
if params.permissions["game_permissions"] || params.permissions["empire_permissions"] || params.permissions["data_permissions"] || params.permissions["user_permissions"] {
|
||||||
|
elevated_auth = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let auth = verify_user_auth(&data, &auth_token, ¶ms.user_token, schemas::TablePermission::User, elevated_auth).await;
|
||||||
|
|
||||||
|
// SQL Queries
|
||||||
|
// TODO: Optimize by utilizing some SQL magic, for now this has to do
|
||||||
|
if auth {
|
||||||
|
let user: db::schemas::User;
|
||||||
|
|
||||||
|
let mut user_query = QueryBuilder::<sqlx::Postgres>::new("UPDATE public.users SET ");
|
||||||
|
let mut user_query_separated = user_query.separated(", ");
|
||||||
|
let mut any_param_present = false;
|
||||||
|
|
||||||
|
if let Some(discord_handle) = params.discord_handle {
|
||||||
|
user_query_separated.push(" discord_id = ").push_bind_unseparated(discord_handle);
|
||||||
|
any_param_present = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(profile_picture) = params.profile_picture {
|
||||||
|
user_query_separated.push(" picture_url = ");
|
||||||
|
match any_param_present {
|
||||||
|
true => user_query_separated.push_bind(profile_picture),
|
||||||
|
false => user_query_separated.push_bind_unseparated(profile_picture)
|
||||||
|
};
|
||||||
|
any_param_present = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entry, value) in params.permissions.iter() {
|
||||||
|
match entry.deref() {
|
||||||
|
"game_permissions" => {
|
||||||
|
user_query_separated.push( " game_permissions = ");
|
||||||
|
match any_param_present {
|
||||||
|
true => user_query_separated.push_bind(value),
|
||||||
|
false => user_query_separated.push_bind_unseparated(value)
|
||||||
|
};
|
||||||
|
any_param_present = true;
|
||||||
|
},
|
||||||
|
"empire_permissions" => {
|
||||||
|
user_query_separated.push( " empire_permissions = ");
|
||||||
|
match any_param_present {
|
||||||
|
true => user_query_separated.push_bind(value),
|
||||||
|
false => user_query_separated.push_bind_unseparated(value)
|
||||||
|
};
|
||||||
|
any_param_present = true;
|
||||||
|
},
|
||||||
|
"data_permissions" => {
|
||||||
|
user_query_separated.push( " data_permissions = ");
|
||||||
|
match any_param_present {
|
||||||
|
true => user_query_separated.push_bind(value),
|
||||||
|
false => user_query_separated.push_bind_unseparated(value)
|
||||||
|
};
|
||||||
|
any_param_present = true;
|
||||||
|
},
|
||||||
|
"user_permissions" => {
|
||||||
|
user_query_separated.push( " user_permissions = ");
|
||||||
|
match any_param_present {
|
||||||
|
true => user_query_separated.push_bind(value),
|
||||||
|
false => user_query_separated.push_bind_unseparated(value)
|
||||||
|
};
|
||||||
|
any_param_present = true;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if any_param_present {
|
||||||
|
user_query_separated.push_unseparated(" WHERE token = ").push_bind_unseparated(params.user_token);
|
||||||
|
user_query_separated.push_unseparated(" RETURNING *");
|
||||||
|
|
||||||
|
user = match user_query
|
||||||
|
.build_query_as::<db::schemas::User>()
|
||||||
|
.fetch_one(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return HttpResponse::InternalServerError().finish(),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
user = match sqlx::query_as!(
|
||||||
|
db::schemas::User,
|
||||||
|
"SELECT * FROM public.users WHERE token = $1",
|
||||||
|
params.user_token
|
||||||
|
)
|
||||||
|
.fetch_one(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return HttpResponse::InternalServerError().finish(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut permissions: HashMap<String, bool> = HashMap::new();
|
||||||
|
permissions.insert("game_permissions".to_string(), user.game_permissions);
|
||||||
|
permissions.insert("empire_permissions".to_string(), user.empire_permissions);
|
||||||
|
permissions.insert("data_permissions".to_string(), user.data_permissions);
|
||||||
|
permissions.insert("user_permissions".to_string(), user.user_permissions);
|
||||||
|
|
||||||
|
let return_data = schemas::User {
|
||||||
|
user_token: user.token,
|
||||||
|
discord_handle: user.discord_id,
|
||||||
|
profile_picture: user.picture_url,
|
||||||
|
permissions: permissions
|
||||||
|
};
|
||||||
|
return HttpResponse::Ok().json(return_data);
|
||||||
|
} else {
|
||||||
|
return HttpResponse::Unauthorized().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
request_body = schemas::DeleteUserParams,
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "OK"),
|
||||||
|
(status = 403, description = "Unauthorized"),
|
||||||
|
(status = 500, description = "Internal Server Error")
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("api_key" = [])
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
#[delete("/api/v1/user")]
|
||||||
|
pub(crate) async fn delete_user(
|
||||||
|
data: web::Data<AppState>,
|
||||||
|
params: web::Query<schemas::DeleteUserParams>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> impl Responder {
|
||||||
|
let auth_header = get_auth_header(&req);
|
||||||
|
let params = params.into_inner();
|
||||||
|
|
||||||
|
let auth_token: String;
|
||||||
|
|
||||||
|
match auth_header {
|
||||||
|
Some(token) => auth_token = token.to_string(),
|
||||||
|
None => return HttpResponse::Unauthorized().finish(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let auth = verify_user_auth(&data, &auth_token, ¶ms.user_token, schemas::TablePermission::User, false).await;
|
||||||
|
|
||||||
|
// SQL Queries
|
||||||
|
// TODO: Optimize by utilizing some SQL magic, for now this has to do
|
||||||
|
if auth {
|
||||||
|
match sqlx::query!(
|
||||||
|
"DELETE FROM public.users WHERE token = $1",
|
||||||
|
params.user_token
|
||||||
|
)
|
||||||
|
.execute(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return HttpResponse::Ok().into();
|
||||||
|
} else {
|
||||||
|
return HttpResponse::Unauthorized().finish();
|
||||||
|
}
|
||||||
|
}
|
65
src/v1/schemas.rs
Normal file
65
src/v1/schemas.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use utoipa::{IntoParams, ToSchema};
|
||||||
|
use crate::v3::schemas::ChellarisGameLegacy;
|
||||||
|
|
||||||
|
// DB Permission Enums
|
||||||
|
|
||||||
|
pub enum TablePermission {
|
||||||
|
Game,
|
||||||
|
Empire,
|
||||||
|
Data,
|
||||||
|
User
|
||||||
|
}
|
||||||
|
|
||||||
|
// User Structs
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema, Debug)]
|
||||||
|
pub struct User {
|
||||||
|
#[schema(example = "abcdef")]
|
||||||
|
pub user_token: String,
|
||||||
|
#[schema(example = "discorduser")]
|
||||||
|
pub discord_handle: Option<String>,
|
||||||
|
#[schema(example = "/assets/avatars/124677612.png")]
|
||||||
|
pub profile_picture: Option<String>,
|
||||||
|
#[schema(example = "\
|
||||||
|
{\
|
||||||
|
[\"game_permissions\"]: true,
|
||||||
|
[\"empire_permissions\"]: true,
|
||||||
|
[\"data_permissions\"]: false,
|
||||||
|
[\"user_permissions\"]: false,
|
||||||
|
}\
|
||||||
|
")]
|
||||||
|
pub permissions: HashMap<String, bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||||
|
pub struct GetUserParams {
|
||||||
|
#[schema(example = "abcdef")]
|
||||||
|
pub user_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||||
|
pub struct UpdateUserParams {
|
||||||
|
#[schema(example = "abcdef")]
|
||||||
|
pub user_token: String,
|
||||||
|
#[schema(example = "discorduser")]
|
||||||
|
pub discord_handle: Option<String>,
|
||||||
|
#[schema(example = "/assets/avatars/124677612.png")]
|
||||||
|
pub profile_picture: Option<String>,
|
||||||
|
#[schema(example = "\
|
||||||
|
{\
|
||||||
|
[\"game_permissions\"]: true,
|
||||||
|
[\"empire_permissions\"]: true,
|
||||||
|
[\"data_permissions\"]: false,
|
||||||
|
[\"user_permissions\"]: false,
|
||||||
|
}\
|
||||||
|
")]
|
||||||
|
pub permissions: HashMap<String, bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||||
|
pub struct DeleteUserParams {
|
||||||
|
#[schema(example = "abcdef")]
|
||||||
|
pub user_token: String,
|
||||||
|
}
|
Reference in a new issue