Compare commits
40 commits
Author | SHA1 | Date | |
---|---|---|---|
e8f931392e | |||
36709b6b80 | |||
cd79f47caa | |||
48143979e5 | |||
717e3fda49 | |||
22fa59334c | |||
5c0c03fd7a | |||
c8ed40c3cc | |||
8373b278cc | |||
c0799484bb | |||
83a1af59d9 | |||
c01ed85e7a | |||
12938d1ee4 | |||
75eefab02c | |||
b3347a6e53 | |||
134581f8ad | |||
35807d66ab | |||
0e5dca0f9a | |||
0f7958ce08 | |||
4c28954335 | |||
e056fd7fa0 | |||
f873fb366a | |||
be28b98ff6 | |||
335cfcb05c | |||
3f7616aeca | |||
29fa524241 | |||
51ade4a3a1 | |||
12b5fc5ccb | |||
489158d1c4 | |||
4213c550b8 | |||
f4e5503d0b | |||
ebbaed0973 | |||
817f777059 | |||
2ac5931c79 | |||
719cbbaf3a | |||
97bae3be1a | |||
5a557d262b | |||
464f870c29 | |||
097b6884b9 | |||
d91af52811 |
16 changed files with 1339 additions and 735 deletions
91
.forgejo/workflows/build+release.yml
Normal file
91
.forgejo/workflows/build+release.yml
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
name: 'Build and Release Binary File'
|
||||||
|
author: 'Neshura'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
|
- '[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checking Out Repository Code
|
||||||
|
uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
-
|
||||||
|
name: Placeholder
|
||||||
|
run: echo Placeholder Job
|
||||||
|
-
|
||||||
|
name: Check if Version in Cargo.toml matches Tag
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ")
|
||||||
|
if test $VERSION != "${{ github.ref_name }}"; then
|
||||||
|
echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'";
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Version is: '$VERSION'";
|
||||||
|
fi
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: test
|
||||||
|
if: success()
|
||||||
|
runs-on: docker
|
||||||
|
container: rust:latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Installing Node
|
||||||
|
run: apt update && apt install -y nodejs
|
||||||
|
-
|
||||||
|
name: Checking Out Repository Code
|
||||||
|
uses: https://code.forgejo.org/actions/checkout@v3
|
||||||
|
-
|
||||||
|
name: Preparing Environment
|
||||||
|
run: |
|
||||||
|
echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
|
||||||
|
echo MACHINE_GROUP_ID=${{ vars.MACHINE_GROUP_ID }} >> .env
|
||||||
|
echo UPTIME_KUMA_URL= >> .env
|
||||||
|
-
|
||||||
|
name: Compiling To Linux Target
|
||||||
|
run: |
|
||||||
|
cargo build -r
|
||||||
|
mv target/release/chellaris-rust-api chellaris-rust-api-linux-amd64
|
||||||
|
-
|
||||||
|
name: Uploading Build Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: chellaris-rust-api-linux-amd64
|
||||||
|
path: chellaris-rust-api-linux-amd64
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
upload-release:
|
||||||
|
needs: build
|
||||||
|
if: success()
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Downloading All Build Artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
-
|
||||||
|
name: Rearrange Artifact Paths
|
||||||
|
run: |
|
||||||
|
mkdir release
|
||||||
|
mv chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64
|
||||||
|
-
|
||||||
|
name: Upload Artifacts As Generic Packages
|
||||||
|
run: |
|
||||||
|
echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
|
||||||
|
--upload-file release/chellaris-rust-api-linux-amd64 \
|
||||||
|
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{ github.ref_name }}/chellaris-rust-api-linux-amd64'
|
||||||
|
curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
|
||||||
|
--upload-file release/chellaris-rust-api-linux-amd64 \
|
||||||
|
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{ github.ref_name }}/chellaris-rust-api-linux-amd64
|
||||||
|
-
|
||||||
|
name: Release New Version
|
||||||
|
uses: actions/forgejo-release@v1
|
||||||
|
with:
|
||||||
|
direction: upload
|
||||||
|
url: https://forgejo.neshweb.net
|
||||||
|
release-dir: release
|
||||||
|
token: ${{ secrets.FORGEJO_TOKEN }}
|
||||||
|
tag: ${{ github.ref_name }}
|
16
.forgejo/workflows/test.yml
Normal file
16
.forgejo/workflows/test.yml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
name: 'Run Tests on Code'
|
||||||
|
author: 'Neshura'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
branches:
|
||||||
|
- '**'
|
||||||
|
jobs:
|
||||||
|
run-tests:
|
||||||
|
runs-on: docker
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Placeholder
|
||||||
|
run: echo Placeholder Job
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
/target
|
/target
|
||||||
|
/.vscode
|
||||||
|
/.idea
|
||||||
|
|
||||||
config.toml
|
config.toml
|
||||||
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
image: 3.10.8-slim-buster
|
|
||||||
|
|
||||||
variables:
|
|
||||||
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/linux/$CI_COMMIT_TAG/"
|
|
||||||
|
|
||||||
.deploy:
|
|
||||||
rules:
|
|
||||||
# Regex magic copied from Neshura/page-test, only deploys on x.y.z or higher (x.y) Tags
|
|
||||||
- if: $CI_COMMIT_TAG =~ /^((([\d])+\.){1,2}[\d]+)\s*$/ && $CI_COMMIT_TAG
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- build
|
|
||||||
- upload
|
|
||||||
- release
|
|
||||||
|
|
||||||
## Docker steps
|
|
||||||
|
|
||||||
build:
|
|
||||||
image: rust:latest
|
|
||||||
stage: build
|
|
||||||
|
|
||||||
variables:
|
|
||||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_BRANCH
|
|
||||||
CACHING:
|
|
||||||
script:
|
|
||||||
- echo "Compiling the code..."
|
|
||||||
- echo DATABASE_URL=$DATABASE_URL >> .env
|
|
||||||
- cargo build -r
|
|
||||||
- echo "Compile complete."
|
|
||||||
after_script:
|
|
||||||
- echo JOB_ID=$CI_JOB_ID >> job.env
|
|
||||||
- mkdir ./artifacts
|
|
||||||
- cp /builds/neshura-websites/chellaris-rust-api/target/release/chellaris-rust-api ./artifacts/
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- ./artifacts/
|
|
||||||
reports:
|
|
||||||
dotenv: job.env
|
|
||||||
rules:
|
|
||||||
- !reference [.deploy, rules]
|
|
||||||
|
|
||||||
upload:
|
|
||||||
needs:
|
|
||||||
- job: build
|
|
||||||
artifacts: true
|
|
||||||
image: curlimages/curl:latest
|
|
||||||
stage: upload
|
|
||||||
script:
|
|
||||||
- |
|
|
||||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file artifacts/chellaris-rust-api "${PACKAGE_REGISTRY_URL}/chellaris-rust-api"
|
|
||||||
rules:
|
|
||||||
- !reference [.deploy, rules]
|
|
||||||
|
|
||||||
|
|
||||||
Tag Release:
|
|
||||||
stage: release
|
|
||||||
image: registry.gitlab.com/gitlab-org/release-cli:latest
|
|
||||||
rules:
|
|
||||||
- !reference [.deploy, rules]
|
|
||||||
script:
|
|
||||||
- apk add curl
|
|
||||||
- echo "running Release Job, attaching Artifact from Job $JOB_ID"
|
|
||||||
release:
|
|
||||||
tag_name: '$CI_COMMIT_TAG'
|
|
||||||
description: '$CI_COMMIT_TAG'
|
|
||||||
assets:
|
|
||||||
links:
|
|
||||||
- name: "chellaris-rust-api"
|
|
||||||
url: "${PACKAGE_REGISTRY_URL}/chellaris-rust-api"
|
|
669
Cargo.lock
generated
669
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
33
Cargo.toml
33
Cargo.toml
|
@ -1,22 +1,25 @@
|
||||||
[package]
|
[package]
|
||||||
name = "chellaris-rust-api"
|
name = "chellaris-rust-api"
|
||||||
version = "1.0.3"
|
version = "1.2.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "4.3.1"
|
actix-web = "4.4.0"
|
||||||
chrono = "0.4.26"
|
chrono = "0.4.31"
|
||||||
ctrlc = "3.4.0"
|
ctrlc = "3.4.1"
|
||||||
dotenv = "0.15.0"
|
dotenvy = "0.15.7"
|
||||||
dotenv_codegen = "0.15.0"
|
dotenvy_macro = "0.15.7"
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.1"
|
||||||
schemars = "0.8.10"
|
reqwest = "0.11.22"
|
||||||
serde = { version = "1.0.185", features = ["derive"] }
|
schemars = "0.8.16"
|
||||||
serde_json = "1.0.105"
|
serde = { version = "1.0.193", features = ["derive"] }
|
||||||
sqlx = { version = "0.7.1", features = ["postgres", "runtime-tokio"] }
|
serde_json = "1.0.108"
|
||||||
tokio = { version = "1.32.0", features = ["rt"] }
|
sqlx = { version = "0.7.3", features = ["postgres", "runtime-tokio"] }
|
||||||
toml = "0.7.6"
|
tokio = { version = "1.35.0", features = ["rt", "rt-multi-thread", "macros", "time"] }
|
||||||
utoipa = { version = "3.5.0", features = ["actix_extras", "non_strict_integers"] }
|
toml = "0.8.8"
|
||||||
utoipa-swagger-ui = { version = "3.1.5", features = ["actix-web"] }
|
utoipa = { version = "4.1.0", features = ["actix_extras", "non_strict_integers"] }
|
||||||
|
utoipa-swagger-ui = { version = "5.0.0", features = ["actix-web"] }
|
||||||
|
rand = "0.8.5"
|
||||||
|
url = "2.5.0"
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"sqlx": "^4.3.2"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,7 +33,7 @@ pub struct GameGroup {
|
||||||
pub struct Ethic {
|
pub struct Ethic {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub machine_ethic: bool,
|
pub gestalt_ethic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
||||||
|
@ -42,10 +42,15 @@ pub struct Empire {
|
||||||
pub group_id: i32,
|
pub group_id: i32,
|
||||||
pub game_id: i32,
|
pub game_id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub discord_user: Option<String>,
|
|
||||||
pub gestalt: bool,
|
pub gestalt: bool,
|
||||||
pub portrait_id: i32,
|
pub portrait_id: i32,
|
||||||
pub portrait_group_id: i32,
|
pub portrait_group_id: i32,
|
||||||
|
pub backstory: String,
|
||||||
|
pub goals: String,
|
||||||
|
pub interactions: String,
|
||||||
|
pub available: bool,
|
||||||
|
pub approval_status: Option<bool>,
|
||||||
|
pub users_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
||||||
|
@ -55,3 +60,15 @@ pub struct EmpireEthic {
|
||||||
pub ethics_id: i32,
|
pub ethics_id: i32,
|
||||||
pub fanatic: bool,
|
pub fanatic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: i32,
|
||||||
|
pub token: String,
|
||||||
|
pub discord_id: Option<String>,
|
||||||
|
pub picture_url: Option<String>,
|
||||||
|
pub game_permissions: bool,
|
||||||
|
pub empire_permissions: bool,
|
||||||
|
pub data_permissions: bool,
|
||||||
|
pub user_permissions: bool,
|
||||||
|
}
|
||||||
|
|
187
src/main.rs
187
src/main.rs
|
@ -1,21 +1,24 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate dotenv_codegen;
|
extern crate dotenvy_macro;
|
||||||
extern crate dotenv;
|
extern crate dotenvy;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenvy::dotenv;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use std::{env, fs, net::Ipv4Addr, net::Ipv6Addr, time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering}}};
|
use std::{env, fs, net::Ipv4Addr, net::Ipv6Addr, time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering}}};
|
||||||
|
use std::process::abort;
|
||||||
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
|
||||||
use actix_web::{middleware::Logger, web, App, HttpServer, Result};
|
use actix_web::{middleware::Logger, web, App, HttpServer};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{PgPool, Pool, Postgres, Connection};
|
use sqlx::{PgPool, Pool, Postgres, Connection};
|
||||||
|
use tokio::signal::unix::SignalKind;
|
||||||
use utoipa::{OpenApi, openapi::security::{SecurityScheme, ApiKey, ApiKeyValue}, Modify};
|
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;
|
||||||
|
mod v1;
|
||||||
mod v2;
|
mod v2;
|
||||||
mod v3;
|
mod v3;
|
||||||
|
|
||||||
|
@ -25,21 +28,33 @@ 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"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub(crate) struct ConfigToml {
|
pub(crate) struct ConfigToml {
|
||||||
auth: AuthenticationTokens,
|
auth: AuthenticationTokens,
|
||||||
|
port: PortConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub(crate) struct PortConfig {
|
||||||
|
default: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
@ -53,11 +68,8 @@ pub struct AppState {
|
||||||
auth_tokens: AuthenticationTokens,
|
auth_tokens: AuthenticationTokens,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Arc<AtomicBool>) {
|
async fn postgres_watchdog(pool: PgPool, shutdown: Arc<AtomicBool>) {
|
||||||
loop {
|
while !shutdown.load(Ordering::Relaxed) {
|
||||||
if shutdown.load(Ordering::Relaxed) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let start = Local::now();
|
let start = Local::now();
|
||||||
|
|
||||||
let mut conn = match pool.acquire().await {
|
let mut conn = match pool.acquire().await {
|
||||||
|
@ -70,27 +82,32 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Ar
|
||||||
Err(_) => {println!("Error pinging Server"); break;},
|
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()));
|
let url = dotenvy::var("UPTIME_KUMA_URL").unwrap_or("".to_string());
|
||||||
|
if url != "" {
|
||||||
|
match reqwest::get(
|
||||||
|
url,
|
||||||
|
).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => println!("{}", err),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("No Uptime Kuma URL provided!");
|
||||||
|
}
|
||||||
|
|
||||||
sleep(Duration::from_secs(15) - passed).await;
|
while Local::now() - start < chrono::Duration::seconds(15) {
|
||||||
|
sleep(Duration::from_millis(100)).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is_alive.store(false, Ordering::Relaxed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
|
|
||||||
let shutdown: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
|
let shutdown: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
let shutdown_clone = Arc::clone(&shutdown);
|
|
||||||
ctrlc::set_handler(move || {
|
|
||||||
eprintln!("Ctrl-C received");
|
|
||||||
shutdown_clone.store(true, Ordering::Relaxed)
|
|
||||||
})
|
|
||||||
.expect("Error setting Ctrl-C handler");
|
|
||||||
|
|
||||||
let toml_str = fs::read_to_string("config.toml").expect("Failed to read config.toml");
|
let toml_str = fs::read_to_string("config.toml").expect("Failed to read config.toml");
|
||||||
|
|
||||||
let config: ConfigToml = toml::from_str(&toml_str).expect("Failed to parse config.toml");
|
let config: ConfigToml = toml::from_str(&toml_str).expect("Failed to parse config.toml");
|
||||||
|
@ -148,7 +165,9 @@ async fn main() -> Result<()> {
|
||||||
v3::get_empire,
|
v3::get_empire,
|
||||||
v3::create_empire,
|
v3::create_empire,
|
||||||
v3::edit_empire,
|
v3::edit_empire,
|
||||||
v3::delete_empire
|
v3::delete_empire,
|
||||||
|
v3::get_ethics,
|
||||||
|
v3::get_phenotypes
|
||||||
),
|
),
|
||||||
components(schemas(
|
components(schemas(
|
||||||
v3::schemas::AuthReturn,
|
v3::schemas::AuthReturn,
|
||||||
|
@ -165,15 +184,17 @@ async fn main() -> Result<()> {
|
||||||
v3::schemas::DeleteEmpireParams,
|
v3::schemas::DeleteEmpireParams,
|
||||||
v3::schemas::FullViewData,
|
v3::schemas::FullViewData,
|
||||||
v3::schemas::Ethic,
|
v3::schemas::Ethic,
|
||||||
|
v3::schemas::ChellarisEthics,
|
||||||
v3::schemas::EmpireEthic,
|
v3::schemas::EmpireEthic,
|
||||||
v3::schemas::EmpireEthicLegacy,
|
v3::schemas::EmpireEthicLegacy,
|
||||||
v3::schemas::ChellarisGameLegacy,
|
v3::schemas::ChellarisGameLegacy,
|
||||||
v3::schemas::ChellarisGameFlat,
|
v3::schemas::ChellarisGameFlat,
|
||||||
v3::schemas::ChellarisGame,
|
v3::schemas::ChellarisGame,
|
||||||
v3::schemas::Species,
|
v3::schemas::Phenotype,
|
||||||
|
v3::schemas::ChellarisPhenotypes,
|
||||||
v3::schemas::ChellarisGameGroupLegacy,
|
v3::schemas::ChellarisGameGroupLegacy,
|
||||||
v3::schemas::ChellarisGroupFlat,
|
v3::schemas::ChellarisGroupFlat,
|
||||||
v3::schemas::Portrait,
|
v3::schemas::Species,
|
||||||
v3::schemas::ChellarisEmpireLegacy,
|
v3::schemas::ChellarisEmpireLegacy,
|
||||||
v3::schemas::ChellarisEmpireFlat,
|
v3::schemas::ChellarisEmpireFlat,
|
||||||
v3::schemas::ChellarisEmpire
|
v3::schemas::ChellarisEmpire
|
||||||
|
@ -182,27 +203,64 @@ async fn main() -> Result<()> {
|
||||||
)]
|
)]
|
||||||
struct ApiDocV3;
|
struct ApiDocV3;
|
||||||
|
|
||||||
let openapi_urls = vec![
|
#[derive(OpenApi)]
|
||||||
Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
|
#[openapi(
|
||||||
Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
|
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 is_alive: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
|
let openapi_urls = vec![
|
||||||
|
Url::new("v1", concat!(api_base!(), "-docs/openapi1.json")),
|
||||||
|
Url::new("v2-L", concat!(api_base!(), "-docs/openapi2l.json")),
|
||||||
|
Url::new("v3-L", concat!(api_base!(), "-docs/openapi3l.json")),
|
||||||
|
];
|
||||||
|
|
||||||
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();
|
|
||||||
openapi_v3.info.title = "Chellaris Rust API".to_string();
|
|
||||||
|
|
||||||
let server = HttpServer::new(move || {
|
let mut openapi_v2_l = ApiDocV2::openapi();
|
||||||
|
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).await });
|
||||||
|
tokio::spawn(async move {
|
||||||
|
actix_web::rt::signal::unix::signal(SignalKind::terminate()).unwrap().recv().await;
|
||||||
|
println!("SIGTERM received, killing Server");
|
||||||
|
abort()
|
||||||
|
});
|
||||||
|
tokio::spawn(async move {
|
||||||
|
actix_web::rt::signal::unix::signal(SignalKind::interrupt()).unwrap().recv().await;
|
||||||
|
println!("SIGINT received, killing Server");
|
||||||
|
abort()
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(web::Data::new(AppState { db: pool.clone(), auth_tokens: db_auth_tokens.clone() }))
|
.app_data(web::Data::new(AppState { db: pool.clone(), auth_tokens: db_auth_tokens.clone() }))
|
||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
|
@ -229,56 +287,43 @@ async fn main() -> Result<()> {
|
||||||
.service(v3::create_empire)
|
.service(v3::create_empire)
|
||||||
.service(v3::edit_empire)
|
.service(v3::edit_empire)
|
||||||
.service(v3::delete_empire)
|
.service(v3::delete_empire)
|
||||||
|
.service(v3::get_ethics)
|
||||||
|
.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!(), "-docs/openapi1.json")),
|
||||||
openapi_v2.clone(),
|
openapi_v1.clone(),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
|
Url::new("v2-l", concat!(api_base!(), "-docs/openapi2l.json")),
|
||||||
openapi_v3.clone(),
|
openapi_v2_l.clone(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Url::new("v3-l", concat!(api_base!(), "-docs/openapi3l.json")),
|
||||||
|
openapi_v3_l.clone(),
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.config(swagger_config.clone()),
|
.config(swagger_config.clone()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.bind((Ipv6Addr::UNSPECIFIED, 8080)).expect("Port or IP already occupied")
|
.bind((Ipv6Addr::UNSPECIFIED, config.port.default)).expect("Port or IP already occupied")
|
||||||
.run();
|
.run()
|
||||||
|
.await;
|
||||||
|
|
||||||
let server_thread = tokio::spawn(async {
|
watchdog_thread.abort();
|
||||||
println!("Awaiting server");
|
|
||||||
let _ = server.await;
|
|
||||||
println!("Stopped awaiting server");
|
|
||||||
});
|
|
||||||
|
|
||||||
println!("Started Serving API on: ");
|
sleep(Duration::from_secs(10)).await;
|
||||||
println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080);
|
|
||||||
println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080);
|
|
||||||
|
|
||||||
let is_alive_clone = Arc::clone(&is_alive);
|
println!("Service crashed due to unexpected Error, restarting thread after wait...");
|
||||||
let shutdown_clone = Arc::clone(&shutdown);
|
|
||||||
let _ = tokio::spawn(async move { postgres_watchdog(pool_copy, is_alive_clone, shutdown_clone).await });
|
|
||||||
|
|
||||||
//watchdog_thread.await;
|
|
||||||
|
|
||||||
while is_alive.load(Ordering::Relaxed) {
|
sleep(Duration::from_secs(10)).await;
|
||||||
let thread = tokio::spawn(async {
|
|
||||||
let _ = sleep(Duration::from_millis(100));
|
|
||||||
});
|
|
||||||
|
|
||||||
let _ = thread.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
if shutdown.load(Ordering::Relaxed) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
eprintln!("Connection died, restarting Server");
|
|
||||||
server_thread.abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
369
src/v1/mod.rs
Normal file
369
src/v1/mod.rs
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
use crate::{db, AppState};
|
||||||
|
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(req: &HttpRequest) -> Option<&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 = GetUserParams,
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "OK", body = User),
|
||||||
|
(status = 403, description = "Unauthorized"),
|
||||||
|
(status = 500, description = "Internal Server Error")
|
||||||
|
),
|
||||||
|
security(
|
||||||
|
("api_key" = [])
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
#[post("/api/v1/user")]
|
||||||
|
pub(crate) 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 user_permissions: HashMap<String, bool> = HashMap::new();
|
||||||
|
|
||||||
|
user_permissions.insert("game_permissions".to_string(), user.game_permissions);
|
||||||
|
user_permissions.insert("empire_permissions".to_string(), user.empire_permissions);
|
||||||
|
user_permissions.insert("data_permissions".to_string(), user.data_permissions);
|
||||||
|
user_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: user_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/create")]
|
||||||
|
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 user_permissions: HashMap<String, bool> = HashMap::new();
|
||||||
|
match params.permissions {
|
||||||
|
Some(data) => {user_permissions = data.clone()},
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut elevated_auth = false;
|
||||||
|
if user_permissions.len() != 0 {
|
||||||
|
if user_permissions["game_permissions"] || user_permissions["empire_permissions"] || user_permissions["data_permissions"] || user_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if user_permissions.len() != 0 {
|
||||||
|
for (entry, value) in user_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 user_permissions: HashMap<String, bool> = HashMap::new();
|
||||||
|
user_permissions.insert("game_permissions".to_string(), user.game_permissions);
|
||||||
|
user_permissions.insert("empire_permissions".to_string(), user.empire_permissions);
|
||||||
|
user_permissions.insert("data_permissions".to_string(), user.data_permissions);
|
||||||
|
user_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: user_permissions
|
||||||
|
};
|
||||||
|
return HttpResponse::Ok().json(return_data);
|
||||||
|
} else {
|
||||||
|
return HttpResponse::Unauthorized().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
request_body = 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(_) => {
|
||||||
|
return HttpResponse::InternalServerError().finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return HttpResponse::Ok().into();
|
||||||
|
} else {
|
||||||
|
return HttpResponse::Unauthorized().finish();
|
||||||
|
}
|
||||||
|
}
|
64
src/v1/schemas.rs
Normal file
64
src/v1/schemas.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use utoipa::{IntoParams, ToSchema};
|
||||||
|
|
||||||
|
// 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: Option<HashMap<String, bool>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema, Debug)]
|
||||||
|
pub struct DeleteUserParams {
|
||||||
|
#[schema(example = "abcdef")]
|
||||||
|
pub user_token: String,
|
||||||
|
}
|
|
@ -78,7 +78,7 @@ pub(crate) async fn empires(
|
||||||
|
|
||||||
if let Some(auth_token) = params.token.clone() {
|
if let Some(auth_token) = params.token.clone() {
|
||||||
if auth_token == data.auth_tokens.admin || auth_token == data.auth_tokens.moderator {
|
if auth_token == data.auth_tokens.admin || auth_token == data.auth_tokens.moderator {
|
||||||
new_data.discord_user = entry.discord_user.clone();
|
new_data.discord_user = Some("deprecated".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ pub(crate) async fn ethics(
|
||||||
db_data.iter().for_each(|entry| {
|
db_data.iter().for_each(|entry| {
|
||||||
let new_data = schemas::Ethic {
|
let new_data = schemas::Ethic {
|
||||||
id: entry.id,
|
id: entry.id,
|
||||||
machine_ethic: entry.machine_ethic,
|
gestalt_ethic: entry.gestalt_ethic,
|
||||||
name: entry.name.clone()
|
name: entry.name.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub struct GameGroup {
|
||||||
pub struct Ethic {
|
pub struct Ethic {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub machine_ethic: bool,
|
pub gestalt_ethic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
#[derive(Serialize, ToSchema, Debug, FromRow)]
|
||||||
|
|
185
src/v3/mod.rs
185
src/v3/mod.rs
|
@ -5,12 +5,11 @@ use actix_web::{
|
||||||
web::{self, Json},
|
web::{self, Json},
|
||||||
HttpRequest, HttpResponse, Responder,
|
HttpRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
use sqlx::{QueryBuilder};
|
use sqlx::QueryBuilder;
|
||||||
|
|
||||||
use crate::{
|
use dotenvy;
|
||||||
db::{self},
|
|
||||||
AppState,
|
use crate::{db, AppState};
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) mod schemas;
|
pub(crate) mod schemas;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ fn verify_auth(token: Option<&str>, data: &AppState) -> schemas::AuthReturn {
|
||||||
return auth_return;
|
return auth_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_auth_header<'a>(req: &'a HttpRequest) -> Option<&'a str> {
|
fn get_auth_header(req: &HttpRequest) -> Option<&str> {
|
||||||
req.headers().get("x-api-key")?.to_str().ok()
|
req.headers().get("x-api-key")?.to_str().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,37 +109,37 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
|
||||||
let mut parsed_data: schemas::FullViewData = schemas::FullViewData {
|
let mut parsed_data: schemas::FullViewData = schemas::FullViewData {
|
||||||
games: HashMap::new(),
|
games: HashMap::new(),
|
||||||
ethics: HashMap::new(),
|
ethics: HashMap::new(),
|
||||||
species: HashMap::new(),
|
phenotypes: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Data processing
|
// Data processing
|
||||||
// Species Vector
|
// Species Vector
|
||||||
db_portrait_groups.iter().for_each(|species| {
|
db_portrait_groups.iter().for_each(|species| {
|
||||||
let new_data = schemas::Species {
|
let new_data = schemas::Phenotype {
|
||||||
id: species.id,
|
id: species.id,
|
||||||
display: species.name.clone(),
|
display: species.name.clone(),
|
||||||
portraits: HashMap::new(),
|
species: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
parsed_data
|
parsed_data
|
||||||
.species
|
.phenotypes
|
||||||
.entry(species.id)
|
.entry(species.id)
|
||||||
.and_modify(|d| *d = new_data.clone())
|
.and_modify(|d| *d = new_data.clone())
|
||||||
.or_insert(new_data);
|
.or_insert(new_data);
|
||||||
});
|
});
|
||||||
|
|
||||||
db_portraits.iter().for_each(|portrait| {
|
db_portraits.iter().for_each(|portrait| {
|
||||||
let new_data = schemas::Portrait {
|
let new_data = schemas::Species {
|
||||||
id: portrait.id,
|
id: portrait.id,
|
||||||
hires: portrait.hires.clone(),
|
hires: portrait.hires.clone(),
|
||||||
lores: Some(portrait.lores.clone()),
|
lores: portrait.lores.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
parsed_data
|
parsed_data
|
||||||
.species
|
.phenotypes
|
||||||
.get_mut(&portrait.group_id)
|
.get_mut(&portrait.group_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.portraits
|
.species
|
||||||
.entry(portrait.id)
|
.entry(portrait.id)
|
||||||
.and_modify(|d| *d = new_data.clone())
|
.and_modify(|d| *d = new_data.clone())
|
||||||
.or_insert(new_data);
|
.or_insert(new_data);
|
||||||
|
@ -182,10 +181,10 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
|
||||||
let new_data = schemas::ChellarisEmpireLegacy {
|
let new_data = schemas::ChellarisEmpireLegacy {
|
||||||
id: empire.id,
|
id: empire.id,
|
||||||
gestalt: empire.gestalt,
|
gestalt: empire.gestalt,
|
||||||
machine: false,
|
machine: empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
|
||||||
group: empire.group_id,
|
group: empire.group_id,
|
||||||
empire_portrait: empire.portrait_id,
|
portrait_id: empire.portrait_id,
|
||||||
empire_portrait_group: empire.portrait_group_id,
|
portrait_group_id: empire.portrait_group_id,
|
||||||
discord_user: None,
|
discord_user: None,
|
||||||
ethics: HashMap::new(),
|
ethics: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
@ -205,7 +204,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
|
||||||
let new_data = schemas::Ethic {
|
let new_data = schemas::Ethic {
|
||||||
id: ethic.id,
|
id: ethic.id,
|
||||||
display: ethic.name.clone(),
|
display: ethic.name.clone(),
|
||||||
machine: ethic.machine_ethic,
|
gestalt: ethic.gestalt_ethic,
|
||||||
};
|
};
|
||||||
|
|
||||||
parsed_data
|
parsed_data
|
||||||
|
@ -222,11 +221,11 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
|
||||||
let new_data = schemas::EmpireEthicLegacy {
|
let new_data = schemas::EmpireEthicLegacy {
|
||||||
ethic_id: empire_ethic.ethics_id,
|
ethic_id: empire_ethic.ethics_id,
|
||||||
display: parsed_data.ethics[&empire_ethic.ethics_id].display.clone(),
|
display: parsed_data.ethics[&empire_ethic.ethics_id].display.clone(),
|
||||||
machine: parsed_data.ethics[&empire_ethic.ethics_id].machine,
|
gestalt: parsed_data.ethics[&empire_ethic.ethics_id].gestalt,
|
||||||
fanatic: empire_ethic.fanatic,
|
fanatic: empire_ethic.fanatic,
|
||||||
};
|
};
|
||||||
|
|
||||||
if new_data.machine {
|
if new_data.gestalt {
|
||||||
parsed_data
|
parsed_data
|
||||||
.games
|
.games
|
||||||
.get_mut(&game_id)
|
.get_mut(&game_id)
|
||||||
|
@ -234,7 +233,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
|
||||||
.empires
|
.empires
|
||||||
.get_mut(&id)
|
.get_mut(&id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.machine = true;
|
.gestalt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed_data
|
parsed_data
|
||||||
|
@ -368,7 +367,7 @@ pub(crate) async fn get_game_data(
|
||||||
"[REDACTED]".to_string()
|
"[REDACTED]".to_string()
|
||||||
},
|
},
|
||||||
discord_user: if user_auth.moderator || user_auth.admin {
|
discord_user: if user_auth.moderator || user_auth.admin {
|
||||||
empire.discord_user.clone()
|
Some("deprecated".to_string())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
@ -808,7 +807,8 @@ pub(crate) async fn get_empire(
|
||||||
group: db_empire.group_id,
|
group: db_empire.group_id,
|
||||||
game: db_empire.game_id,
|
game: db_empire.game_id,
|
||||||
name: db_empire.name,
|
name: db_empire.name,
|
||||||
discord_user: db_empire.discord_user,
|
discord_user: Some("deprecated".to_string()),
|
||||||
|
machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
|
||||||
gestalt: db_empire.gestalt,
|
gestalt: db_empire.gestalt,
|
||||||
portrait_id: db_empire.portrait_id,
|
portrait_id: db_empire.portrait_id,
|
||||||
portrait_group_id: db_empire.portrait_group_id,
|
portrait_group_id: db_empire.portrait_group_id,
|
||||||
|
@ -941,7 +941,8 @@ pub(crate) async fn create_empire(
|
||||||
group: db_empire.group_id,
|
group: db_empire.group_id,
|
||||||
game: db_empire.game_id,
|
game: db_empire.game_id,
|
||||||
name: db_empire.name,
|
name: db_empire.name,
|
||||||
discord_user: db_empire.discord_user,
|
discord_user: Some("deprecated".to_string()),
|
||||||
|
machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
|
||||||
gestalt: db_empire.gestalt,
|
gestalt: db_empire.gestalt,
|
||||||
portrait_id: db_empire.portrait_id,
|
portrait_id: db_empire.portrait_id,
|
||||||
portrait_group_id: db_empire.portrait_group_id,
|
portrait_group_id: db_empire.portrait_group_id,
|
||||||
|
@ -987,12 +988,10 @@ pub(crate) async fn edit_empire(
|
||||||
let mut db_empire_query = QueryBuilder::<sqlx::Postgres>::new("UPDATE public.empires SET ");
|
let mut db_empire_query = QueryBuilder::<sqlx::Postgres>::new("UPDATE public.empires SET ");
|
||||||
let mut db_empire_separated = db_empire_query.separated(", ");
|
let mut db_empire_separated = db_empire_query.separated(", ");
|
||||||
|
|
||||||
if let Some(new_game) = params.game_id {
|
// More often than not does nothing but is required to ensure data is handled properly
|
||||||
any_param_present = true;
|
db_empire_separated
|
||||||
db_empire_separated
|
.push(" game_id = ")
|
||||||
.push(" game_id = ")
|
.push_bind_unseparated(params.game_id);
|
||||||
.push_bind_unseparated(new_game);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(new_group) = params.group_id {
|
if let Some(new_group) = params.group_id {
|
||||||
any_param_present = true;
|
any_param_present = true;
|
||||||
|
@ -1038,6 +1037,12 @@ pub(crate) async fn edit_empire(
|
||||||
.push(" discord_user = ")
|
.push(" discord_user = ")
|
||||||
.push_bind_unseparated(new_discord_user);
|
.push_bind_unseparated(new_discord_user);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
any_param_present = true;
|
||||||
|
let val: Option<String> = None;
|
||||||
|
db_empire_separated
|
||||||
|
.push(" discord_user = ").push_bind_unseparated(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let db_empire: db::schemas::Empire;
|
let db_empire: db::schemas::Empire;
|
||||||
|
@ -1046,9 +1051,6 @@ pub(crate) async fn edit_empire(
|
||||||
db_empire_separated
|
db_empire_separated
|
||||||
.push_unseparated(" WHERE id = ")
|
.push_unseparated(" WHERE id = ")
|
||||||
.push_bind_unseparated(params.empire_id);
|
.push_bind_unseparated(params.empire_id);
|
||||||
db_empire_separated
|
|
||||||
.push_unseparated(" AND group_id = ")
|
|
||||||
.push_bind_unseparated(params.group_id);
|
|
||||||
db_empire_separated
|
db_empire_separated
|
||||||
.push_unseparated(" AND game_id = ")
|
.push_unseparated(" AND game_id = ")
|
||||||
.push_bind_unseparated(params.game_id);
|
.push_bind_unseparated(params.game_id);
|
||||||
|
@ -1071,9 +1073,6 @@ pub(crate) async fn edit_empire(
|
||||||
db_empire_separated
|
db_empire_separated
|
||||||
.push_unseparated(" WHERE id = ")
|
.push_unseparated(" WHERE id = ")
|
||||||
.push_bind_unseparated(params.empire_id);
|
.push_bind_unseparated(params.empire_id);
|
||||||
db_empire_separated
|
|
||||||
.push_unseparated(" AND group_id = ")
|
|
||||||
.push_bind_unseparated(params.group_id);
|
|
||||||
db_empire_separated
|
db_empire_separated
|
||||||
.push_unseparated(" AND game_id = ")
|
.push_unseparated(" AND game_id = ")
|
||||||
.push_bind_unseparated(params.game_id);
|
.push_bind_unseparated(params.game_id);
|
||||||
|
@ -1175,7 +1174,8 @@ pub(crate) async fn edit_empire(
|
||||||
group: db_empire.group_id,
|
group: db_empire.group_id,
|
||||||
game: db_empire.game_id,
|
game: db_empire.game_id,
|
||||||
name: db_empire.name,
|
name: db_empire.name,
|
||||||
discord_user: db_empire.discord_user,
|
discord_user: Some("deprecated".to_string()),
|
||||||
|
machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
|
||||||
gestalt: db_empire.gestalt,
|
gestalt: db_empire.gestalt,
|
||||||
portrait_id: db_empire.portrait_id,
|
portrait_id: db_empire.portrait_id,
|
||||||
portrait_group_id: db_empire.portrait_group_id,
|
portrait_group_id: db_empire.portrait_group_id,
|
||||||
|
@ -1235,9 +1235,110 @@ pub(crate) async fn delete_empire(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data Manipulation Endpoints
|
// Ethics Endpoints
|
||||||
|
// Data Manipulation Admin Only
|
||||||
|
|
||||||
// Admin
|
#[utoipa::path(
|
||||||
// Add/Update/Remove Portrait
|
responses(
|
||||||
// Add/Update/Remove Species
|
(status = 200, description = "OK", body = ChellarisEthics),
|
||||||
// Add/Update/Remove Ethics
|
),
|
||||||
|
)]
|
||||||
|
#[get("/api/v3/ethics")]
|
||||||
|
pub(crate) async fn get_ethics(data: web::Data<AppState>) -> impl Responder {
|
||||||
|
// SQL Queries
|
||||||
|
// TODO: Optimize by utilizing some SQL magic, for now this has to do
|
||||||
|
let mut db_ethics: HashMap<i32, schemas::Ethic> = HashMap::new();
|
||||||
|
|
||||||
|
let mut db_ethic_query = QueryBuilder::<sqlx::Postgres>::new("SELECT * FROM public.ethics");
|
||||||
|
|
||||||
|
match db_ethic_query
|
||||||
|
.build_query_as::<db::schemas::Ethic>()
|
||||||
|
.fetch_all(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => {
|
||||||
|
for ethic in data {
|
||||||
|
db_ethics.insert(
|
||||||
|
ethic.id,
|
||||||
|
schemas::Ethic {
|
||||||
|
id: ethic.id,
|
||||||
|
gestalt: ethic.gestalt_ethic,
|
||||||
|
display: ethic.name,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => return HttpResponse::UnprocessableEntity().body(format!("{:#?}", e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Empire Ethic Creation
|
||||||
|
let parsed_data: schemas::ChellarisEthics = schemas::ChellarisEthics { ethics: db_ethics };
|
||||||
|
|
||||||
|
return HttpResponse::Ok().json(parsed_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Species & Portrait Endpoints
|
||||||
|
// Data Manipulation Admin Only
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "OK", body = ChellarisPhenotypes),
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
#[get("/api/v3/phenotypes")]
|
||||||
|
pub(crate) async fn get_phenotypes(data: web::Data<AppState>) -> impl Responder {
|
||||||
|
// SQL Queries
|
||||||
|
// TODO: Optimize by utilizing some SQL magic, for now this has to do
|
||||||
|
let mut db_phenotypes: HashMap<i32, schemas::Phenotype> = HashMap::new();
|
||||||
|
|
||||||
|
let mut db_phenotype_query = QueryBuilder::<sqlx::Postgres>::new("SELECT * FROM public.portrait_groups");
|
||||||
|
|
||||||
|
match db_phenotype_query
|
||||||
|
.build_query_as::<db::schemas::PortraitGroup>()
|
||||||
|
.fetch_all(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => {
|
||||||
|
for phenotype in data {
|
||||||
|
db_phenotypes.insert(
|
||||||
|
phenotype.id,
|
||||||
|
schemas::Phenotype {
|
||||||
|
id: phenotype.id,
|
||||||
|
display: phenotype.name,
|
||||||
|
species: HashMap::new(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => return HttpResponse::UnprocessableEntity().body(format!("{:#?}", e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut db_species_query = QueryBuilder::<sqlx::Postgres>::new("SELECT * FROM public.portraits");
|
||||||
|
|
||||||
|
match db_species_query
|
||||||
|
.build_query_as::<db::schemas::Portrait>()
|
||||||
|
.fetch_all(&data.db)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(data) => {
|
||||||
|
for species in data {
|
||||||
|
if let Some(phenotype) = db_phenotypes.get_mut(&species.group_id) {
|
||||||
|
phenotype.species.insert(
|
||||||
|
species.id,
|
||||||
|
schemas::Species {
|
||||||
|
id: species.id,
|
||||||
|
hires: species.hires,
|
||||||
|
lores: species.lores
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => return HttpResponse::UnprocessableEntity().body(format!("{:#?}", e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Empire Ethic Creation
|
||||||
|
let parsed_data: schemas::ChellarisPhenotypes = schemas::ChellarisPhenotypes { phenotypes: db_phenotypes };
|
||||||
|
|
||||||
|
return HttpResponse::Ok().json(parsed_data);
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub struct DeleteGameParam {
|
||||||
pub struct FullViewData {
|
pub struct FullViewData {
|
||||||
pub games: HashMap<i32, ChellarisGameLegacy>,
|
pub games: HashMap<i32, ChellarisGameLegacy>,
|
||||||
pub ethics: HashMap<i32, Ethic>,
|
pub ethics: HashMap<i32, Ethic>,
|
||||||
pub species: HashMap<i32, Species>,
|
pub phenotypes: HashMap<i32, Phenotype>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, Clone)]
|
#[derive(Serialize, ToSchema, Debug, Clone)]
|
||||||
|
@ -147,7 +147,7 @@ pub struct UpdateEmpireParams {
|
||||||
#[schema(example = 1)]
|
#[schema(example = 1)]
|
||||||
pub empire_id: i32,
|
pub empire_id: i32,
|
||||||
#[schema(example = 1)]
|
#[schema(example = 1)]
|
||||||
pub game_id: Option<i32>,
|
pub game_id: i32,
|
||||||
#[schema(example = 1)]
|
#[schema(example = 1)]
|
||||||
pub group_id: Option<i32>,
|
pub group_id: Option<i32>,
|
||||||
#[schema(example = "Example Empire")]
|
#[schema(example = "Example Empire")]
|
||||||
|
@ -195,6 +195,7 @@ pub struct ChellarisEmpire {
|
||||||
pub game: i32,
|
pub game: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub discord_user: Option<String>,
|
pub discord_user: Option<String>,
|
||||||
|
pub machine: bool,
|
||||||
pub gestalt: bool,
|
pub gestalt: bool,
|
||||||
pub portrait_id: i32,
|
pub portrait_id: i32,
|
||||||
pub portrait_group_id: i32,
|
pub portrait_group_id: i32,
|
||||||
|
@ -207,17 +208,19 @@ pub struct ChellarisEmpireLegacy {
|
||||||
pub group: i32,
|
pub group: i32,
|
||||||
pub gestalt: bool,
|
pub gestalt: bool,
|
||||||
pub machine: bool,
|
pub machine: bool,
|
||||||
pub empire_portrait: i32,
|
pub portrait_id: i32,
|
||||||
pub empire_portrait_group: i32,
|
pub portrait_group_id: i32,
|
||||||
pub discord_user: Option<String>,
|
pub discord_user: Option<String>,
|
||||||
pub ethics: HashMap<i32, EmpireEthicLegacy>,
|
pub ethics: HashMap<i32, EmpireEthicLegacy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ethics Structs
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, Clone)]
|
#[derive(Serialize, ToSchema, Debug, Clone)]
|
||||||
pub struct Ethic {
|
pub struct Ethic {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub display: String,
|
pub display: String,
|
||||||
pub machine: bool,
|
pub gestalt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, ToSchema, Debug, Clone)]
|
#[derive(Serialize, Deserialize, ToSchema, Debug, Clone)]
|
||||||
|
@ -232,21 +235,33 @@ pub struct EmpireEthic {
|
||||||
pub struct EmpireEthicLegacy {
|
pub struct EmpireEthicLegacy {
|
||||||
pub ethic_id: i32,
|
pub ethic_id: i32,
|
||||||
pub display: String,
|
pub display: String,
|
||||||
pub machine: bool,
|
pub gestalt: bool,
|
||||||
pub fanatic: bool,
|
pub fanatic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema, Debug, Clone)]
|
||||||
|
pub struct ChellarisEthics {
|
||||||
|
pub ethics: HashMap<i32, Ethic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Species Structs
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema, Debug, Clone)]
|
||||||
|
pub struct Phenotype {
|
||||||
|
pub id: i32,
|
||||||
|
pub display: String,
|
||||||
|
pub species: HashMap<i32, Species>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema, Debug, Clone)]
|
||||||
|
pub struct ChellarisPhenotypes {
|
||||||
|
pub phenotypes: HashMap<i32, Phenotype>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, Clone)]
|
#[derive(Serialize, ToSchema, Debug, Clone)]
|
||||||
pub struct Species {
|
pub struct Species {
|
||||||
pub id: i32,
|
|
||||||
pub display: String,
|
|
||||||
pub portraits: HashMap<i32, Portrait>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema, Debug, Clone)]
|
|
||||||
pub struct Portrait {
|
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub hires: String,
|
pub hires: String,
|
||||||
pub lores: Option<String>,
|
pub lores: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
314
yarn.lock
314
yarn.lock
|
@ -1,314 +0,0 @@
|
||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
ajv@^6.1.1:
|
|
||||||
version "6.12.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
|
||||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
|
||||||
dependencies:
|
|
||||||
fast-deep-equal "^3.1.1"
|
|
||||||
fast-json-stable-stringify "^2.0.0"
|
|
||||||
json-schema-traverse "^0.4.1"
|
|
||||||
uri-js "^4.2.2"
|
|
||||||
|
|
||||||
async@^2.0.1:
|
|
||||||
version "2.6.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
|
|
||||||
integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.14"
|
|
||||||
|
|
||||||
bignumber.js@9.0.0:
|
|
||||||
version "9.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
|
|
||||||
integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==
|
|
||||||
|
|
||||||
bson@~1.0.4:
|
|
||||||
version "1.0.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/bson/-/bson-1.0.9.tgz#12319f8323b1254739b7c6bef8d3e89ae05a2f57"
|
|
||||||
integrity sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==
|
|
||||||
|
|
||||||
buffer-shims@~1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
|
|
||||||
integrity sha512-Zy8ZXMyxIT6RMTeY7OP/bDndfj6bwCan7SS98CEndS6deHwWPpseeHlwarNcBim+etXnF9HBc1non5JgDaJU1g==
|
|
||||||
|
|
||||||
core-util-is@~1.0.0:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
|
|
||||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
|
||||||
|
|
||||||
debug@*:
|
|
||||||
version "4.3.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
|
||||||
dependencies:
|
|
||||||
ms "2.1.2"
|
|
||||||
|
|
||||||
debug@^2.2.0:
|
|
||||||
version "2.6.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
|
||||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
|
||||||
dependencies:
|
|
||||||
ms "2.0.0"
|
|
||||||
|
|
||||||
double-ended-queue@^2.1.0-0:
|
|
||||||
version "2.1.0-0"
|
|
||||||
resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
|
|
||||||
integrity sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ==
|
|
||||||
|
|
||||||
es6-promise@3.2.1:
|
|
||||||
version "3.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.2.1.tgz#ec56233868032909207170c39448e24449dd1fc4"
|
|
||||||
integrity sha512-oj4jOSXvWglTsc3wrw86iom3LDPOx1nbipQk+jaG3dy+sMRM6ReSgVr/VlmBuF6lXUrflN9DCcQHeSbAwGUl4g==
|
|
||||||
|
|
||||||
fast-deep-equal@^3.1.1:
|
|
||||||
version "3.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
|
||||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
|
||||||
|
|
||||||
fast-json-stable-stringify@^2.0.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
|
||||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
|
||||||
|
|
||||||
inherits@~2.0.1, inherits@~2.0.3:
|
|
||||||
version "2.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
|
||||||
|
|
||||||
isarray@~1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
|
||||||
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
|
|
||||||
|
|
||||||
json-schema-traverse@^0.4.1:
|
|
||||||
version "0.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
|
||||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
|
||||||
|
|
||||||
lodash@^4.17.14, lodash@^4.17.4:
|
|
||||||
version "4.17.21"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
|
||||||
|
|
||||||
mongo-sql@^2.7.5:
|
|
||||||
version "2.7.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/mongo-sql/-/mongo-sql-2.7.8.tgz#f50184aaadc1be530db69e301ba35b01afd402d9"
|
|
||||||
integrity sha512-fJ4Tsn/G5QimXPRyoT0tnDhYdrPa/UJZY6FCJ4e9CYZgYH84w1qQrlednrpqgD9qK0oXtrLv78j1V+I5Yt/a6A==
|
|
||||||
|
|
||||||
mongodb-core@2.1.20:
|
|
||||||
version "2.1.20"
|
|
||||||
resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.20.tgz#fece8dd76b59ee7d7f2d313b65322c160492d8f1"
|
|
||||||
integrity sha512-IN57CX5/Q1bhDq6ShAR6gIv4koFsZP7L8WOK1S0lR0pVDQaScffSMV5jxubLsmZ7J+UdqmykKw4r9hG3XQEGgQ==
|
|
||||||
dependencies:
|
|
||||||
bson "~1.0.4"
|
|
||||||
require_optional "~1.0.0"
|
|
||||||
|
|
||||||
mongodb@^2.1.18:
|
|
||||||
version "2.2.36"
|
|
||||||
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.36.tgz#1c573680b2849fb0f47acbba3dc5fa228de975f5"
|
|
||||||
integrity sha512-P2SBLQ8Z0PVx71ngoXwo12+FiSfbNfGOClAao03/bant5DgLNkOPAck5IaJcEk4gKlQhDEURzfR3xuBG1/B+IA==
|
|
||||||
dependencies:
|
|
||||||
es6-promise "3.2.1"
|
|
||||||
mongodb-core "2.1.20"
|
|
||||||
readable-stream "2.2.7"
|
|
||||||
|
|
||||||
monk-middleware-cast-ids@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk-middleware-cast-ids/-/monk-middleware-cast-ids-0.2.1.tgz#40c40e5a6cb33ccedc289220943275ee8861c529"
|
|
||||||
integrity sha512-Hp9gwjXo+inSPhXUlsV1u3DyZh2cXT3Osij/1gSNCJQCgacAF1lfmnTj6bKmlf1Et4dvLhwUL0PquxdZRIofkA==
|
|
||||||
|
|
||||||
monk-middleware-fields@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk-middleware-fields/-/monk-middleware-fields-0.2.0.tgz#ff637af35f5948879ccb2be15a91360911bea6c1"
|
|
||||||
integrity sha512-pp+k0JeBX+HkIKnCisrtsW/QM2WGkOVG1Bd1qKLSanuBCf1l5khpdHrEullfko0HO6tCjCJMp//MsR16gd5tAw==
|
|
||||||
|
|
||||||
monk-middleware-handle-callback@^0.2.0:
|
|
||||||
version "0.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk-middleware-handle-callback/-/monk-middleware-handle-callback-0.2.2.tgz#47de6cc1248726c72a2be0c81bc4e68310c32146"
|
|
||||||
integrity sha512-5hBynb7asZ2uw9XVze7C3XH0zXT51yFDvYydk/5HnWWzh2NLglDSiKDcX0yLKPHzFgiq+5Z4Laq5fFVnFsmm8w==
|
|
||||||
|
|
||||||
monk-middleware-options@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk-middleware-options/-/monk-middleware-options-0.2.1.tgz#58dae1c518d46636ebdff506fadfc773bb442886"
|
|
||||||
integrity sha512-ypE0wGC8n5ARvOq2tlERr1uyu1edckeDRkheQLaXPRm9LoW7kr9P7xMGEjW2vmBh7IxnkpONVc7555X8x+34hQ==
|
|
||||||
|
|
||||||
monk-middleware-query@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk-middleware-query/-/monk-middleware-query-0.2.0.tgz#a926c677d4a5620c62151b0a56d0c0c151675874"
|
|
||||||
integrity sha512-BApd5HBiczJl1eVy65c9/NBVLtygBePFxuoHgar/LeMWCjWP9odSJk3vsnbxTnsOT1CMJ+hFysbaosLzDsxvtA==
|
|
||||||
|
|
||||||
monk-middleware-wait-for-connection@^0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk-middleware-wait-for-connection/-/monk-middleware-wait-for-connection-0.2.0.tgz#312958d30e588b57d09754dd7c97b4843316835a"
|
|
||||||
integrity sha512-jSTz73B/+pGTTvhu5Ym8xsG6+QqaWab53UXnXdNNlTijTdLvcHABCLJXudQiJxob5N1Mzr5EOSx5ziwn2sihPQ==
|
|
||||||
|
|
||||||
monk@^6.0.5:
|
|
||||||
version "6.0.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/monk/-/monk-6.0.6.tgz#2ff1cd57f001bba0fea73d1eea3952a7d35450c5"
|
|
||||||
integrity sha512-bSuADQGwIxBcRzCzQaMoGmiGl30Dr+0iB1FQAQb3VwWwAKbtpDN2wkVHCjthzw/jXhPHWxTQFUtlSt/nSagojQ==
|
|
||||||
dependencies:
|
|
||||||
debug "*"
|
|
||||||
mongodb "^2.1.18"
|
|
||||||
monk-middleware-cast-ids "^0.2.1"
|
|
||||||
monk-middleware-fields "^0.2.0"
|
|
||||||
monk-middleware-handle-callback "^0.2.0"
|
|
||||||
monk-middleware-options "^0.2.1"
|
|
||||||
monk-middleware-query "^0.2.0"
|
|
||||||
monk-middleware-wait-for-connection "^0.2.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
|
|
||||||
ms@2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
|
||||||
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
|
|
||||||
|
|
||||||
ms@2.1.2:
|
|
||||||
version "2.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
|
||||||
|
|
||||||
mysql@^2.11.1:
|
|
||||||
version "2.18.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717"
|
|
||||||
integrity sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==
|
|
||||||
dependencies:
|
|
||||||
bignumber.js "9.0.0"
|
|
||||||
readable-stream "2.3.7"
|
|
||||||
safe-buffer "5.1.2"
|
|
||||||
sqlstring "2.3.1"
|
|
||||||
|
|
||||||
object-assign@^4.1.1:
|
|
||||||
version "4.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
|
||||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
|
||||||
|
|
||||||
process-nextick-args@~1.0.6:
|
|
||||||
version "1.0.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
|
||||||
integrity sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==
|
|
||||||
|
|
||||||
process-nextick-args@~2.0.0:
|
|
||||||
version "2.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
|
||||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
|
||||||
|
|
||||||
punycode@^2.1.0:
|
|
||||||
version "2.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
|
||||||
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
|
|
||||||
|
|
||||||
readable-stream@2.2.7:
|
|
||||||
version "2.2.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.7.tgz#07057acbe2467b22042d36f98c5ad507054e95b1"
|
|
||||||
integrity sha512-a6ibcfWFhgihuTw/chl+u3fB5ykBZFmnvpyZHebY0MCQE4vvYcsCLpCeaQ1BkH7HdJYavNSqF0WDLeo4IPHQaQ==
|
|
||||||
dependencies:
|
|
||||||
buffer-shims "~1.0.0"
|
|
||||||
core-util-is "~1.0.0"
|
|
||||||
inherits "~2.0.1"
|
|
||||||
isarray "~1.0.0"
|
|
||||||
process-nextick-args "~1.0.6"
|
|
||||||
string_decoder "~1.0.0"
|
|
||||||
util-deprecate "~1.0.1"
|
|
||||||
|
|
||||||
readable-stream@2.3.7:
|
|
||||||
version "2.3.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
|
||||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
|
||||||
dependencies:
|
|
||||||
core-util-is "~1.0.0"
|
|
||||||
inherits "~2.0.3"
|
|
||||||
isarray "~1.0.0"
|
|
||||||
process-nextick-args "~2.0.0"
|
|
||||||
safe-buffer "~5.1.1"
|
|
||||||
string_decoder "~1.1.1"
|
|
||||||
util-deprecate "~1.0.1"
|
|
||||||
|
|
||||||
redis-commands@^1.2.0:
|
|
||||||
version "1.7.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89"
|
|
||||||
integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==
|
|
||||||
|
|
||||||
redis-parser@^2.6.0:
|
|
||||||
version "2.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b"
|
|
||||||
integrity sha512-9Hdw19gwXFBJdN8ENUoNVJFRyMDFrE/ZBClPicKYDPwNPJ4ST1TedAHYNSiGKElwh2vrmRGMoJYbVdJd+WQXIw==
|
|
||||||
|
|
||||||
redis@^2.8.0:
|
|
||||||
version "2.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02"
|
|
||||||
integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==
|
|
||||||
dependencies:
|
|
||||||
double-ended-queue "^2.1.0-0"
|
|
||||||
redis-commands "^1.2.0"
|
|
||||||
redis-parser "^2.6.0"
|
|
||||||
|
|
||||||
require_optional@~1.0.0:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
|
|
||||||
integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==
|
|
||||||
dependencies:
|
|
||||||
resolve-from "^2.0.0"
|
|
||||||
semver "^5.1.0"
|
|
||||||
|
|
||||||
resolve-from@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
|
|
||||||
integrity sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==
|
|
||||||
|
|
||||||
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|
||||||
version "5.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
|
||||||
|
|
||||||
semver@^5.1.0:
|
|
||||||
version "5.7.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
|
|
||||||
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
|
|
||||||
|
|
||||||
sqlstring@2.3.1:
|
|
||||||
version "2.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40"
|
|
||||||
integrity sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==
|
|
||||||
|
|
||||||
sqlx@^4.3.2:
|
|
||||||
version "4.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/sqlx/-/sqlx-4.3.2.tgz#e00e9c01543e776639b3622beee0b51f2e005b76"
|
|
||||||
integrity sha512-cKXn3T0fDhnX69F7556K0weGUYaBsmmtcIjTlj9OPQNxR56Lvil89pk5WntRR+h4IFFkrmKDg0yzl0YVsSDgbQ==
|
|
||||||
dependencies:
|
|
||||||
ajv "^6.1.1"
|
|
||||||
async "^2.0.1"
|
|
||||||
debug "^2.2.0"
|
|
||||||
lodash "^4.17.4"
|
|
||||||
mongo-sql "^2.7.5"
|
|
||||||
monk "^6.0.5"
|
|
||||||
mysql "^2.11.1"
|
|
||||||
redis "^2.8.0"
|
|
||||||
|
|
||||||
string_decoder@~1.0.0:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
|
|
||||||
integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==
|
|
||||||
dependencies:
|
|
||||||
safe-buffer "~5.1.0"
|
|
||||||
|
|
||||||
string_decoder@~1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
|
||||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
|
||||||
dependencies:
|
|
||||||
safe-buffer "~5.1.0"
|
|
||||||
|
|
||||||
uri-js@^4.2.2:
|
|
||||||
version "4.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
|
||||||
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
|
|
||||||
dependencies:
|
|
||||||
punycode "^2.1.0"
|
|
||||||
|
|
||||||
util-deprecate@~1.0.1:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
|
||||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
|
Reference in a new issue