Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ user = "root"
password = ""
host = "127.0.0.1"
port = 3306
database = ""
game_database = ""
api_database = ""

[[servers]]
name = "Primary Station"
Expand Down
28 changes: 28 additions & 0 deletions database_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `hid_ckeys_autocomplete`
--

DROP TABLE IF EXISTS `hid_ckeys_autocomplete`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `hid_ckeys_autocomplete` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`ckey` VARCHAR(32) NOT NULL COLLATE 'utf8mb4_general_ci',
`hid_by` BIGINT(20) NOT NULL,
`unhid_by` BIGINT(20) NULL DEFAULT NULL,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`valid` BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (`id`)
) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB;
/*!40101 SET character_set_client = @saved_cs_client */;
3 changes: 2 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ pub struct Database {
pub password: String,
pub host: IpAddr,
pub port: u16,
pub database: String,
pub game_database: String,
pub api_database: String,
}

#[derive(Debug, Deserialize)]
Expand Down
72 changes: 69 additions & 3 deletions src/database/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use rocket::futures::StreamExt as _;
use serde::Serialize;
use sqlx::{pool::PoolConnection, Executor as _, FromRow, MySql, MySqlPool, Row as _};

use crate::config::Config;

use super::error::Error;

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -151,11 +153,15 @@ pub async fn get_jobs(job: &str, pool: &MySqlPool) -> Result<Vec<String>, Error>
Ok(jobs)
}

pub async fn get_ckeys(ckey: &str, pool: &MySqlPool) -> Result<Vec<String>, Error> {
pub async fn get_ckeys(
ckey: &str,
pool: &MySqlPool,
config: &Config,
) -> Result<Vec<String>, Error> {
let mut connection = pool.acquire().await?;

let query = sqlx::query("SELECT ckey FROM player WHERE ckey LIKE ? ORDER BY ckey LIMIT 25")
.bind(format!("{ckey}%"));
let sql = format!("SELECT p.ckey FROM {}.player p LEFT JOIN {}.hid_ckeys_autocomplete i ON i.ckey = p.ckey WHERE p.ckey LIKE ? AND (i.ckey IS NULL OR i.valid IS FALSE) ORDER BY p.ckey LIMIT 25", config.database.game_database, config.database.api_database);
let query = sqlx::query(&sql).bind(format!("{ckey}%"));

let mut ckeys = Vec::new();

Expand Down Expand Up @@ -388,3 +394,63 @@ pub async fn get_achievements(ckey: &str, pool: &MySqlPool) -> Result<Vec<Achiev

Ok(achievements)
}

pub async fn hide_ckey(
ckey: &str,
hid_by: i64,
pool: &MySqlPool,
config: &Config,
) -> Result<bool, Error> {
let mut connection = pool.acquire().await?;

let sql = format!(
"SELECT 1 FROM {}.hid_ckeys_autocomplete WHERE ckey = ? AND valid = 1",
config.database.api_database
);
let query = sqlx::query(&sql).bind(ckey.to_lowercase());

if connection.fetch_optional(query).await?.is_some() {
return Ok(false);
}

let sql = format!(
"INSERT INTO {}.hid_ckeys_autocomplete (ckey, hid_by, valid) VALUES (?, ?, 1)",
config.database.api_database
);
let query = sqlx::query(&sql).bind(ckey.to_lowercase()).bind(hid_by);

connection.execute(query).await?;
connection.close().await?;

Ok(true)
}

pub async fn unhide_ckey(
ckey: &str,
unhid_by: i64,
pool: &MySqlPool,
config: &Config,
) -> Result<bool, Error> {
let mut connection = pool.acquire().await?;

let sql = format!(
"SELECT 1 FROM {}.hid_ckeys_autocomplete WHERE ckey = ? AND valid = 1",
config.database.api_database
);
let query = sqlx::query(&sql).bind(ckey.to_lowercase());

if connection.fetch_optional(query).await?.is_none() {
return Ok(false);
}

let sql = format!(
"UPDATE {}.hid_ckeys_autocomplete SET valid = 0, unhid_by = ? WHERE ckey = ? AND valid = 1",
config.database.api_database
);
let query = sqlx::query(&sql).bind(unhid_by).bind(ckey.to_lowercase());

connection.execute(query).await?;
connection.close().await?;

Ok(true)
}
2 changes: 1 addition & 1 deletion src/database/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Database {
encode(&config.password),
config.host,
config.port,
config.database
config.game_database
);

let pool = options.connect_lazy(&url)?;
Expand Down
37 changes: 34 additions & 3 deletions src/routes/v2/autocomplete.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rocket::{get, http::Status, State};
use rocket::{get, http::Status, post, State};

use crate::{database::*, Database};
use crate::{config::Config, database::*, Database};

use super::{common::ApiKey, Json};

Expand All @@ -21,9 +21,10 @@ pub async fn job(
pub async fn ckey(
ckey: &str,
database: &State<Database>,
config: &State<Config>,
_api_key: ApiKey,
) -> Result<Json<Vec<String>>, Status> {
let Ok(ckeys) = get_ckeys(ckey, &database.pool).await else {
let Ok(ckeys) = get_ckeys(ckey, &database.pool, config).await else {
return Err(Status::InternalServerError);
};

Expand All @@ -42,3 +43,33 @@ pub async fn ic_name(

Ok(Json::Ok(ic_names))
}

#[post("/autocomplete/ckey/hide?<ckey>&<hid_by>")]
pub async fn hide_ckey_autocomplete(
ckey: &str,
hid_by: i64,
database: &State<Database>,
config: &State<Config>,
_api_key: ApiKey,
) -> Result<Json<bool>, Status> {
match hide_ckey(ckey, hid_by, &database.pool, config).await {
Ok(true) => Ok(Json::Ok(true)),
Ok(false) => Err(Status::Conflict),
Err(_) => Err(Status::InternalServerError),
}
}

#[post("/autocomplete/ckey/unhide?<ckey>&<unhid_by>")]
pub async fn unhide_ckey_autocomplete(
ckey: &str,
unhid_by: i64,
database: &State<Database>,
config: &State<Config>,
_api_key: ApiKey,
) -> Result<Json<bool>, Status> {
match unhide_ckey(ckey, unhid_by, &database.pool, config).await {
Ok(true) => Ok(Json::Ok(true)),
Ok(false) => Err(Status::Conflict),
Err(_) => Err(Status::InternalServerError),
}
}
2 changes: 2 additions & 0 deletions src/routes/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub fn mount(rocket: Rocket<Build>) -> Rocket<Build> {
autocomplete::job,
autocomplete::ckey,
autocomplete::ic_name,
autocomplete::hide_ckey_autocomplete,
autocomplete::unhide_ckey_autocomplete,
events::overview,
events::citations,
events::crimes,
Expand Down
Loading