2023-09-11 01:25:07 +00:00
|
|
|
use dotenvy::dotenv;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use serenity::{
|
2023-09-11 17:18:59 +00:00
|
|
|
model::{
|
|
|
|
guild,
|
|
|
|
id::{GuildId, RoleId},
|
|
|
|
},
|
2023-09-11 01:25:07 +00:00
|
|
|
prelude::TypeMapKey,
|
|
|
|
};
|
2023-09-11 17:18:59 +00:00
|
|
|
|
2023-09-16 19:05:50 +00:00
|
|
|
use chrono::{Datelike, SecondsFormat, Utc};
|
2023-09-17 14:25:17 +00:00
|
|
|
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
2023-09-11 01:25:07 +00:00
|
|
|
use sqlx::{
|
2023-09-11 17:18:59 +00:00
|
|
|
sqlite::{SqliteConnectOptions, SqlitePoolOptions, SqliteRow},
|
|
|
|
Error, FromRow, Pool, Row, Sqlite,
|
2023-09-11 01:25:07 +00:00
|
|
|
};
|
2023-09-11 17:18:59 +00:00
|
|
|
use std::{env, str::FromStr, sync::Arc};
|
2023-09-11 01:25:07 +00:00
|
|
|
use tokio::sync::RwLock;
|
|
|
|
|
|
|
|
pub struct Config {
|
|
|
|
pub skynet_server: GuildId,
|
|
|
|
pub ldap_api: String,
|
|
|
|
pub home: String,
|
|
|
|
pub database: String,
|
2023-09-16 18:47:39 +00:00
|
|
|
pub csv: String,
|
2023-09-11 01:25:07 +00:00
|
|
|
|
2023-09-17 20:02:41 +00:00
|
|
|
pub auth: String,
|
|
|
|
pub discord_token: String,
|
|
|
|
|
2023-09-11 01:25:07 +00:00
|
|
|
pub mail_smtp: String,
|
|
|
|
pub mail_user: String,
|
|
|
|
pub mail_pass: String,
|
|
|
|
}
|
|
|
|
impl TypeMapKey for Config {
|
|
|
|
type Value = Arc<RwLock<Config>>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DataBase;
|
|
|
|
impl TypeMapKey for DataBase {
|
|
|
|
type Value = Arc<RwLock<Pool<Sqlite>>>;
|
|
|
|
}
|
|
|
|
|
|
|
|
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(),
|
|
|
|
discord_token: "".to_string(),
|
|
|
|
|
|
|
|
home: ".".to_string(),
|
|
|
|
database: "database.db".to_string(),
|
2023-09-16 18:47:39 +00:00
|
|
|
csv: "wolves.csv".to_string(),
|
2023-09-11 01:25:07 +00:00
|
|
|
|
|
|
|
mail_smtp: "".to_string(),
|
|
|
|
mail_user: "".to_string(),
|
|
|
|
mail_pass: "".to_string(),
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Ok(x) = env::var("LDAP_API") {
|
|
|
|
config.ldap_api = x.trim().to_string();
|
|
|
|
}
|
2023-09-17 20:02:41 +00:00
|
|
|
if let Ok(x) = env::var("SKYNET_SERVER") {
|
|
|
|
config.skynet_server = GuildId::from(str_to_num::<u64>(&x));
|
2023-09-11 01:25:07 +00:00
|
|
|
}
|
|
|
|
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();
|
|
|
|
}
|
2023-09-16 18:47:39 +00:00
|
|
|
if let Ok(x) = env::var("CSV") {
|
|
|
|
config.csv = x.trim().to_string();
|
|
|
|
}
|
2023-09-11 01:25:07 +00:00
|
|
|
|
2023-09-17 20:02:41 +00:00
|
|
|
if let Ok(x) = env::var("LDAP_DISCORD_AUTH") {
|
|
|
|
config.auth = x.trim().to_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Ok(x) = env::var("DISCORD_TOKEN") {
|
|
|
|
config.discord_token = x.trim().to_string();
|
|
|
|
}
|
|
|
|
|
2023-09-11 01:25:07 +00:00
|
|
|
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<T: FromStr + Default>(x: &str) -> T {
|
|
|
|
x.trim().parse::<T>().unwrap_or_default()
|
|
|
|
}
|
|
|
|
|
2023-09-11 17:18:59 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
2023-09-16 23:14:50 +00:00
|
|
|
pub struct ServerMembers {
|
2023-09-11 17:18:59 +00:00
|
|
|
pub server: GuildId,
|
2023-09-16 17:02:15 +00:00
|
|
|
pub id_wolves: String,
|
2023-09-11 01:25:07 +00:00
|
|
|
pub expiry: String,
|
|
|
|
}
|
2023-09-16 23:14:50 +00:00
|
|
|
impl<'r> FromRow<'r, SqliteRow> for ServerMembers {
|
2023-09-11 17:18:59 +00:00
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let server_tmp: i64 = row.try_get("server")?;
|
|
|
|
let server = GuildId::from(server_tmp as u64);
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
server,
|
2023-09-16 17:02:15 +00:00
|
|
|
id_wolves: row.try_get("id_wolves")?,
|
2023-09-11 17:18:59 +00:00
|
|
|
expiry: row.try_get("expiry")?,
|
2023-09-16 23:14:50 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-17 20:17:57 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
|
|
pub struct ServerMembersWolves {
|
|
|
|
pub server: GuildId,
|
|
|
|
pub id_wolves: String,
|
|
|
|
pub expiry: String,
|
|
|
|
pub email: String,
|
|
|
|
pub discord: Option<String>,
|
|
|
|
pub minecraft: Option<String>,
|
|
|
|
}
|
|
|
|
impl<'r> FromRow<'r, SqliteRow> for ServerMembersWolves {
|
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let server_tmp: i64 = row.try_get("server")?;
|
|
|
|
let server = GuildId::from(server_tmp as u64);
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
server,
|
|
|
|
id_wolves: row.try_get("id_wolves")?,
|
|
|
|
expiry: row.try_get("expiry")?,
|
|
|
|
email: row.try_get("email")?,
|
|
|
|
discord: row.try_get("discord")?,
|
|
|
|
minecraft: row.try_get("minecraft")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-17 14:25:17 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)]
|
2023-09-16 23:14:50 +00:00
|
|
|
pub struct Wolves {
|
|
|
|
pub id_wolves: String,
|
|
|
|
pub email: String,
|
|
|
|
pub discord: Option<String>,
|
|
|
|
pub minecraft: Option<String>,
|
|
|
|
}
|
|
|
|
|
2023-09-17 14:25:17 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, sqlx::FromRow)]
|
|
|
|
pub struct WolvesVerify {
|
|
|
|
pub email: String,
|
|
|
|
pub discord: String,
|
|
|
|
pub auth_code: String,
|
|
|
|
pub date_expiry: String,
|
2023-09-11 17:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
2023-09-11 01:25:07 +00:00
|
|
|
pub struct Servers {
|
2023-09-11 17:18:59 +00:00
|
|
|
pub server: GuildId,
|
2023-09-11 01:25:07 +00:00
|
|
|
pub wolves_api: String,
|
2023-09-11 17:18:59 +00:00
|
|
|
pub role_past: Option<RoleId>,
|
|
|
|
pub role_current: Option<RoleId>,
|
2023-09-11 01:25:07 +00:00
|
|
|
pub member_past: i64,
|
|
|
|
pub member_current: i64,
|
|
|
|
}
|
2023-09-11 17:18:59 +00:00
|
|
|
impl<'r> FromRow<'r, SqliteRow> for Servers {
|
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let server_tmp: i64 = row.try_get("server")?;
|
|
|
|
let server = GuildId::from(server_tmp as u64);
|
|
|
|
let role_past = match row.try_get("role_past") {
|
|
|
|
Ok(x) => {
|
|
|
|
let tmp: i64 = x;
|
|
|
|
Some(RoleId::from(tmp as u64))
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
let role_current = match row.try_get("role_current") {
|
|
|
|
Ok(x) => {
|
|
|
|
let tmp: i64 = x;
|
|
|
|
Some(RoleId::from(tmp as u64))
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
server,
|
|
|
|
wolves_api: row.try_get("wolves_api")?,
|
|
|
|
role_past,
|
|
|
|
role_current,
|
|
|
|
member_past: row.try_get("member_past")?,
|
|
|
|
member_current: row.try_get("member_current")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-09-11 01:25:07 +00:00
|
|
|
|
|
|
|
pub async fn db_init(config: &Config) -> Result<Pool<Sqlite>, Error> {
|
|
|
|
let database = format!("{}/{}", &config.home, &config.database);
|
|
|
|
|
|
|
|
let pool = SqlitePoolOptions::new()
|
|
|
|
.max_connections(5)
|
2023-09-16 23:14:50 +00:00
|
|
|
.connect_with(
|
|
|
|
SqliteConnectOptions::from_str(&format!("sqlite://{}", database))?
|
|
|
|
.foreign_keys(true)
|
|
|
|
.create_if_missing(true),
|
|
|
|
)
|
2023-09-11 01:25:07 +00:00
|
|
|
.await?;
|
|
|
|
|
|
|
|
sqlx::query(
|
2023-09-16 23:14:50 +00:00
|
|
|
"CREATE TABLE IF NOT EXISTS wolves (
|
|
|
|
id_wolves text PRIMARY KEY,
|
|
|
|
email text not null,
|
|
|
|
discord text,
|
2023-09-17 20:17:57 +00:00
|
|
|
minecraft text
|
2023-09-16 23:14:50 +00:00
|
|
|
)",
|
2023-09-11 01:25:07 +00:00
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
|
|
|
|
2023-09-16 23:14:50 +00:00
|
|
|
sqlx::query("CREATE INDEX IF NOT EXISTS index_discord ON wolves (discord)").execute(&pool).await?;
|
|
|
|
|
2023-09-17 14:25:17 +00:00
|
|
|
sqlx::query(
|
|
|
|
"CREATE TABLE IF NOT EXISTS wolves_verify (
|
2023-09-17 17:00:05 +00:00
|
|
|
discord text PRIMARY KEY,
|
|
|
|
email text not null,
|
2023-09-17 14:25:17 +00:00
|
|
|
auth_code text not null,
|
|
|
|
date_expiry text not null
|
|
|
|
)",
|
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
sqlx::query("CREATE INDEX IF NOT EXISTS index_date_expiry ON wolves_verify (date_expiry)")
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
|
|
|
|
2023-09-16 23:14:50 +00:00
|
|
|
sqlx::query(
|
|
|
|
"CREATE TABLE IF NOT EXISTS server_members (
|
|
|
|
server integer not null,
|
|
|
|
id_wolves text not null,
|
|
|
|
expiry text not null,
|
|
|
|
PRIMARY KEY(server,id_wolves),
|
|
|
|
FOREIGN KEY (id_wolves) REFERENCES wolves (id_wolves)
|
|
|
|
)",
|
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
2023-09-11 01:25:07 +00:00
|
|
|
|
|
|
|
sqlx::query(
|
|
|
|
"CREATE TABLE IF NOT EXISTS servers (
|
2023-09-17 18:30:59 +00:00
|
|
|
server integer PRIMARY KEY,
|
2023-09-16 23:14:50 +00:00
|
|
|
wolves_api text not null,
|
|
|
|
role_past integer,
|
|
|
|
role_current integer,
|
|
|
|
member_past integer DEFAULT 0,
|
|
|
|
member_current integer DEFAULT 0
|
|
|
|
)",
|
2023-09-11 01:25:07 +00:00
|
|
|
)
|
|
|
|
.execute(&pool)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(pool)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_server_config(db: &Pool<Sqlite>, server: &GuildId) -> Option<Servers> {
|
|
|
|
sqlx::query_as::<_, Servers>(
|
|
|
|
r#"
|
2023-09-16 23:14:50 +00:00
|
|
|
SELECT *
|
|
|
|
FROM servers
|
|
|
|
WHERE server = ?
|
|
|
|
"#,
|
2023-09-11 01:25:07 +00:00
|
|
|
)
|
|
|
|
.bind(*server.as_u64() as i64)
|
|
|
|
.fetch_one(db)
|
|
|
|
.await
|
|
|
|
.ok()
|
|
|
|
}
|
|
|
|
|
2023-09-17 20:17:57 +00:00
|
|
|
pub async fn get_server_member(db: &Pool<Sqlite>, server: &GuildId, member: &guild::Member) -> Result<ServerMembersWolves, Error> {
|
|
|
|
sqlx::query_as::<_, ServerMembersWolves>(
|
2023-09-11 01:25:07 +00:00
|
|
|
r#"
|
2023-09-16 23:14:50 +00:00
|
|
|
SELECT *
|
2023-09-17 20:17:57 +00:00
|
|
|
FROM server_members
|
|
|
|
JOIN wolves USING (id_wolves)
|
|
|
|
WHERE server = ? AND discord = ?
|
2023-09-16 23:14:50 +00:00
|
|
|
"#,
|
2023-09-11 01:25:07 +00:00
|
|
|
)
|
|
|
|
.bind(*server.as_u64() as i64)
|
|
|
|
.bind(&member.user.name)
|
|
|
|
.fetch_one(db)
|
2023-09-17 20:17:57 +00:00
|
|
|
.await
|
2023-09-11 01:25:07 +00:00
|
|
|
}
|
2023-09-11 17:18:59 +00:00
|
|
|
|
|
|
|
pub async fn get_server_config_bulk(db: &Pool<Sqlite>) -> Vec<Servers> {
|
|
|
|
sqlx::query_as::<_, Servers>(
|
|
|
|
r#"
|
|
|
|
SELECT *
|
|
|
|
FROM servers
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.fetch_all(db)
|
|
|
|
.await
|
|
|
|
.unwrap_or_default()
|
|
|
|
}
|
2023-09-16 19:03:58 +00:00
|
|
|
|
|
|
|
pub fn get_now_iso(short: bool) -> String {
|
|
|
|
let now = Utc::now();
|
|
|
|
if short {
|
|
|
|
format!("{}-{:02}-{:02}", now.year(), now.month(), now.day())
|
|
|
|
} else {
|
|
|
|
now.to_rfc3339_opts(SecondsFormat::Millis, true)
|
|
|
|
}
|
2023-09-16 19:05:50 +00:00
|
|
|
}
|
2023-09-17 14:25:17 +00:00
|
|
|
|
|
|
|
pub fn random_string(len: usize) -> String {
|
|
|
|
thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect()
|
|
|
|
}
|