use dotenvy::dotenv; use serde::{Deserialize, Serialize}; use serenity::{ model::{guild, id::GuildId}, prelude::TypeMapKey, }; use sqlx::{ sqlite::{SqliteConnectOptions, SqlitePoolOptions}, Error, Pool, Sqlite, }; use std::str::FromStr; use std::{env, sync::Arc}; use tokio::sync::RwLock; pub struct Config { pub skynet_server: GuildId, pub ldap_api: String, pub auth: String, pub timing_update: u64, pub timing_fetch: u64, pub discord_token: String, pub home: String, pub database: String, pub mail_smtp: String, pub mail_user: String, pub mail_pass: String, } impl TypeMapKey for Config { type Value = Arc>; } pub struct DataBase; impl TypeMapKey for DataBase { type Value = Arc>>; } pub fn get_config() -> Config { dotenv().ok(); // reasonable defaults let mut config = Config { skynet_server: Default::default(), ldap_api: "https://api.account.skynet.ie".to_string(), auth: "".to_string(), timing_update: 0, timing_fetch: 0, discord_token: "".to_string(), home: ".".to_string(), database: "database.db".to_string(), mail_smtp: "".to_string(), mail_user: "".to_string(), mail_pass: "".to_string(), }; if let Ok(x) = env::var("SKYNET_SERVER") { config.skynet_server = GuildId::from(str_to_num::(&x)); } if let Ok(x) = env::var("LDAP_API") { config.ldap_api = x.trim().to_string(); } if let Ok(x) = env::var("LDAP_DISCORD_AUTH") { config.auth = x.trim().to_string(); } if let Ok(x) = env::var("DISCORD_TIMING_UPDATE") { config.timing_update = str_to_num::(&x); } if let Ok(x) = env::var("DISCORD_TIMING_FETCH") { config.timing_fetch = str_to_num::(&x); } if let Ok(x) = env::var("DISCORD_TOKEN") { config.discord_token = x.trim().to_string(); } if let Ok(x) = env::var("HOME") { config.home = x.trim().to_string(); } if let Ok(x) = env::var("DATABASE") { config.database = x.trim().to_string(); } if let Ok(x) = env::var("EMAIL_SMTP") { config.mail_smtp = x.trim().to_string(); } if let Ok(x) = env::var("EMAIL_USER") { config.mail_user = x.trim().to_string(); } if let Ok(x) = env::var("EMAIL_PASS") { config.mail_pass = x.trim().to_string(); } config } fn str_to_num(x: &str) -> T { x.trim().parse::().unwrap_or_default() } #[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)] pub struct Accounts { pub server: i64, pub wolves_id: String, pub email: String, pub expiry: String, pub discord: Option, pub minecraft: Option, } #[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)] pub struct Servers { pub server: i64, pub wolves_api: String, pub role_past: Option, pub role_current: Option, pub member_past: i64, pub member_current: i64, } pub async fn db_init(config: &Config) -> Result, Error> { let database = format!("{}/{}", &config.home, &config.database); let pool = SqlitePoolOptions::new() .max_connections(5) .connect_with(SqliteConnectOptions::from_str(&format!("sqlite://{}", database))?.create_if_missing(true)) .await?; sqlx::query( "CREATE TABLE IF NOT EXISTS accounts ( server integer not null, wolves_id text not null, email text not null, expiry text not null, discord text, minecraft text, CONSTRAINT con_server_wolves PRIMARY KEY(server,wolves_id) )", ) .execute(&pool) .await?; sqlx::query("CREATE INDEX IF NOT EXISTS index_server ON accounts (server)").execute(&pool).await?; sqlx::query("CREATE INDEX IF NOT EXISTS index_wolves_id ON accounts (wolves_id)") .execute(&pool) .await?; sqlx::query( "CREATE TABLE IF NOT EXISTS servers ( server integer key, wolves_api text not null, role_past integer, role_current integer, member_past integer DEFAULT 0, member_current integer DEFAULT 0 )", ) .execute(&pool) .await?; Ok(pool) } pub async fn get_server_config(db: &Pool, server: &GuildId) -> Option { sqlx::query_as::<_, Servers>( r#" SELECT * FROM servers WHERE server = ? "#, ) .bind(*server.as_u64() as i64) .fetch_one(db) .await .ok() } pub async fn get_server_member(db: &Pool, server: &GuildId, member: &guild::Member) -> Option { sqlx::query_as::<_, Accounts>( r#" SELECT * FROM accounts WHERE server = ? AND discord = ? "#, ) .bind(*server.as_u64() as i64) .bind(&member.user.name) .fetch_one(db) .await .ok() }