From 93bded4afc94fbf7113aaf1fd12a7d3b5c89c2f3 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Thu, 7 Sep 2023 20:19:33 +0200
Subject: [PATCH 01/44] CI/CD Update

---
 .gitlab-ci.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 20c400c..d646058 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,6 +24,7 @@ build:
     CACHING: 
   script:
     - echo "Compiling the code..."
+    - export DATABASE_URL=$DATABASE_URL
     - cargo build -r
     - echo "Compile complete."
   after_script:

From 6ab4ae7244f10f45c9f1e530ca63a25e79197957 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Thu, 7 Sep 2023 20:24:11 +0200
Subject: [PATCH 02/44] Ci/CD Fix Attempt #2

---
 .gitlab-ci.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d646058..7621e9e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,7 +24,7 @@ build:
     CACHING: 
   script:
     - echo "Compiling the code..."
-    - export DATABASE_URL=$DATABASE_URL
+    - echo DATABASE_URL=$DATABASE_URL >> .env
     - cargo build -r
     - echo "Compile complete."
   after_script:

From cf36c8205bdc233ac923de80daf35ac5aa51146c Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Thu, 7 Sep 2023 20:33:47 +0200
Subject: [PATCH 03/44] Rust Version, Linting & CI Fix

---
 .gitlab-ci.yml | 2 +-
 Cargo.lock     | 2 +-
 Cargo.toml     | 2 +-
 src/db/mod.rs  | 4 ----
 src/main.rs    | 4 ++--
 src/v3/mod.rs  | 4 ++--
 6 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7621e9e..b92dca6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -30,7 +30,7 @@ build:
   after_script:
     - echo JOB_ID=$CI_JOB_ID >> job.env
     - mkdir ./artifacts
-    - cp /builds/Neshura/chellaris-rust-api/target/release/chellaris-rust-api ./artifacts/
+    - cp /builds/neshura-websites/chellaris-rust-api/target/release/chellaris-rust-api ./artifacts/
   artifacts:
     paths:
       - ./artifacts/
diff --git a/Cargo.lock b/Cargo.lock
index 93c78fa..6870a7e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -398,7 +398,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chellaris-rust-api"
-version = "0.1.0"
+version = "1.0.3"
 dependencies = [
  "actix-web",
  "chrono",
diff --git a/Cargo.toml b/Cargo.toml
index 4d071ee..f0b7398 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "chellaris-rust-api"
-version = "0.1.0"
+version = "1.0.3"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 7c8e632..0f2302c 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -1,5 +1 @@
-use std::error::Error;
-
-use sqlx::{Postgres, postgres::PgConnectOptions, PgPool, Pool};
-
 pub(crate) mod schemas;
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index d8da6f8..8cc7c09 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,7 +5,7 @@ extern crate dotenv;
 use dotenv::dotenv;
 use tokio::time::sleep;
 
-use std::{env, error::Error, fs, net::Ipv4Addr, net::Ipv6Addr, thread, time::Duration, sync::{Mutex, Arc, atomic::{AtomicBool, Ordering}}};
+use std::{env, fs, net::Ipv4Addr, net::Ipv6Addr, time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering}}};
 
 use chrono::Local;
 
@@ -266,7 +266,7 @@ async fn main() -> Result<()> {
 
         while is_alive.load(Ordering::Relaxed) {
             let thread = tokio::spawn(async {
-                sleep(Duration::from_millis(100));
+                let _ = sleep(Duration::from_millis(100));
             });
 
             let _ = thread.await;
diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 980e772..7769a5b 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -5,10 +5,10 @@ use actix_web::{
     web::{self, Json},
     HttpRequest, HttpResponse, Responder,
 };
-use sqlx::{Execute, QueryBuilder};
+use sqlx::{QueryBuilder};
 
 use crate::{
-    db::{self, schemas::EmpireEthic},
+    db::{self},
     AppState,
 };
 

From 849b82cef4b88bd1250cdab3a665ca3a87cccf41 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Thu, 7 Sep 2023 21:54:52 +0200
Subject: [PATCH 04/44] schema change for compat reasons on frontend

---
 src/v3/mod.rs     | 2 +-
 src/v3/schemas.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 7769a5b..4cf27be 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -220,7 +220,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let id = empire_ethic.empire_id;
 
         let new_data = schemas::EmpireEthicLegacy {
-            id: empire_ethic.ethics_id,
+            ethic_id: empire_ethic.ethics_id,
             display: parsed_data.ethics[&empire_ethic.ethics_id].display.clone(),
             machine: parsed_data.ethics[&empire_ethic.ethics_id].machine,
             fanatic: empire_ethic.fanatic,
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index 2a25b96..d8ec992 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -230,7 +230,7 @@ pub struct EmpireEthic {
 
 #[derive(Serialize, ToSchema, Debug, Clone)]
 pub struct EmpireEthicLegacy {
-    pub id: i32,
+    pub ethic_id: i32,
     pub display: String,
     pub machine: bool,
     pub fanatic: bool,

From d91af52811ebb8c1a1b4ce7fef7992a899cc1daf Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Thu, 7 Sep 2023 22:00:20 +0200
Subject: [PATCH 05/44] Portrait Renaming on Full View Structs

---
 src/v3/mod.rs     | 4 ++--
 src/v3/schemas.rs | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 4cf27be..b95ab27 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -184,8 +184,8 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
             gestalt: empire.gestalt,
             machine: false,
             group: empire.group_id,
-            empire_portrait: empire.portrait_id,
-            empire_portrait_group: empire.portrait_group_id,
+            portrait_id: empire.portrait_id,
+            portrait_group_id: empire.portrait_group_id,
             discord_user: None,
             ethics: HashMap::new(),
         };
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index d8ec992..8ff7e60 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -207,8 +207,8 @@ pub struct ChellarisEmpireLegacy {
     pub group: i32,
     pub gestalt: bool,
     pub machine: bool,
-    pub empire_portrait: i32,
-    pub empire_portrait_group: i32,
+    pub portrait_id: i32,
+    pub portrait_group_id: i32,
     pub discord_user: Option<String>,
     pub ethics: HashMap<i32, EmpireEthicLegacy>,
 }

From 097b6884b9838c6d42f7d23545cec0985bb35c31 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Fri, 8 Sep 2023 22:55:17 +0200
Subject: [PATCH 06/44] Ethics & Phenotype Endpoints + Phenotype Renaming

---
 .gitlab-ci.yml    |   1 +
 src/db/schemas.rs |   2 +-
 src/main.rs       |  12 +++-
 src/v2/mod.rs     |   2 +-
 src/v2/schemas.rs |   2 +-
 src/v3/mod.rs     | 147 ++++++++++++++++++++++++++++++++++++++--------
 src/v3/schemas.rs |  38 ++++++++----
 7 files changed, 163 insertions(+), 41 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b92dca6..4580c75 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -25,6 +25,7 @@ build:
   script:
     - echo "Compiling the code..."
     - echo DATABASE_URL=$DATABASE_URL >> .env
+    - echo MACHINE_GROUP_ID=12 >> .env
     - cargo build -r
     - echo "Compile complete."
   after_script:
diff --git a/src/db/schemas.rs b/src/db/schemas.rs
index 88525ad..0978e56 100644
--- a/src/db/schemas.rs
+++ b/src/db/schemas.rs
@@ -33,7 +33,7 @@ pub struct GameGroup {
 pub struct Ethic {
     pub id: i32,
     pub name: String,
-    pub machine_ethic: bool,
+    pub gestalt_ethic: bool,
 }
 
 #[derive(Serialize, ToSchema, Debug, FromRow)]
diff --git a/src/main.rs b/src/main.rs
index 8cc7c09..28b5ef2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -148,7 +148,9 @@ async fn main() -> Result<()> {
             v3::get_empire,
             v3::create_empire,
             v3::edit_empire,
-            v3::delete_empire
+            v3::delete_empire,
+            v3::get_ethics,
+            v3::get_phenotypes
         ), 
         components(schemas(
             v3::schemas::AuthReturn,
@@ -165,15 +167,17 @@ async fn main() -> Result<()> {
             v3::schemas::DeleteEmpireParams,
             v3::schemas::FullViewData,
             v3::schemas::Ethic,
+            v3::schemas::ChellarisEthics,
             v3::schemas::EmpireEthic,
             v3::schemas::EmpireEthicLegacy,
             v3::schemas::ChellarisGameLegacy,
             v3::schemas::ChellarisGameFlat,
             v3::schemas::ChellarisGame,
-            v3::schemas::Species,
+            v3::schemas::Phenotype,
+            v3::schemas::ChellarisPhenotypes,
             v3::schemas::ChellarisGameGroupLegacy,
             v3::schemas::ChellarisGroupFlat,
-            v3::schemas::Portrait,
+            v3::schemas::Species,
             v3::schemas::ChellarisEmpireLegacy,
             v3::schemas::ChellarisEmpireFlat,
             v3::schemas::ChellarisEmpire
@@ -229,6 +233,8 @@ async fn main() -> Result<()> {
                 .service(v3::create_empire)
                 .service(v3::edit_empire)
                 .service(v3::delete_empire)
+                .service(v3::get_ethics)
+                .service(v3::get_phenotypes)
                 // Swagger UI
                 .service(
                     SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
diff --git a/src/v2/mod.rs b/src/v2/mod.rs
index 9f37731..8cff9c5 100644
--- a/src/v2/mod.rs
+++ b/src/v2/mod.rs
@@ -112,7 +112,7 @@ pub(crate) async fn ethics(
     db_data.iter().for_each(|entry| {
         let new_data = schemas::Ethic {
             id: entry.id,
-            machine_ethic: entry.machine_ethic,
+            gestalt_ethic: entry.gestalt_ethic,
             name: entry.name.clone()
         };
 
diff --git a/src/v2/schemas.rs b/src/v2/schemas.rs
index e575885..69897e0 100644
--- a/src/v2/schemas.rs
+++ b/src/v2/schemas.rs
@@ -38,7 +38,7 @@ pub struct GameGroup {
 pub struct Ethic {
     pub id: i32,
     pub name: String,
-    pub machine_ethic: bool,
+    pub gestalt_ethic: bool,
 }
 
 #[derive(Serialize, ToSchema, Debug, FromRow)]
diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index b95ab27..9d56bce 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -5,12 +5,9 @@ use actix_web::{
     web::{self, Json},
     HttpRequest, HttpResponse, Responder,
 };
-use sqlx::{QueryBuilder};
+use sqlx::QueryBuilder;
 
-use crate::{
-    db::{self},
-    AppState,
-};
+use crate::{db, AppState};
 
 pub(crate) mod schemas;
 
@@ -110,37 +107,37 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
     let mut parsed_data: schemas::FullViewData = schemas::FullViewData {
         games: HashMap::new(),
         ethics: HashMap::new(),
-        species: HashMap::new(),
+        phenotypes: HashMap::new(),
     };
 
     // Data processing
     // Species Vector
     db_portrait_groups.iter().for_each(|species| {
-        let new_data = schemas::Species {
+        let new_data = schemas::Phenotype {
             id: species.id,
             display: species.name.clone(),
-            portraits: HashMap::new(),
+            species: HashMap::new(),
         };
 
         parsed_data
-            .species
+            .phenotypes
             .entry(species.id)
             .and_modify(|d| *d = new_data.clone())
             .or_insert(new_data);
     });
 
     db_portraits.iter().for_each(|portrait| {
-        let new_data = schemas::Portrait {
+        let new_data = schemas::Species {
             id: portrait.id,
             hires: portrait.hires.clone(),
-            lores: Some(portrait.lores.clone()),
+            lores: portrait.lores.clone(),
         };
 
         parsed_data
-            .species
+            .phenotypes
             .get_mut(&portrait.group_id)
             .unwrap()
-            .portraits
+            .species
             .entry(portrait.id)
             .and_modify(|d| *d = new_data.clone())
             .or_insert(new_data);
@@ -182,7 +179,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let new_data = schemas::ChellarisEmpireLegacy {
             id: empire.id,
             gestalt: empire.gestalt,
-            machine: false,
+            machine: empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
             group: empire.group_id,
             portrait_id: empire.portrait_id,
             portrait_group_id: empire.portrait_group_id,
@@ -205,7 +202,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let new_data = schemas::Ethic {
             id: ethic.id,
             display: ethic.name.clone(),
-            machine: ethic.machine_ethic,
+            gestalt: ethic.gestalt_ethic,
         };
 
         parsed_data
@@ -222,11 +219,11 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let new_data = schemas::EmpireEthicLegacy {
             ethic_id: empire_ethic.ethics_id,
             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,
         };
 
-        if new_data.machine {
+        if new_data.gestalt {
             parsed_data
                 .games
                 .get_mut(&game_id)
@@ -234,7 +231,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
                 .empires
                 .get_mut(&id)
                 .unwrap()
-                .machine = true;
+                .gestalt = true;
         }
 
         parsed_data
@@ -1235,9 +1232,113 @@ pub(crate) async fn delete_empire(
     }
 }
 
-// Data Manipulation Endpoints
+// Ethics Endpoints
+// Data Manipulation Admin Only
 
-// Admin
-// Add/Update/Remove Portrait
-// Add/Update/Remove Species
-// Add/Update/Remove Ethics
+#[utoipa::path(
+    responses(
+        (status = 200, description = "OK", body = ChellarisEthics),
+    ),
+)]
+#[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),
+    ),
+    security(
+        ("api_key" = [])
+    ),
+)]
+#[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);
+}
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index 8ff7e60..7320358 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -1,4 +1,4 @@
-use std::{collections::HashMap};
+use std::{collections::HashMap, hash::Hash};
 
 use serde::{Serialize, Deserialize};
 use utoipa::{ToSchema, IntoParams};
@@ -43,7 +43,7 @@ pub struct DeleteGameParam {
 pub struct FullViewData {
     pub games: HashMap<i32, ChellarisGameLegacy>,
     pub ethics: HashMap<i32, Ethic>,
-    pub species: HashMap<i32, Species>,
+    pub phenotypes: HashMap<i32, Phenotype>,
 }
 
 #[derive(Serialize, ToSchema, Debug, Clone)]
@@ -213,11 +213,13 @@ pub struct ChellarisEmpireLegacy {
     pub ethics: HashMap<i32, EmpireEthicLegacy>,
 }
 
+// Ethics Structs
+
 #[derive(Serialize, ToSchema, Debug, Clone)]
 pub struct Ethic {
     pub id: i32,
     pub display: String,
-    pub machine: bool,
+    pub gestalt: bool,
 }
 
 #[derive(Serialize, Deserialize, ToSchema, Debug, Clone)]
@@ -232,21 +234,33 @@ pub struct EmpireEthic {
 pub struct EmpireEthicLegacy {
     pub ethic_id: i32,
     pub display: String,
-    pub machine: bool,
+    pub gestalt: 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)]
 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 hires: String,
-    pub lores: Option<String>,
+    pub lores: String,
 }
 

From 464f870c29db22c14687ef1f66a42971168351cb Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Fri, 8 Sep 2023 23:06:56 +0200
Subject: [PATCH 07/44] Added machine field on empire routes

---
 src/v3/mod.rs     | 3 +++
 src/v3/schemas.rs | 1 +
 2 files changed, 4 insertions(+)

diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 9d56bce..3e4c361 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -806,6 +806,7 @@ pub(crate) async fn get_empire(
             game: db_empire.game_id,
             name: db_empire.name,
             discord_user: db_empire.discord_user,
+            machine: db_empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
             gestalt: db_empire.gestalt,
             portrait_id: db_empire.portrait_id,
             portrait_group_id: db_empire.portrait_group_id,
@@ -939,6 +940,7 @@ pub(crate) async fn create_empire(
                 game: db_empire.game_id,
                 name: db_empire.name,
                 discord_user: db_empire.discord_user,
+                machine: db_empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
                 gestalt: db_empire.gestalt,
                 portrait_id: db_empire.portrait_id,
                 portrait_group_id: db_empire.portrait_group_id,
@@ -1173,6 +1175,7 @@ pub(crate) async fn edit_empire(
                 game: db_empire.game_id,
                 name: db_empire.name,
                 discord_user: db_empire.discord_user,
+                machine: db_empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
                 gestalt: db_empire.gestalt,
                 portrait_id: db_empire.portrait_id,
                 portrait_group_id: db_empire.portrait_group_id,
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index 7320358..df628d7 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -195,6 +195,7 @@ pub struct ChellarisEmpire {
     pub game: i32,
     pub name: String,
     pub discord_user: Option<String>,
+    pub machine: bool,
     pub gestalt: bool,
     pub portrait_id: i32,
     pub portrait_group_id: i32,

From 5a557d262b3b4abd831e79efd39048ad62c93db1 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 9 Sep 2023 01:04:01 +0200
Subject: [PATCH 08/44] Minor API Fixes

---
 src/v3/mod.rs     | 19 ++++---------------
 src/v3/schemas.rs |  2 +-
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 3e4c361..53122c3 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -986,12 +986,10 @@ pub(crate) async fn edit_empire(
         let mut db_empire_query = QueryBuilder::<sqlx::Postgres>::new("UPDATE public.empires SET ");
         let mut db_empire_separated = db_empire_query.separated(", ");
 
-        if let Some(new_game) = params.game_id {
-            any_param_present = true;
-            db_empire_separated
-                .push(" game_id = ")
-                .push_bind_unseparated(new_game);
-        }
+        // More often than not does nothing but is required to ensure data is handled properly
+        db_empire_separated
+            .push(" game_id = ")
+            .push_bind_unseparated(params.game_id);
 
         if let Some(new_group) = params.group_id {
             any_param_present = true;
@@ -1045,9 +1043,6 @@ pub(crate) async fn edit_empire(
             db_empire_separated
                 .push_unseparated(" WHERE id = ")
                 .push_bind_unseparated(params.empire_id);
-            db_empire_separated
-                .push_unseparated(" AND group_id = ")
-                .push_bind_unseparated(params.group_id);
             db_empire_separated
                 .push_unseparated(" AND game_id = ")
                 .push_bind_unseparated(params.game_id);
@@ -1070,9 +1065,6 @@ pub(crate) async fn edit_empire(
             db_empire_separated
                 .push_unseparated(" WHERE id = ")
                 .push_bind_unseparated(params.empire_id);
-            db_empire_separated
-                .push_unseparated(" AND group_id = ")
-                .push_bind_unseparated(params.group_id);
             db_empire_separated
                 .push_unseparated(" AND game_id = ")
                 .push_bind_unseparated(params.game_id);
@@ -1284,9 +1276,6 @@ pub(crate) async fn get_ethics(data: web::Data<AppState>) -> impl Responder {
     responses(
         (status = 200, description = "OK", body = ChellarisPhenotypes),
     ),
-    security(
-        ("api_key" = [])
-    ),
 )]
 #[get("/api/v3/phenotypes")]
 pub(crate) async fn get_phenotypes(data: web::Data<AppState>) -> impl Responder {
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index df628d7..847bccc 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -147,7 +147,7 @@ pub struct UpdateEmpireParams {
     #[schema(example = 1)]
     pub empire_id: i32,
     #[schema(example = 1)]
-    pub game_id: Option<i32>,
+    pub game_id: i32,
     #[schema(example = 1)]
     pub group_id: Option<i32>,
     #[schema(example = "Example Empire")]

From 97bae3be1a9e8f2b48a4114e6f17977e2e118f7c Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 9 Sep 2023 02:11:43 +0200
Subject: [PATCH 09/44] Make Discord Usernames Nullable

---
 src/v3/mod.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 53122c3..d35861c 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -1035,6 +1035,11 @@ pub(crate) async fn edit_empire(
                     .push(" discord_user = ")
                     .push_bind_unseparated(new_discord_user);
             }
+            else {
+                any_param_present = true;
+                db_empire_separated
+                    .push(" discord_user = NONE");
+            }
         }
 
         let db_empire: db::schemas::Empire;

From 719cbbaf3a33e53bb10458fd89d810a359c4e6cd Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sat, 9 Sep 2023 02:21:49 +0200
Subject: [PATCH 10/44] Unify Handling of Setting to Null on DB

---
 src/v3/mod.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index d35861c..c1433c5 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -1037,8 +1037,9 @@ pub(crate) async fn edit_empire(
             }
             else {
                 any_param_present = true;
+                let val: Option<String> = None;
                 db_empire_separated
-                    .push(" discord_user = NONE");
+                    .push(" discord_user = ").push_bind_unseparated(val);
             }
         }
 

From 2ac5931c79860dbaa7dd89459c25866978e51b56 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Sep 2023 20:31:46 +0200
Subject: [PATCH 11/44] Swap dotenv for dotenvy, added uptime kuma url config

---
 .gitlab-ci.yml |   1 +
 Cargo.lock     | 325 +++++++++++++++++++++++++++++++++++++++++++------
 Cargo.toml     |   5 +-
 src/main.rs    |  35 ++++--
 src/v3/mod.rs  |  10 +-
 5 files changed, 325 insertions(+), 51 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4580c75..41b046d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -26,6 +26,7 @@ build:
     - echo "Compiling the code..."
     - echo DATABASE_URL=$DATABASE_URL >> .env
     - echo MACHINE_GROUP_ID=12 >> .env
+    - echo UPTIME_KUMA_URL= >> .env
     - cargo build -r
     - echo "Compile complete."
   after_script:
diff --git a/Cargo.lock b/Cargo.lock
index 6870a7e..c226b77 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -403,9 +403,10 @@ dependencies = [
  "actix-web",
  "chrono",
  "ctrlc",
- "dotenv",
- "dotenv_codegen",
+ "dotenvy",
+ "dotenvy_macro",
  "env_logger",
+ "reqwest",
  "schemars",
  "serde",
  "serde_json",
@@ -454,6 +455,16 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.4"
@@ -594,41 +605,24 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "dotenv"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
-
-[[package]]
-name = "dotenv_codegen"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56966279c10e4f8ee8c22123a15ed74e7c8150b658b26c619c53f4a56eb4a8aa"
-dependencies = [
- "dotenv_codegen_implementation",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "dotenv_codegen_implementation"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e737a3522cd45f6adc19b644ce43ef53e1e9045f2d2de425c1f468abd4cf33"
-dependencies = [
- "dotenv",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "dotenvy"
 version = "0.15.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
 
+[[package]]
+name = "dotenvy_macro"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb0235d912a8c749f4e0c9f18ca253b4c28cfefc1d2518096016d6e3230b6424"
+dependencies = [
+ "dotenvy",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "dyn-clone"
 version = "1.0.13"
@@ -744,6 +738,21 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
 [[package]]
 name = "form_urlencoded"
 version = "1.2.0"
@@ -955,6 +964,17 @@ dependencies = [
  "itoa",
 ]
 
+[[package]]
+name = "http-body"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
 [[package]]
 name = "httparse"
 version = "1.8.0"
@@ -973,6 +993,43 @@ version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
+[[package]]
+name = "hyper"
+version = "0.14.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2 0.4.9",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
 [[package]]
 name = "iana-time-zone"
 version = "0.1.57"
@@ -1027,6 +1084,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "ipnet"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
+
 [[package]]
 name = "is-terminal"
 version = "0.4.9"
@@ -1207,6 +1270,24 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "native-tls"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
 [[package]]
 name = "nix"
 version = "0.26.2"
@@ -1302,6 +1383,50 @@ version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
+[[package]]
+name = "openssl"
+version = "0.10.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
+dependencies = [
+ "bitflags 2.4.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.29",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "parking_lot"
 version = "0.12.1"
@@ -1435,12 +1560,6 @@ dependencies = [
  "version_check",
 ]
 
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
-
 [[package]]
 name = "proc-macro2"
 version = "1.0.66"
@@ -1547,6 +1666,43 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
 
+[[package]]
+name = "reqwest"
+version = "0.11.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
 [[package]]
 name = "rsa"
 version = "0.9.2"
@@ -1647,6 +1803,15 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "schannel"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
+dependencies = [
+ "windows-sys",
+]
+
 [[package]]
 name = "schemars"
 version = "0.8.12"
@@ -1677,6 +1842,29 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
+[[package]]
+name = "security-framework"
+version = "2.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "semver"
 version = "1.0.18"
@@ -2219,6 +2407,16 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-stream"
 version = "0.1.14"
@@ -2278,6 +2476,12 @@ dependencies = [
  "winnow",
 ]
 
+[[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
 [[package]]
 name = "tracing"
 version = "0.1.37"
@@ -2311,6 +2515,12 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "try-lock"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+
 [[package]]
 name = "typenum"
 version = "1.16.0"
@@ -2433,6 +2643,15 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
 [[package]]
 name = "wasi"
 version = "0.10.0+wasi-snapshot-preview1"
@@ -2470,6 +2689,18 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.87"
@@ -2499,6 +2730,16 @@ version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
+[[package]]
+name = "web-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "whoami"
 version = "1.4.1"
@@ -2620,6 +2861,16 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "winreg"
+version = "0.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
+dependencies = [
+ "cfg-if",
+ "windows-sys",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.6.0"
diff --git a/Cargo.toml b/Cargo.toml
index f0b7398..8d13671 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,9 +9,10 @@ edition = "2021"
 actix-web = "4.3.1"
 chrono = "0.4.26"
 ctrlc = "3.4.0"
-dotenv = "0.15.0"
-dotenv_codegen = "0.15.0"
+dotenvy = "0.15.7"
+dotenvy_macro = "0.15.7"
 env_logger = "0.10.0"
+reqwest = "0.11.20"
 schemars = "0.8.10"
 serde = { version = "1.0.185", features = ["derive"] }
 serde_json = "1.0.105"
diff --git a/src/main.rs b/src/main.rs
index 28b5ef2..35cbfa3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,8 @@
 #[macro_use]
-extern crate dotenv_codegen;
-extern crate dotenv;
+extern crate dotenvy_macro;
+extern crate dotenvy;
 
-use dotenv::dotenv;
+use dotenvy::dotenv;
 use tokio::time::sleep;
 
 use std::{env, fs, net::Ipv4Addr, net::Ipv6Addr, time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering}}};
@@ -55,9 +55,6 @@ pub struct AppState {
 
 async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Arc<AtomicBool>) {
     loop {
-        if shutdown.load(Ordering::Relaxed) {
-            break;
-        }
         let start = Local::now();
 
         let mut conn = match pool.acquire().await {
@@ -70,9 +67,31 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Ar
             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;
+
+        let passed = (Local::now() - start).to_std().expect(&format!("Unable to get Time Difference for '{}' and '{}'", start, Local::now()));
+
+        while Local::now() - start < chrono::Duration::seconds(15) {
+            sleep(Duration::from_millis(100)).await;
+            if shutdown.load(Ordering::Relaxed) {
+                break;
+            }
+        }
+        if shutdown.load(Ordering::Relaxed) {
+            break;
+        }
     }
     is_alive.store(false, Ordering::Relaxed);
 }
diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index c1433c5..bf27705 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -7,6 +7,8 @@ use actix_web::{
 };
 use sqlx::QueryBuilder;
 
+use dotenvy;
+
 use crate::{db, AppState};
 
 pub(crate) mod schemas;
@@ -179,7 +181,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let new_data = schemas::ChellarisEmpireLegacy {
             id: empire.id,
             gestalt: empire.gestalt,
-            machine: empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
+            machine: empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
             group: empire.group_id,
             portrait_id: empire.portrait_id,
             portrait_group_id: empire.portrait_group_id,
@@ -806,7 +808,7 @@ pub(crate) async fn get_empire(
             game: db_empire.game_id,
             name: db_empire.name,
             discord_user: db_empire.discord_user,
-            machine: db_empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
+            machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
             gestalt: db_empire.gestalt,
             portrait_id: db_empire.portrait_id,
             portrait_group_id: db_empire.portrait_group_id,
@@ -940,7 +942,7 @@ pub(crate) async fn create_empire(
                 game: db_empire.game_id,
                 name: db_empire.name,
                 discord_user: db_empire.discord_user,
-                machine: db_empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
+                machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
                 gestalt: db_empire.gestalt,
                 portrait_id: db_empire.portrait_id,
                 portrait_group_id: db_empire.portrait_group_id,
@@ -1173,7 +1175,7 @@ pub(crate) async fn edit_empire(
                 game: db_empire.game_id,
                 name: db_empire.name,
                 discord_user: db_empire.discord_user,
-                machine: db_empire.portrait_group_id.to_string() == dotenv!("MACHINE_GROUP_ID"),
+                machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
                 gestalt: db_empire.gestalt,
                 portrait_id: db_empire.portrait_id,
                 portrait_group_id: db_empire.portrait_group_id,

From 817f7770595f42f0acb43d3389e77757477059c4 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Sep 2023 20:34:53 +0200
Subject: [PATCH 12/44] Move Port Number to Config.toml

---
 src/main.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/main.rs b/src/main.rs
index 35cbfa3..707754c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -40,6 +40,12 @@ macro_rules! api_base_3 {
 #[derive(Serialize, Deserialize, Debug, Clone)]
 pub(crate) struct ConfigToml {
     auth: AuthenticationTokens,
+    port: PortConfig,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub(crate) struct PortConfig {
+    default: u16,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -270,7 +276,7 @@ async fn main() -> Result<()> {
                         .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();
 
         let server_thread = tokio::spawn(async {

From ebbaed09737527ed78af1297359d435e0aa4efb4 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sun, 17 Sep 2023 20:11:06 +0200
Subject: [PATCH 13/44] Reduce load by not constantly spawning new threads for
 sleeping

---
 src/main.rs | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 707754c..239a703 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -86,9 +86,6 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Ar
             println!("No Uptime Kuma URL provided!");
         }
         
-
-        let passed = (Local::now() - start).to_std().expect(&format!("Unable to get Time Difference for '{}' and '{}'", start, Local::now()));
-
         while Local::now() - start < chrono::Duration::seconds(15) {
             sleep(Duration::from_millis(100)).await;
             if shutdown.load(Ordering::Relaxed) {
@@ -296,11 +293,7 @@ async fn main() -> Result<()> {
         //watchdog_thread.await;
 
         while is_alive.load(Ordering::Relaxed) {
-            let thread = tokio::spawn(async {
-                let _ = sleep(Duration::from_millis(100));
-            });
-
-            let _ = thread.await;
+            sleep(Duration::from_millis(200)).await;
         }
 
         if shutdown.load(Ordering::Relaxed) {

From f4e5503d0b89d416394cea435a56eb67d9c877ab Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sun, 17 Sep 2023 22:49:37 +0200
Subject: [PATCH 14/44] Remove erroneous package.json and yarn.lock

---
 .gitignore   |   2 +
 package.json |   5 -
 yarn.lock    | 314 ---------------------------------------------------
 3 files changed, 2 insertions(+), 319 deletions(-)
 delete mode 100644 package.json
 delete mode 100644 yarn.lock

diff --git a/.gitignore b/.gitignore
index ecdc5b9..14602bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 /target
+/.vscode
+/.idea
 
 config.toml
 
diff --git a/package.json b/package.json
deleted file mode 100644
index 2bb8783..0000000
--- a/package.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "dependencies": {
-    "sqlx": "^4.3.2"
-  }
-}
diff --git a/yarn.lock b/yarn.lock
deleted file mode 100644
index a2e0510..0000000
--- a/yarn.lock
+++ /dev/null
@@ -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==

From 4213c550b8542730e0af77b19e12459c0f608f1a Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Fri, 17 Nov 2023 11:33:57 +0000
Subject: [PATCH 15/44] Add Test Workflow

---
 .forgejo/workflows/test.yml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 .forgejo/workflows/test.yml

diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml
new file mode 100644
index 0000000..637f42a
--- /dev/null
+++ b/.forgejo/workflows/test.yml
@@ -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
\ No newline at end of file

From 489158d1c4437f47c6c43c80fa1852292fe7e0aa Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Fri, 17 Nov 2023 11:35:36 +0000
Subject: [PATCH 16/44] Add Build + Release Workflow

---
 .forgejo/workflows/build+release.yml | 72 ++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 .forgejo/workflows/build+release.yml

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
new file mode 100644
index 0000000..4e9647d
--- /dev/null
+++ b/.forgejo/workflows/build+release.yml
@@ -0,0 +1,72 @@
+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:
+    run-tests:
+        runs-on: docker
+        steps:
+            -
+                name: Placeholder
+                run: echo Placeholder Job
+
+    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: 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/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 }}

From 12b5fc5ccbbade4835dfc8de1b1f6b9755f637ba Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Fri, 17 Nov 2023 11:43:06 +0000
Subject: [PATCH 17/44] Add Env Variables to build step

---
 .forgejo/workflows/build+release.yml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 4e9647d..d3e60eb 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -26,6 +26,12 @@ jobs:
             -
                 name: Checking Out Repository Code
                 uses: https://code.forgejo.org/actions/checkout@v3
+            -
+                name: Preparing Environment
+                run: |
+                    echo DATABASE_URL=$DATABASE_URL >> .env
+                    echo MACHINE_GROUP_ID=12 >> .env
+                    echo UPTIME_KUMA_URL= >> .env
             -
                 name: Compiling To Linux Target
                 run: |

From 51ade4a3a149faad39485161956ef29689e95bdb Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Fri, 17 Nov 2023 11:52:03 +0000
Subject: [PATCH 18/44] Get DATABASE_URL from Secrets until UI Update adds
 Variables

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index d3e60eb..8b86049 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -29,7 +29,7 @@ jobs:
             -
                 name: Preparing Environment
                 run: |
-                    echo DATABASE_URL=$DATABASE_URL >> .env
+                    echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
                     echo MACHINE_GROUP_ID=12 >> .env
                     echo UPTIME_KUMA_URL= >> .env
             -

From 29fa524241f138612a77fa3afee46ffaadd25ac0 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 07:48:26 +0000
Subject: [PATCH 19/44] Change Machine ID to Variable

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 8b86049..383b414 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -30,7 +30,7 @@ jobs:
                 name: Preparing Environment
                 run: |
                     echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
-                    echo MACHINE_GROUP_ID=12 >> .env
+                    echo MACHINE_GROUP_ID=${{ vars.MACHINE_GROUP_ID}} >> .env
                     echo UPTIME_KUMA_URL= >> .env
             -
                 name: Compiling To Linux Target

From 3f7616aeca92c59ba88d9e5ae74df09244d809bb Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 07:48:45 +0000
Subject: [PATCH 20/44] formatting change

Signed-off-by: Neshura <neshura@noreply.forgejo.neshweb.net>
---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 383b414..2540592 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -30,7 +30,7 @@ jobs:
                 name: Preparing Environment
                 run: |
                     echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
-                    echo MACHINE_GROUP_ID=${{ vars.MACHINE_GROUP_ID}} >> .env
+                    echo MACHINE_GROUP_ID=${{ vars.MACHINE_GROUP_ID }} >> .env
                     echo UPTIME_KUMA_URL= >> .env
             -
                 name: Compiling To Linux Target

From 335cfcb05c45d67f9db95dedf797085fcfbd9e7f Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 07:54:06 +0000
Subject: [PATCH 21/44] corrected Artifact naming

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 2540592..847024a 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -57,7 +57,7 @@ jobs:
                 name: Rearrange Artifact Paths
                 run: |
                     mkdir release
-                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
+                    mv chellaris-rust-api/chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
             -
                 name: Upload Artifacts As Generic Packages
                 run: |

From be28b98ff6c371ad1b3bce39f8417b0e6accdd66 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 07:56:32 +0000
Subject: [PATCH 22/44] Artifact Path Fix Attempt #2

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 847024a..a5959b0 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -57,7 +57,7 @@ jobs:
                 name: Rearrange Artifact Paths
                 run: |
                     mkdir release
-                    mv chellaris-rust-api/chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
+                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
             -
                 name: Upload Artifacts As Generic Packages
                 run: |

From f873fb366a80b46546380a7f3bf3e69bdcaddb64 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 07:59:27 +0000
Subject: [PATCH 23/44] Artifact Path Fix Attemtp #3 + Debugging

---
 .forgejo/workflows/build+release.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index a5959b0..8ef5b86 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -57,7 +57,8 @@ jobs:
                 name: Rearrange Artifact Paths
                 run: |
                     mkdir release
-                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
+                    ls ./
+                    mv chellaris-rust-api/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
             -
                 name: Upload Artifacts As Generic Packages
                 run: |

From e056fd7fa0dbb9be4aca5d7bfc0674bb889f7e78 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 08:01:38 +0000
Subject: [PATCH 24/44] Fix debugging output

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 8ef5b86..2c9bc39 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -57,7 +57,7 @@ jobs:
                 name: Rearrange Artifact Paths
                 run: |
                     mkdir release
-                    ls ./
+                    ls -lap ./
                     mv chellaris-rust-api/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
             -
                 name: Upload Artifacts As Generic Packages

From 4c28954335c1d9f0c541b59f99cd32917d60ebe3 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 08:03:48 +0000
Subject: [PATCH 25/44] Artifact Path Fix Attempt #4

---
 .forgejo/workflows/build+release.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 2c9bc39..3adb8f9 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -57,8 +57,8 @@ jobs:
                 name: Rearrange Artifact Paths
                 run: |
                     mkdir release
-                    ls -lap ./
-                    mv chellaris-rust-api/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
+                    ls -lap ./chellaris-rust-api-linux-amd64
+                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
             -
                 name: Upload Artifacts As Generic Packages
                 run: |

From 0f7958ce085f721523fc165eb45c573f61c1cc2c Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 27 Nov 2023 08:07:13 +0000
Subject: [PATCH 26/44] Artifact Path Fix Attempt #5

---
 .forgejo/workflows/build+release.yml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 3adb8f9..dd35a7c 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -57,8 +57,7 @@ jobs:
                 name: Rearrange Artifact Paths
                 run: |
                     mkdir release
-                    ls -lap ./chellaris-rust-api-linux-amd64
-                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
+                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
             -
                 name: Upload Artifacts As Generic Packages
                 run: |

From 0e5dca0f9a81507fd6531878fd97755678ca9690 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Tue, 12 Dec 2023 06:50:55 +0000
Subject: [PATCH 27/44] remove gitlab-ci.yml

---
 .gitlab-ci.yml | 71 --------------------------------------------------
 1 file changed, 71 deletions(-)
 delete mode 100644 .gitlab-ci.yml

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index 41b046d..0000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,71 +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
-    - echo MACHINE_GROUP_ID=12 >> .env
-    - echo UPTIME_KUMA_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"

From 35807d66ab41d2f2470ee797b516251cf92c2e42 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 20:35:17 +0100
Subject: [PATCH 28/44] Dependency Version Bumps

---
 Cargo.lock | 348 ++++++++++++++++++++++++++++-------------------------
 Cargo.toml |  28 +++--
 2 files changed, 198 insertions(+), 178 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c226b77..53947cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,17 +21,17 @@ dependencies = [
 
 [[package]]
 name = "actix-http"
-version = "3.3.1"
+version = "3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74"
+checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9"
 dependencies = [
  "actix-codec",
  "actix-rt",
  "actix-service",
  "actix-utils",
- "ahash 0.8.3",
+ "ahash",
  "base64",
- "bitflags 1.3.2",
+ "bitflags 2.4.0",
  "brotli",
  "bytes",
  "bytestring",
@@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
 dependencies = [
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "actix-web"
-version = "4.3.1"
+version = "4.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96"
+checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9"
 dependencies = [
  "actix-codec",
  "actix-http",
@@ -145,7 +145,7 @@ dependencies = [
  "actix-service",
  "actix-utils",
  "actix-web-codegen",
- "ahash 0.7.6",
+ "ahash",
  "bytes",
  "bytestring",
  "cfg-if",
@@ -154,7 +154,6 @@ dependencies = [
  "encoding_rs",
  "futures-core",
  "futures-util",
- "http",
  "itoa",
  "language-tags",
  "log",
@@ -166,8 +165,8 @@ dependencies = [
  "serde_json",
  "serde_urlencoded",
  "smallvec",
- "socket2 0.4.9",
- "time 0.3.27",
+ "socket2 0.5.5",
+ "time",
  "url",
 ]
 
@@ -200,25 +199,15 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "ahash"
-version = "0.7.6"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "ahash"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
 dependencies = [
  "cfg-if",
  "getrandom",
  "once_cell",
  "version_check",
+ "zerocopy",
 ]
 
 [[package]]
@@ -275,6 +264,16 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "atomic-write-file"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
+dependencies = [
+ "nix",
+ "rand",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -406,6 +405,7 @@ dependencies = [
  "dotenvy",
  "dotenvy_macro",
  "env_logger",
+ "rand",
  "reqwest",
  "schemars",
  "serde",
@@ -413,23 +413,23 @@ dependencies = [
  "sqlx",
  "tokio",
  "toml",
+ "url",
  "utoipa",
  "utoipa-swagger-ui",
 ]
 
 [[package]]
 name = "chrono"
-version = "0.4.26"
+version = "0.4.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
+checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
- "time 0.1.45",
  "wasm-bindgen",
- "winapi",
+ "windows-targets",
 ]
 
 [[package]]
@@ -451,7 +451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
 dependencies = [
  "percent-encoding",
- "time 0.3.27",
+ "time",
  "version_check",
 ]
 
@@ -535,9 +535,9 @@ dependencies = [
 
 [[package]]
 name = "ctrlc"
-version = "3.4.0"
+version = "3.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
+checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
 dependencies = [
  "nix",
  "windows-sys",
@@ -649,9 +649,9 @@ dependencies = [
 
 [[package]]
 name = "env_logger"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
 dependencies = [
  "humantime",
  "is-terminal",
@@ -722,13 +722,12 @@ dependencies = [
 
 [[package]]
 name = "flume"
-version = "0.10.14"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
+checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
 dependencies = [
  "futures-core",
  "futures-sink",
- "pin-project",
  "spin 0.9.8",
 ]
 
@@ -755,9 +754,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -852,7 +851,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
 ]
 
 [[package]]
@@ -892,7 +891,7 @@ version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
 dependencies = [
- "ahash 0.8.3",
+ "ahash",
  "allocator-api2",
 ]
 
@@ -1055,9 +1054,9 @@ dependencies = [
 
 [[package]]
 name = "idna"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -1151,9 +1150,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.147"
+version = "0.2.151"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
 
 [[package]]
 name = "libm"
@@ -1163,9 +1162,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
 
 [[package]]
 name = "libsqlite3-sys"
-version = "0.26.0"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
+checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
 dependencies = [
  "cc",
  "pkg-config",
@@ -1260,13 +1259,13 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.8"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
 dependencies = [
  "libc",
  "log",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
  "windows-sys",
 ]
 
@@ -1290,14 +1289,13 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.26.2"
+version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.0",
  "cfg-if",
  "libc",
- "static_assertions",
 ]
 
 [[package]]
@@ -1406,7 +1404,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -1467,29 +1465,9 @@ dependencies = [
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
-
-[[package]]
-name = "pin-project"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.29",
-]
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pin-project-lite"
@@ -1668,9 +1646,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
 
 [[package]]
 name = "reqwest"
-version = "0.11.20"
+version = "0.11.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
+checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
 dependencies = [
  "base64",
  "bytes",
@@ -1693,6 +1671,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_urlencoded",
+ "system-configuration",
  "tokio",
  "tokio-native-tls",
  "tower-service",
@@ -1727,9 +1706,9 @@ dependencies = [
 
 [[package]]
 name = "rust-embed"
-version = "6.8.1"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661"
+checksum = "810294a8a4a0853d4118e3b94bb079905f2107c7fe979d8f0faae98765eb6378"
 dependencies = [
  "rust-embed-impl",
  "rust-embed-utils",
@@ -1738,23 +1717,23 @@ dependencies = [
 
 [[package]]
 name = "rust-embed-impl"
-version = "6.8.1"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac"
+checksum = "bfc144a1273124a67b8c1d7cd19f5695d1878b31569c0512f6086f0f4676604e"
 dependencies = [
  "proc-macro2",
  "quote",
  "rust-embed-utils",
  "shellexpand",
- "syn 2.0.29",
+ "syn 2.0.32",
  "walkdir",
 ]
 
 [[package]]
 name = "rust-embed-utils"
-version = "7.8.1"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74"
+checksum = "816ccd4875431253d6bb54b804bcff4369cbde9bae33defde25fdf6c2ef91d40"
 dependencies = [
  "sha2",
  "walkdir",
@@ -1814,9 +1793,9 @@ dependencies = [
 
 [[package]]
 name = "schemars"
-version = "0.8.12"
+version = "0.8.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
+checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
 dependencies = [
  "dyn-clone",
  "schemars_derive",
@@ -1826,9 +1805,9 @@ dependencies = [
 
 [[package]]
 name = "schemars_derive"
-version = "0.8.12"
+version = "0.8.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
+checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1873,22 +1852,22 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
 
 [[package]]
 name = "serde"
-version = "1.0.185"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.185"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -1904,9 +1883,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.105"
+version = "1.0.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
 dependencies = [
  "itoa",
  "ryu",
@@ -1915,9 +1894,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.3"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
 dependencies = [
  "serde",
 ]
@@ -1958,9 +1937,9 @@ dependencies = [
 
 [[package]]
 name = "shellexpand"
-version = "2.1.2"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
+checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
 dependencies = [
  "dirs",
 ]
@@ -2011,9 +1990,9 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.5.3"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
  "windows-sys",
@@ -2057,9 +2036,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e58421b6bc416714d5115a2ca953718f6c621a51b68e4f4922aea5a4391a721"
+checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
 dependencies = [
  "sqlx-core",
  "sqlx-macros",
@@ -2070,11 +2049,11 @@ dependencies = [
 
 [[package]]
 name = "sqlx-core"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53"
+checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
 dependencies = [
- "ahash 0.8.3",
+ "ahash",
  "atoi",
  "byteorder",
  "bytes",
@@ -2110,9 +2089,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-macros"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "208e3165167afd7f3881b16c1ef3f2af69fa75980897aac8874a0696516d12c2"
+checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2123,10 +2102,11 @@ dependencies = [
 
 [[package]]
 name = "sqlx-macros-core"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a4a8336d278c62231d87f24e8a7a74898156e34c1c18942857be2acb29c7dfc"
+checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
 dependencies = [
+ "atomic-write-file",
  "dotenvy",
  "either",
  "heck",
@@ -2149,9 +2129,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-mysql"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482"
+checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
 dependencies = [
  "atoi",
  "base64",
@@ -2191,9 +2171,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-postgres"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e"
+checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
 dependencies = [
  "atoi",
  "base64",
@@ -2230,9 +2210,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-sqlite"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2"
+checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
 dependencies = [
  "atoi",
  "flume",
@@ -2248,14 +2228,9 @@ dependencies = [
  "sqlx-core",
  "tracing",
  "url",
+ "urlencoding",
 ]
 
-[[package]]
-name = "static_assertions"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-
 [[package]]
 name = "stringprep"
 version = "0.1.3"
@@ -2285,15 +2260,36 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.29"
+version = "2.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "system-configuration"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "tempfile"
 version = "3.8.0"
@@ -2333,18 +2329,7 @@ checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
-]
-
-[[package]]
-name = "time"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
-dependencies = [
- "libc",
- "wasi 0.10.0+wasi-snapshot-preview1",
- "winapi",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -2392,21 +2377,34 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.32.0"
+version = "1.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
+checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
 dependencies = [
  "backtrace",
  "bytes",
  "libc",
  "mio",
+ "num_cpus",
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.3",
+ "socket2 0.5.5",
+ "tokio-macros",
  "windows-sys",
 ]
 
+[[package]]
+name = "tokio-macros"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
 [[package]]
 name = "tokio-native-tls"
 version = "0.3.1"
@@ -2444,9 +2442,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.7.6"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
+checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2456,18 +2454,18 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.19.14"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
+checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
 dependencies = [
  "indexmap 2.0.0",
  "serde",
@@ -2503,7 +2501,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -2571,9 +2569,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
 
 [[package]]
 name = "url"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -2581,10 +2579,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "utoipa"
-version = "3.5.0"
+name = "urlencoding"
+version = "2.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+
+[[package]]
+name = "utoipa"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ff05e3bac2c9428f57ade702667753ca3f5cf085e2011fe697de5bfd49aa72d"
 dependencies = [
  "indexmap 2.0.0",
  "serde",
@@ -2594,22 +2598,22 @@ dependencies = [
 
 [[package]]
 name = "utoipa-gen"
-version = "3.5.0"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c"
+checksum = "5f0b6f4667edd64be0e820d6631a60433a269710b6ee89ac39525b872b76d61d"
 dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
  "regex",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
 name = "utoipa-swagger-ui"
-version = "3.1.5"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653"
+checksum = "f839caa8e09dddc3ff1c3112a91ef7da0601075ba5025d9f33ae99c4cb9b6e51"
 dependencies = [
  "actix-web",
  "mime_guess",
@@ -2652,12 +2656,6 @@ dependencies = [
  "try-lock",
 ]
 
-[[package]]
-name = "wasi"
-version = "0.10.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
-
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -2685,7 +2683,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
  "wasm-bindgen-shared",
 ]
 
@@ -2719,7 +2717,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -2871,6 +2869,26 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "zerocopy"
+version = "0.7.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.6.0"
diff --git a/Cargo.toml b/Cargo.toml
index 8d13671..7a9019a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,18 +6,20 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-actix-web = "4.3.1"
-chrono = "0.4.26"
-ctrlc = "3.4.0"
+actix-web = "4.4.0"
+chrono = "0.4.31"
+ctrlc = "3.4.1"
 dotenvy = "0.15.7"
 dotenvy_macro = "0.15.7"
-env_logger = "0.10.0"
-reqwest = "0.11.20"
-schemars = "0.8.10"
-serde = { version = "1.0.185", features = ["derive"] }
-serde_json = "1.0.105"
-sqlx = { version = "0.7.1", features = ["postgres", "runtime-tokio"] }
-tokio = { version = "1.32.0", features = ["rt"] }
-toml = "0.7.6"
-utoipa = { version = "3.5.0", features = ["actix_extras", "non_strict_integers"] }
-utoipa-swagger-ui = { version = "3.1.5", features = ["actix-web"] }
+env_logger = "0.10.1"
+reqwest = "0.11.22"
+schemars = "0.8.16"
+serde = { version = "1.0.193", features = ["derive"] }
+serde_json = "1.0.108"
+sqlx = { version = "0.7.3", features = ["postgres", "runtime-tokio"] }
+tokio = { version = "1.35.0", features = ["rt", "rt-multi-thread", "macros", "time"] }
+toml = "0.8.8"
+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"

From 134581f8ad82fdfa5b3375421d10920f5271ee27 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 20:38:04 +0100
Subject: [PATCH 29/44] Adapt API v2 and v3 to new DB Schema

---
 src/db/schemas.rs | 19 ++++++++++++++++++-
 src/v2/mod.rs     |  2 +-
 src/v3/mod.rs     |  8 ++++----
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/src/db/schemas.rs b/src/db/schemas.rs
index 0978e56..9604b78 100644
--- a/src/db/schemas.rs
+++ b/src/db/schemas.rs
@@ -42,10 +42,15 @@ pub struct Empire {
     pub group_id: i32,
     pub game_id: i32,
     pub name: String,
-    pub discord_user: Option<String>,
     pub gestalt: bool,
     pub portrait_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)]
@@ -55,3 +60,15 @@ pub struct EmpireEthic {
     pub ethics_id: i32,
     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,
+}
diff --git a/src/v2/mod.rs b/src/v2/mod.rs
index 8cff9c5..1f1f07a 100644
--- a/src/v2/mod.rs
+++ b/src/v2/mod.rs
@@ -78,7 +78,7 @@ pub(crate) async fn empires(
 
         if let Some(auth_token) = params.token.clone() {
             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());
             }
         }
 
diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index bf27705..9d904a3 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -367,7 +367,7 @@ pub(crate) async fn get_game_data(
                 "[REDACTED]".to_string()
             },
             discord_user: if user_auth.moderator || user_auth.admin {
-                empire.discord_user.clone()
+                Some("deprecated".to_string())
             } else {
                 None
             },
@@ -807,7 +807,7 @@ pub(crate) async fn get_empire(
             group: db_empire.group_id,
             game: db_empire.game_id,
             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,
             portrait_id: db_empire.portrait_id,
@@ -941,7 +941,7 @@ pub(crate) async fn create_empire(
                 group: db_empire.group_id,
                 game: db_empire.game_id,
                 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,
                 portrait_id: db_empire.portrait_id,
@@ -1174,7 +1174,7 @@ pub(crate) async fn edit_empire(
                 group: db_empire.group_id,
                 game: db_empire.game_id,
                 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,
                 portrait_id: db_empire.portrait_id,

From b3347a6e533ac2a83ec32d55ba2c09cfd2f8328a Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 20:39:15 +0100
Subject: [PATCH 30/44] Add new "v1" API, rename "v2" and "v3" to legacy

---
 src/main.rs       |  75 ++++++++--
 src/v1/mod.rs     | 360 ++++++++++++++++++++++++++++++++++++++++++++++
 src/v1/schemas.rs |  65 +++++++++
 3 files changed, 487 insertions(+), 13 deletions(-)
 create mode 100644 src/v1/mod.rs
 create mode 100644 src/v1/schemas.rs

diff --git a/src/main.rs b/src/main.rs
index 239a703..23b583d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -25,15 +25,21 @@ macro_rules! api_base {
     };
 }
 
+macro_rules! api_base_1 {
+    () => {
+        "/api/v1"
+    };
+}
+
 macro_rules! api_base_2 {
     () => {
-        "/api/v2"
+        "/api/v2-l"
     };
 }
 
 macro_rules! api_base_3 {
     () => {
-        "/api/v3"
+        "/api/v3-l"
     };
 }
 
@@ -208,9 +214,27 @@ async fn main() -> Result<()> {
     )]
     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![
-        Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
-        Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
+        Url::new("v1", concat!(api_base_1!(), "/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));
@@ -218,15 +242,31 @@ async fn main() -> Result<()> {
     loop {
         let db_auth_tokens = config.auth.clone();
         let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap();
+
         let pool_copy = pool.clone();
+        let shutdown_clone = shutdown.clone();
 
         let swagger_config = Config::new(openapi_urls.clone());
 
-        let mut openapi_v2 = ApiDocV2::openapi();
-        openapi_v2.info.title = "Chellaris Rust API".to_string();
-    
-        let mut openapi_v3 = ApiDocV3::openapi();
-        openapi_v3.info.title = "Chellaris Rust API".to_string();
+        let mut openapi_v1 = ApiDocV1::openapi();
+        openapi_v1.info.title = "Chellaris Rust API v1".to_string();
+
+        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) });
+        tokio::spawn(async move {
+            actix_web::rt::signal::ctrl_c().await.unwrap();
+            println!("Ctrl-C received, killing Server");
+            abort()
+        });
 
         let server = HttpServer::new(move || {
             App::new()
@@ -257,17 +297,26 @@ async fn main() -> Result<()> {
                 .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
                 .service(
                     SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
                         .urls(vec![
                             (
-                                Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
-                                openapi_v2.clone(),
+                                Url::new("v1", concat!(api_base_1!(), "/openapi.json")),
+                                openapi_v1.clone(),
                             ),
                             (
-                                Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
-                                openapi_v3.clone(),
+                                Url::new("v2-l", concat!(api_base_2!(), "/openapi.json")),
+                                openapi_v2_l.clone(),
+                            ),
+                            (
+                                Url::new("v3-l", concat!(api_base_3!(), "/openapi.json")),
+                                openapi_v3_l.clone(),
                             ),
                         ])
                         .config(swagger_config.clone()),
diff --git a/src/v1/mod.rs b/src/v1/mod.rs
new file mode 100644
index 0000000..ad7c47a
--- /dev/null
+++ b/src/v1/mod.rs
@@ -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, &params.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, &params.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, &params.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();
+    }
+}
diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs
new file mode 100644
index 0000000..e561cce
--- /dev/null
+++ b/src/v1/schemas.rs
@@ -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,
+}
\ No newline at end of file

From 75eefab02c8ae12b3e0e0e6b32efd1230015deb6 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 20:39:34 +0100
Subject: [PATCH 31/44] Hopefully Fix Server getting stuck when main thread
 dies

---
 src/main.rs | 58 ++++++++++++-----------------------------------------
 1 file changed, 13 insertions(+), 45 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 23b583d..51e8abb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,16 +6,18 @@ use dotenvy::dotenv;
 use tokio::time::sleep;
 
 use std::{env, fs, net::Ipv4Addr, net::Ipv6Addr, time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering}}};
+use std::process::abort;
 
 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 sqlx::{PgPool, Pool, Postgres, Connection};
 use utoipa::{OpenApi, openapi::security::{SecurityScheme, ApiKey, ApiKeyValue}, Modify};
 use utoipa_swagger_ui::{Config, SwaggerUi, Url};
 
 mod db;
+mod v1;
 mod v2;
 mod v3;
 
@@ -65,8 +67,8 @@ pub struct AppState {
     auth_tokens: AuthenticationTokens,
 }
 
-async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Arc<AtomicBool>) {
-    loop {
+async fn postgres_watchdog(pool: PgPool, shutdown: Arc<AtomicBool>) {
+    while !shutdown.load(Ordering::Relaxed) {
         let start = Local::now();
 
         let mut conn = match pool.acquire().await {
@@ -94,31 +96,17 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Ar
         
         while Local::now() - start < chrono::Duration::seconds(15) {
             sleep(Duration::from_millis(100)).await;
-            if shutdown.load(Ordering::Relaxed) {
-                break;
-            }
-        }
-        if shutdown.load(Ordering::Relaxed) {
-            break;
         }
     }
-    is_alive.store(false, Ordering::Relaxed);
 }
 
 #[actix_web::main]
-async fn main() -> Result<()> {
+async fn main() {
     env_logger::init();
     dotenv().ok();
 
     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 config: ConfigToml = toml::from_str(&toml_str).expect("Failed to parse config.toml");
@@ -322,36 +310,16 @@ async fn main() -> Result<()> {
                         .config(swagger_config.clone()),
                 )
         })
-        .bind((Ipv6Addr::UNSPECIFIED, config.port.default)).expect("Port or IP already occupied")
-        .run();
+            .bind((Ipv6Addr::UNSPECIFIED, config.port.default)).expect("Port or IP already occupied")
+            .run()
+            .await;
 
-        let server_thread = tokio::spawn(async {
-            println!("Awaiting server");
-            let _ = server.await;
-            println!("Stopped awaiting server");
-        });
+        watchdog_thread.abort();
 
-        println!("Started Serving API on: ");
-        println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080);
-        println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080);
+        sleep(Duration::from_secs(10)).await;
 
-        let is_alive_clone = Arc::clone(&is_alive);
-        let shutdown_clone = Arc::clone(&shutdown);
-        let _ = tokio::spawn(async move { postgres_watchdog(pool_copy, is_alive_clone, shutdown_clone).await });
-        
-        //watchdog_thread.await;
+        println!("Service crashed due to unexpected Error, restarting thread after wait...");
 
-        while is_alive.load(Ordering::Relaxed) {
-            sleep(Duration::from_millis(200)).await;
-        }
-
-        if shutdown.load(Ordering::Relaxed) {
-            break;
-        }
-
-        eprintln!("Connection died, restarting Server");
-        server_thread.abort();
+        sleep(Duration::from_secs(10)).await;
     }
-
-    Ok(())
 }

From 12938d1ee46fd1c0a1eb1cafed95c1e27425cf1c Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 20:49:39 +0100
Subject: [PATCH 32/44] Various linting changes

---
 src/main.rs       |  4 +---
 src/v1/mod.rs     | 29 ++++++++++++++---------------
 src/v1/schemas.rs |  3 +--
 src/v3/mod.rs     |  2 +-
 src/v3/schemas.rs |  2 +-
 5 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 51e8abb..e973a6d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -225,8 +225,6 @@ async fn main() {
         Url::new("v3-L", concat!(api_base_3!(), "/openapi.json")),
     ];
 
-    let is_alive: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
-
     loop {
         let db_auth_tokens = config.auth.clone();
         let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap();
@@ -256,7 +254,7 @@ async fn main() {
             abort()
         });
 
-        let server = HttpServer::new(move || {
+        let _ = HttpServer::new(move || {
             App::new()
                 .app_data(web::Data::new(AppState { db: pool.clone(), auth_tokens: db_auth_tokens.clone() }))
                 .wrap(Logger::default())
diff --git a/src/v1/mod.rs b/src/v1/mod.rs
index ad7c47a..cddfbba 100644
--- a/src/v1/mod.rs
+++ b/src/v1/mod.rs
@@ -1,5 +1,4 @@
 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;
@@ -9,7 +8,7 @@ use sqlx::QueryBuilder;
 
 pub(crate) mod schemas;
 
-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()
 }
 
@@ -90,18 +89,18 @@ async fn get_user(
             Err(_) => return HttpResponse::InternalServerError().finish(),
         };
 
-        let mut permissions: HashMap<String, bool> = HashMap::new();
+        let mut user_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);
+        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: permissions
+            permissions: user_permissions
         };
 
         return HttpResponse::Ok().json(return_data);
@@ -290,17 +289,17 @@ pub(crate) async fn update_user(
             };
         }
 
-        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 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: permissions
+            permissions: user_permissions
         };
         return HttpResponse::Ok().json(return_data);
     } else {
@@ -348,7 +347,7 @@ pub(crate) async fn delete_user(
             .await
         {
             Ok(_) => {}
-            Err(e) => {
+            Err(_) => {
                 return HttpResponse::InternalServerError().finish();
             }
         };
diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs
index e561cce..d6d9d65 100644
--- a/src/v1/schemas.rs
+++ b/src/v1/schemas.rs
@@ -1,7 +1,6 @@
 use std::collections::HashMap;
 use serde::{Deserialize, Serialize};
-use utoipa::{IntoParams, ToSchema};
-use crate::v3::schemas::ChellarisGameLegacy;
+use utoipa::{ToSchema};
 
 // DB Permission Enums
 
diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 9d904a3..f1c414c 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -31,7 +31,7 @@ fn verify_auth(token: Option<&str>, data: &AppState) -> schemas::AuthReturn {
     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()
 }
 
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index 847bccc..709a7b2 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -1,4 +1,4 @@
-use std::{collections::HashMap, hash::Hash};
+use std::{collections::HashMap};
 
 use serde::{Serialize, Deserialize};
 use utoipa::{ToSchema, IntoParams};

From c01ed85e7af3c90cad6bfc96a68ce2e5c1f33e44 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 21:10:04 +0100
Subject: [PATCH 33/44] Postgres Watchdog Fix

---
 src/main.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main.rs b/src/main.rs
index e973a6d..f1df875 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -247,7 +247,7 @@ async fn main() {
         println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080);
         println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080);
 
-        let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone) });
+        let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone).await });
         tokio::spawn(async move {
             actix_web::rt::signal::ctrl_c().await.unwrap();
             println!("Ctrl-C received, killing Server");

From 83a1af59d9a413ff8d145d94b7deb434dba93a3b Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 21:15:50 +0100
Subject: [PATCH 34/44] General SIGINT handling instead of CTRLC handling

---
 src/main.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index f1df875..fd57680 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,6 +13,7 @@ use chrono::Local;
 use actix_web::{middleware::Logger, web, App, HttpServer};
 use serde::{Deserialize, Serialize};
 use sqlx::{PgPool, Pool, Postgres, Connection};
+use tokio::signal::unix::SignalKind;
 use utoipa::{OpenApi, openapi::security::{SecurityScheme, ApiKey, ApiKeyValue}, Modify};
 use utoipa_swagger_ui::{Config, SwaggerUi, Url};
 
@@ -249,8 +250,8 @@ async fn main() {
 
         let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone).await });
         tokio::spawn(async move {
-            actix_web::rt::signal::ctrl_c().await.unwrap();
-            println!("Ctrl-C received, killing Server");
+            actix_web::rt::signal::unix::signal(SignalKind::interrupt()).unwrap().recv().await;
+            println!("SIGINT received, killing Server");
             abort()
         });
 

From c0799484bba11f2b06e8e32b1ca6ff6753bb27ec Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 21:25:57 +0100
Subject: [PATCH 35/44] Add SigTerm handling for systemctl stop

---
 src/main.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/main.rs b/src/main.rs
index fd57680..5f59b99 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -249,6 +249,11 @@ async fn main() {
         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");

From 8373b278cc6242be75115381e755e1bbc2a668f7 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Tue, 12 Dec 2023 22:11:32 +0100
Subject: [PATCH 36/44] Various Fixes to API v1

---
 src/v1/mod.rs     | 90 +++++++++++++++++++++++++++--------------------
 src/v1/schemas.rs |  6 ++--
 2 files changed, 54 insertions(+), 42 deletions(-)

diff --git a/src/v1/mod.rs b/src/v1/mod.rs
index cddfbba..118d0ca 100644
--- a/src/v1/mod.rs
+++ b/src/v1/mod.rs
@@ -48,7 +48,9 @@ async fn verify_user_auth(data: &web::Data<AppState>, auth_token: &str, user_tok
 
 // User Endpoints
 #[utoipa::path(
-    request_body = schemas::GetUserParams,
+    params(
+        schemas::GetUserParams
+    ),
     responses(
         (status = 200, description = "OK", body = User),
         (status = 403, description = "Unauthorized"),
@@ -59,7 +61,7 @@ async fn verify_user_auth(data: &web::Data<AppState>, auth_token: &str, user_tok
     ),
 )]
 #[get("/api/v1/user")]
-async fn get_user(
+pub(crate) async fn get_user(
     data: web::Data<AppState>,
     params: web::Json<schemas::GetUserParams>,
     req: HttpRequest,
@@ -195,9 +197,17 @@ pub(crate) async fn update_user(
         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 params.permissions["game_permissions"] || params.permissions["empire_permissions"] || params.permissions["data_permissions"] || params.permissions["user_permissions"] {
-        elevated_auth = true;
+    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, &params.user_token, schemas::TablePermission::User, elevated_auth).await;
@@ -225,41 +235,43 @@ pub(crate) async fn update_user(
             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 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;
+                    },
+                    _ => {}
+                }
             }
         }
 
diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs
index d6d9d65..8fea931 100644
--- a/src/v1/schemas.rs
+++ b/src/v1/schemas.rs
@@ -1,6 +1,6 @@
 use std::collections::HashMap;
 use serde::{Deserialize, Serialize};
-use utoipa::{ToSchema};
+use utoipa::{IntoParams, ToSchema};
 
 // DB Permission Enums
 
@@ -32,7 +32,7 @@ pub struct User {
     pub permissions: HashMap<String, bool>,
 }
 
-#[derive(Serialize, Deserialize, ToSchema, Debug)]
+#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
 pub struct GetUserParams {
     #[schema(example = "abcdef")]
     pub user_token: String,
@@ -54,7 +54,7 @@ pub struct UpdateUserParams {
         [\"user_permissions\"]: false,
     }\
     ")]
-    pub permissions: HashMap<String, bool>,
+    pub permissions: Option<HashMap<String, bool>>,
 }
 
 #[derive(Serialize, Deserialize, ToSchema, Debug)]

From c8ed40c3cc3e8da68c0b0358fefc3759b7c749ef Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 13 Dec 2023 19:05:58 +0100
Subject: [PATCH 37/44] Add Version Checking to Actions file

---
 .forgejo/workflows/build+release.yml | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index dd35a7c..ccbb560 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -10,9 +10,22 @@ jobs:
     run-tests:
         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 src-tauri/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

From 5c0c03fd7a10f7a435663f41dc0ecd00ac1369fb Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 13 Dec 2023 19:06:32 +0100
Subject: [PATCH 38/44] Fix Param Naming mismatch

---
 src/v1/mod.rs     | 10 ++++------
 src/v1/schemas.rs |  2 +-
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/src/v1/mod.rs b/src/v1/mod.rs
index 118d0ca..4c0fb1b 100644
--- a/src/v1/mod.rs
+++ b/src/v1/mod.rs
@@ -48,9 +48,7 @@ async fn verify_user_auth(data: &web::Data<AppState>, auth_token: &str, user_tok
 
 // User Endpoints
 #[utoipa::path(
-    params(
-        schemas::GetUserParams
-    ),
+    request_body = GetUserParams,
     responses(
         (status = 200, description = "OK", body = User),
         (status = 403, description = "Unauthorized"),
@@ -60,7 +58,7 @@ async fn verify_user_auth(data: &web::Data<AppState>, auth_token: &str, user_tok
         ("api_key" = [])
     ),
 )]
-#[get("/api/v1/user")]
+#[post("/api/v1/user")]
 pub(crate) async fn get_user(
     data: web::Data<AppState>,
     params: web::Json<schemas::GetUserParams>,
@@ -118,7 +116,7 @@ pub(crate) async fn get_user(
         (status = 500, description = "Internal Server Error")
     ),
 )]
-#[post("/api/v1/user")]
+#[post("/api/v1/user/create")]
 pub(crate) async fn create_user(
     data: web::Data<AppState>,
 ) -> impl Responder {
@@ -320,7 +318,7 @@ pub(crate) async fn update_user(
 }
 
 #[utoipa::path(
-    request_body = schemas::DeleteUserParams,
+    request_body = DeleteUserParams,
     responses(
         (status = 200, description = "OK"),
         (status = 403, description = "Unauthorized"),
diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs
index 8fea931..81c23c3 100644
--- a/src/v1/schemas.rs
+++ b/src/v1/schemas.rs
@@ -32,7 +32,7 @@ pub struct User {
     pub permissions: HashMap<String, bool>,
 }
 
-#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)]
+#[derive(Serialize, Deserialize, ToSchema, Debug)]
 pub struct GetUserParams {
     #[schema(example = "abcdef")]
     pub user_token: String,

From 22fa59334cc41ff145e39e98781512d76e517329 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 13 Dec 2023 19:06:46 +0100
Subject: [PATCH 39/44] move API docs to different route than API endpoints

---
 src/main.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 5f59b99..6a3a574 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -221,9 +221,9 @@ async fn main() {
     struct ApiDocV1;
 
     let openapi_urls = vec![
-        Url::new("v1", concat!(api_base_1!(), "/openapi.json")),
-        Url::new("v2-L", concat!(api_base_2!(), "/openapi.json")),
-        Url::new("v3-L", concat!(api_base_3!(), "/openapi.json")),
+        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 {
@@ -299,15 +299,15 @@ async fn main() {
                     SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
                         .urls(vec![
                             (
-                                Url::new("v1", concat!(api_base_1!(), "/openapi.json")),
+                                Url::new("v1", concat!(api_base!(), "-docs/openapi1.json")),
                                 openapi_v1.clone(),
                             ),
                             (
-                                Url::new("v2-l", concat!(api_base_2!(), "/openapi.json")),
+                                Url::new("v2-l", concat!(api_base!(), "-docs/openapi2l.json")),
                                 openapi_v2_l.clone(),
                             ),
                             (
-                                Url::new("v3-l", concat!(api_base_3!(), "/openapi.json")),
+                                Url::new("v3-l", concat!(api_base!(), "-docs/openapi3l.json")),
                                 openapi_v3_l.clone(),
                             ),
                         ])

From 717e3fda4915bc3bfdb825338109d297801bbd5d Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 13 Dec 2023 19:07:00 +0100
Subject: [PATCH 40/44] Cargo.toml version bump

---
 Cargo.lock | 2 +-
 Cargo.toml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 53947cb..ca617a4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -397,7 +397,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chellaris-rust-api"
-version = "1.0.3"
+version = "1.2.4"
 dependencies = [
  "actix-web",
  "chrono",
diff --git a/Cargo.toml b/Cargo.toml
index 7a9019a..f901372 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "chellaris-rust-api"
-version = "1.0.3"
+version = "1.2.4"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

From 48143979e5057720c0a0e9bd983b8cd5ad53d4b8 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 13 Dec 2023 19:08:05 +0100
Subject: [PATCH 41/44] Fix actions version check directory

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index ccbb560..d7f3bc7 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -19,7 +19,7 @@ jobs:
             -
                 name: Check if Version in Cargo.toml matches Tag
                 run: |
-                    VERSION=$(cat src-tauri/Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ")
+                    VERSION=$(cat src/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

From cd79f47caa00bae9df832cb7757c36f4af53017b Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 18 Dec 2023 07:50:58 +0000
Subject: [PATCH 42/44] Fix Version Check in Actions

---
 .forgejo/workflows/build+release.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index d7f3bc7..96e61f8 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -19,7 +19,7 @@ jobs:
             -
                 name: Check if Version in Cargo.toml matches Tag
                 run: |
-                    VERSION=$(cat src/Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ")
+                    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

From 36709b6b800de1242f69f7f7f0eacc4fea8c2860 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 18 Dec 2023 08:06:12 +0000
Subject: [PATCH 43/44] Update .forgejo/workflows/build+release.yml

---
 .forgejo/workflows/build+release.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 96e61f8..625e5e8 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -7,7 +7,7 @@ on:
             - '[0-9]+.[0-9]+.[0-9]+'
             - '[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
 jobs:
-    run-tests:
+    tests:
         runs-on: docker
         steps:
             -
@@ -28,7 +28,7 @@ jobs:
                     fi
 
     build:
-        needs: test
+        needs: tests
         if: success()
         runs-on: docker
         container: rust:latest

From e8f931392ef4e891b1038e1e509aaa9daef3349e Mon Sep 17 00:00:00 2001
From: Neshura <neshura@noreply.forgejo.neshweb.net>
Date: Mon, 18 Dec 2023 08:07:23 +0000
Subject: [PATCH 44/44] Update .forgejo/workflows/build+release.yml

---
 .forgejo/workflows/build+release.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
index 625e5e8..c473e32 100644
--- a/.forgejo/workflows/build+release.yml
+++ b/.forgejo/workflows/build+release.yml
@@ -7,7 +7,7 @@ on:
             - '[0-9]+.[0-9]+.[0-9]+'
             - '[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
 jobs:
-    tests:
+    test:
         runs-on: docker
         steps:
             -
@@ -28,7 +28,7 @@ jobs:
                     fi
 
     build:
-        needs: tests
+        needs: test
         if: success()
         runs-on: docker
         container: rust:latest