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
|
|
|
|
2024-03-03 14:40:37 +00:00
|
|
|
use crate::set_roles::get_server_member_bulk;
|
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};
|
2024-06-03 03:06:47 +00:00
|
|
|
use serde::de::DeserializeOwned;
|
2023-11-23 16:12:28 +00:00
|
|
|
use serenity::client::Context;
|
2023-09-26 00:04:07 +00:00
|
|
|
use serenity::model::id::UserId;
|
2024-03-03 12:49:55 +00:00
|
|
|
use serenity::model::prelude::application_command::ApplicationCommandInteraction;
|
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 {
|
2024-09-16 23:21:07 +00:00
|
|
|
// manages where teh database is stored
|
2023-09-11 01:25:07 +00:00
|
|
|
pub home: String,
|
|
|
|
pub database: String,
|
|
|
|
|
2024-09-16 23:21:07 +00:00
|
|
|
// tokens for discord and other API's
|
2023-09-17 20:02:41 +00:00
|
|
|
pub discord_token: String,
|
2024-09-16 23:21:07 +00:00
|
|
|
pub discord_token_minecraft: String,
|
2023-09-17 20:02:41 +00:00
|
|
|
|
2024-09-16 23:21:07 +00:00
|
|
|
// email settings
|
2023-09-11 01:25:07 +00:00
|
|
|
pub mail_smtp: String,
|
|
|
|
pub mail_user: String,
|
|
|
|
pub mail_pass: String,
|
2023-10-27 00:39:03 +00:00
|
|
|
|
2024-09-16 23:21:07 +00:00
|
|
|
// wolves API base for clubs/socs
|
2023-10-27 00:39:03 +00:00
|
|
|
pub wolves_url: String,
|
2023-09-11 01:25:07 +00:00
|
|
|
}
|
|
|
|
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 {
|
|
|
|
discord_token: "".to_string(),
|
2024-09-16 23:21:07 +00:00
|
|
|
discord_token_minecraft: "".to_string(),
|
2023-09-11 01:25:07 +00:00
|
|
|
|
|
|
|
home: ".".to_string(),
|
|
|
|
database: "database.db".to_string(),
|
|
|
|
|
|
|
|
mail_smtp: "".to_string(),
|
|
|
|
mail_user: "".to_string(),
|
|
|
|
mail_pass: "".to_string(),
|
2023-10-27 00:39:03 +00:00
|
|
|
wolves_url: "".to_string(),
|
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-17 20:02:41 +00:00
|
|
|
if let Ok(x) = env::var("DISCORD_TOKEN") {
|
|
|
|
config.discord_token = x.trim().to_string();
|
|
|
|
}
|
2024-09-16 23:21:07 +00:00
|
|
|
if let Ok(x) = env::var("DISCORD_TOKEN_MINECRAFT") {
|
|
|
|
config.discord_token_minecraft = x.trim().to_string();
|
2024-03-03 12:49:55 +00:00
|
|
|
}
|
2023-09-17 20:02:41 +00:00
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2023-10-27 00:39:03 +00:00
|
|
|
if let Ok(x) = env::var("WOLVES_URL") {
|
|
|
|
config.wolves_url = x.trim().to_string();
|
|
|
|
}
|
|
|
|
|
2023-09-11 01:25:07 +00:00
|
|
|
config
|
|
|
|
}
|
|
|
|
|
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-10-27 00:39:03 +00:00
|
|
|
pub id_wolves: i64,
|
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,
|
2023-10-27 00:39:03 +00:00
|
|
|
pub id_wolves: i64,
|
2023-09-17 20:17:57 +00:00
|
|
|
pub expiry: String,
|
|
|
|
pub email: String,
|
2023-09-25 23:57:03 +00:00
|
|
|
pub discord: Option<UserId>,
|
2023-09-17 20:17:57 +00:00
|
|
|
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);
|
2023-09-25 23:57:03 +00:00
|
|
|
let discord = match row.try_get("discord") {
|
|
|
|
Ok(x) => {
|
|
|
|
let tmp: i64 = x;
|
2023-09-28 16:54:12 +00:00
|
|
|
if tmp == 0 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(UserId::from(tmp as u64))
|
|
|
|
}
|
2023-09-25 23:57:03 +00:00
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
2023-09-26 00:04:07 +00:00
|
|
|
|
2023-09-17 20:17:57 +00:00
|
|
|
Ok(Self {
|
|
|
|
server,
|
|
|
|
id_wolves: row.try_get("id_wolves")?,
|
|
|
|
expiry: row.try_get("expiry")?,
|
|
|
|
email: row.try_get("email")?,
|
2023-09-25 23:57:03 +00:00
|
|
|
discord,
|
2023-09-17 20:17:57 +00:00
|
|
|
minecraft: row.try_get("minecraft")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 17:50:33 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
2023-09-25 23:57:03 +00:00
|
|
|
pub struct Wolves {
|
2023-10-27 00:39:03 +00:00
|
|
|
pub id_wolves: i64,
|
2023-09-25 17:50:33 +00:00
|
|
|
pub email: String,
|
|
|
|
pub discord: Option<UserId>,
|
|
|
|
pub minecraft: Option<String>,
|
|
|
|
}
|
2023-09-25 23:57:03 +00:00
|
|
|
impl<'r> FromRow<'r, SqliteRow> for Wolves {
|
2023-09-25 17:50:33 +00:00
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let discord = match row.try_get("discord") {
|
|
|
|
Ok(x) => {
|
|
|
|
let tmp: i64 = x;
|
2023-09-28 16:54:12 +00:00
|
|
|
if tmp == 0 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(UserId::from(tmp as u64))
|
|
|
|
}
|
2023-09-25 17:50:33 +00:00
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
2023-09-26 00:04:07 +00:00
|
|
|
|
2023-09-25 17:50:33 +00:00
|
|
|
Ok(Self {
|
|
|
|
id_wolves: row.try_get("id_wolves")?,
|
|
|
|
email: row.try_get("email")?,
|
|
|
|
discord,
|
|
|
|
minecraft: row.try_get("minecraft")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 23:57:03 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
2023-09-17 14:25:17 +00:00
|
|
|
pub struct WolvesVerify {
|
|
|
|
pub email: String,
|
2023-09-25 23:57:03 +00:00
|
|
|
pub discord: UserId,
|
2023-09-17 14:25:17 +00:00
|
|
|
pub auth_code: String,
|
|
|
|
pub date_expiry: String,
|
2023-09-11 17:18:59 +00:00
|
|
|
}
|
2023-09-25 23:57:03 +00:00
|
|
|
impl<'r> FromRow<'r, SqliteRow> for WolvesVerify {
|
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let user_tmp: i64 = row.try_get("discord")?;
|
|
|
|
let discord = UserId::from(user_tmp as u64);
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
email: row.try_get("email")?,
|
|
|
|
discord,
|
|
|
|
auth_code: row.try_get("auth_code")?,
|
|
|
|
date_expiry: row.try_get("date_expiry")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-09-11 17:18:59 +00:00
|
|
|
|
2024-08-31 18:21:01 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
|
|
pub struct Committee {
|
|
|
|
pub email: String,
|
|
|
|
pub discord: UserId,
|
|
|
|
pub auth_code: String,
|
|
|
|
pub committee: i64,
|
|
|
|
}
|
|
|
|
impl<'r> FromRow<'r, SqliteRow> for Committee {
|
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let user_tmp: i64 = row.try_get("discord")?;
|
|
|
|
let discord = UserId::from(user_tmp as u64);
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
email: row.try_get("email")?,
|
|
|
|
discord,
|
|
|
|
auth_code: row.try_get("auth_code")?,
|
|
|
|
committee: row.try_get("committee")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2023-09-28 16:54:12 +00:00
|
|
|
if tmp == 0 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(RoleId::from(tmp as u64))
|
|
|
|
}
|
2023-09-11 17:18:59 +00:00
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
let role_current = match row.try_get("role_current") {
|
|
|
|
Ok(x) => {
|
|
|
|
let tmp: i64 = x;
|
2023-09-28 16:54:12 +00:00
|
|
|
if tmp == 0 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(RoleId::from(tmp as u64))
|
|
|
|
}
|
2023-09-11 17:18:59 +00:00
|
|
|
}
|
|
|
|
_ => 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
|
|
|
|
2024-06-03 00:23:57 +00:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
|
|
pub struct Minecraft {
|
|
|
|
pub discord: GuildId,
|
|
|
|
pub minecraft: String,
|
|
|
|
}
|
|
|
|
impl<'r> FromRow<'r, SqliteRow> for Minecraft {
|
|
|
|
fn from_row(row: &'r SqliteRow) -> Result<Self, Error> {
|
|
|
|
let server_tmp: i64 = row.try_get("server_discord")?;
|
|
|
|
let discord = GuildId::from(server_tmp as u64);
|
2024-06-03 03:06:47 +00:00
|
|
|
|
2024-06-03 00:23:57 +00:00
|
|
|
Ok(Self {
|
|
|
|
discord,
|
|
|
|
minecraft: row.try_get("server_minecraft")?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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?;
|
|
|
|
|
2024-03-03 00:18:46 +00:00
|
|
|
// migrations are amazing!
|
2024-03-03 12:49:55 +00:00
|
|
|
sqlx::migrate!("./db/migrations").run(&pool).await.unwrap();
|
2023-09-17 14:25:17 +00:00
|
|
|
|
2023-09-11 01:25:07 +00:00
|
|
|
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)
|
2023-11-23 22:23:31 +00:00
|
|
|
.bind(*member.user.id.as_u64() as i64)
|
2023-09-11 01:25:07 +00:00
|
|
|
.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()
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
pub mod set_roles {
|
|
|
|
use super::*;
|
2024-05-06 01:12:26 +00:00
|
|
|
pub async fn update_server(ctx: &Context, server: &Servers, remove_roles: &[Option<RoleId>], members_changed: &[UserId]) {
|
2023-11-25 21:15:07 +00:00
|
|
|
let db_lock = {
|
|
|
|
let data_read = ctx.data.read().await;
|
|
|
|
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
|
|
|
|
};
|
|
|
|
|
|
|
|
let db = db_lock.read().await;
|
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
let Servers {
|
|
|
|
server,
|
|
|
|
role_past,
|
|
|
|
role_current,
|
|
|
|
..
|
|
|
|
} = server;
|
|
|
|
|
|
|
|
let mut roles_set = [0, 0, 0];
|
|
|
|
let mut members = vec![];
|
|
|
|
|
2023-11-25 21:15:07 +00:00
|
|
|
for member in get_server_member_bulk(&db, server).await {
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Some(x) = member.discord {
|
|
|
|
members.push(x);
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
2023-11-23 21:53:27 +00:00
|
|
|
let mut members_all = members.len();
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Ok(x) = server.members(ctx, None, None).await {
|
|
|
|
for mut member in x {
|
2023-11-25 21:15:07 +00:00
|
|
|
// members_changed acts as an override to only deal with teh users in it
|
|
|
|
if !members_changed.is_empty() && !members_changed.contains(&member.user.id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if members.contains(&member.user.id) {
|
|
|
|
let mut roles = vec![];
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Some(role) = &role_past {
|
|
|
|
if !member.roles.contains(role) {
|
|
|
|
roles_set[0] += 1;
|
|
|
|
roles.push(role.to_owned());
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Some(role) = &role_current {
|
|
|
|
if !member.roles.contains(role) {
|
|
|
|
roles_set[1] += 1;
|
|
|
|
roles.push(role.to_owned());
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Err(e) = member.add_roles(ctx, &roles).await {
|
|
|
|
println!("{:?}", e);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// old and never
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Some(role) = &role_past {
|
|
|
|
if member.roles.contains(role) {
|
|
|
|
members_all += 1;
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
if let Some(role) = &role_current {
|
|
|
|
if member.roles.contains(role) {
|
|
|
|
roles_set[2] += 1;
|
|
|
|
// if theya re not a current member and have the role then remove it
|
|
|
|
if let Err(e) = member.remove_role(ctx, role).await {
|
|
|
|
println!("{:?}", e);
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-23 21:53:27 +00:00
|
|
|
for role in remove_roles.iter().flatten() {
|
|
|
|
if let Err(e) = member.remove_role(ctx, role).await {
|
|
|
|
println!("{:?}", e);
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-25 21:15:07 +00:00
|
|
|
set_server_numbers(&db, server, members_all as i64, members.len() as i64).await;
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
// small bit of logging to note changes over time
|
|
|
|
println!("{:?} Changes: New: +{}, Current: +{}/-{}", server.as_u64(), roles_set[0], roles_set[1], roles_set[2]);
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2024-03-03 12:49:55 +00:00
|
|
|
pub async fn get_server_member_bulk(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
|
2023-11-23 21:53:27 +00:00
|
|
|
sqlx::query_as::<_, ServerMembersWolves>(
|
|
|
|
r#"
|
2023-11-23 16:12:28 +00:00
|
|
|
SELECT *
|
|
|
|
FROM server_members
|
|
|
|
JOIN wolves USING (id_wolves)
|
|
|
|
WHERE (
|
|
|
|
server = ?
|
|
|
|
AND discord IS NOT NULL
|
|
|
|
AND expiry > ?
|
|
|
|
)
|
|
|
|
"#,
|
2023-11-23 21:53:27 +00:00
|
|
|
)
|
|
|
|
.bind(*server.as_u64() as i64)
|
|
|
|
.bind(get_now_iso(true))
|
|
|
|
.fetch_all(db)
|
|
|
|
.await
|
|
|
|
.unwrap_or_default()
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
async fn set_server_numbers(db: &Pool<Sqlite>, server: &GuildId, past: i64, current: i64) {
|
|
|
|
match sqlx::query_as::<_, Wolves>(
|
|
|
|
"
|
2023-11-23 16:12:28 +00:00
|
|
|
UPDATE servers
|
|
|
|
SET member_past = ?, member_current = ?
|
|
|
|
WHERE server = ?
|
|
|
|
",
|
2023-11-23 21:53:27 +00:00
|
|
|
)
|
|
|
|
.bind(past)
|
|
|
|
.bind(current)
|
|
|
|
.bind(*server.as_u64() as i64)
|
|
|
|
.fetch_optional(db)
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(e) => {
|
|
|
|
println!("Failure to insert into {}", server.as_u64());
|
|
|
|
println!("{:?}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub mod get_data {
|
|
|
|
use super::*;
|
2023-11-25 21:15:07 +00:00
|
|
|
use crate::set_roles::update_server;
|
|
|
|
use std::collections::BTreeMap;
|
2023-11-23 21:53:27 +00:00
|
|
|
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
struct WolvesResultUser {
|
|
|
|
committee: String,
|
2024-03-28 12:51:48 +00:00
|
|
|
member_id: String,
|
2023-11-23 21:53:27 +00:00
|
|
|
first_name: String,
|
|
|
|
last_name: String,
|
|
|
|
contact_email: String,
|
2024-09-02 12:51:58 +00:00
|
|
|
opt_in_email: String,
|
2023-11-23 21:53:27 +00:00
|
|
|
student_id: Option<String>,
|
|
|
|
note: Option<String>,
|
|
|
|
expiry: String,
|
|
|
|
requested: String,
|
|
|
|
approved: String,
|
|
|
|
sitename: String,
|
|
|
|
domain: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
struct WolvesResult {
|
|
|
|
success: i8,
|
|
|
|
result: Vec<WolvesResultUser>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
struct WolvesResultLocal {
|
|
|
|
pub id_wolves: String,
|
|
|
|
pub email: String,
|
|
|
|
pub expiry: String,
|
|
|
|
}
|
2023-11-25 21:15:07 +00:00
|
|
|
pub async fn get_wolves(ctx: &Context) {
|
|
|
|
let db_lock = {
|
|
|
|
let data_read = ctx.data.read().await;
|
|
|
|
data_read.get::<DataBase>().expect("Expected Database in TypeMap.").clone()
|
|
|
|
};
|
|
|
|
let db = db_lock.read().await;
|
|
|
|
|
|
|
|
let config_lock = {
|
|
|
|
let data_read = ctx.data.read().await;
|
|
|
|
data_read.get::<Config>().expect("Expected Config in TypeMap.").clone()
|
|
|
|
};
|
|
|
|
let config = config_lock.read().await;
|
|
|
|
|
|
|
|
for server_config in get_server_config_bulk(&db).await {
|
2023-11-23 21:53:27 +00:00
|
|
|
let Servers {
|
|
|
|
server,
|
|
|
|
wolves_api,
|
|
|
|
..
|
2023-11-25 21:15:07 +00:00
|
|
|
} = &server_config;
|
|
|
|
|
|
|
|
let existing_tmp = get_server_member(&db, server).await;
|
|
|
|
let existing = existing_tmp.iter().map(|data| (data.id_wolves, data)).collect::<BTreeMap<_, _>>();
|
|
|
|
|
|
|
|
// list of users that need to be updated for this server
|
|
|
|
let mut user_to_update = vec![];
|
|
|
|
for user in get_wolves_sub(&config, wolves_api).await {
|
2024-03-28 12:51:48 +00:00
|
|
|
let id = user.member_id.parse::<u64>().unwrap_or_default();
|
2023-11-25 21:15:07 +00:00
|
|
|
match existing.get(&(id as i64)) {
|
|
|
|
None => {
|
|
|
|
// user does not exist already, add everything
|
|
|
|
add_users_wolves(&db, &user).await;
|
|
|
|
add_users_server_members(&db, server, &user).await;
|
|
|
|
}
|
|
|
|
Some(old) => {
|
|
|
|
// always update wolves table, in case data has changed
|
|
|
|
add_users_wolves(&db, &user).await;
|
|
|
|
if old.expiry != user.expiry {
|
|
|
|
add_users_server_members(&db, server, &user).await;
|
|
|
|
|
|
|
|
if let Some(discord_id) = old.discord {
|
|
|
|
user_to_update.push(discord_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-23 21:53:27 +00:00
|
|
|
|
2023-11-25 21:15:07 +00:00
|
|
|
if !user_to_update.is_empty() {
|
|
|
|
update_server(ctx, &server_config, &[], &user_to_update).await;
|
2023-11-23 21:53:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-25 21:15:07 +00:00
|
|
|
pub async fn get_server_member(db: &Pool<Sqlite>, server: &GuildId) -> Vec<ServerMembersWolves> {
|
|
|
|
sqlx::query_as::<_, ServerMembersWolves>(
|
|
|
|
r#"
|
|
|
|
SELECT *
|
|
|
|
FROM server_members
|
|
|
|
JOIN wolves USING (id_wolves)
|
|
|
|
WHERE (
|
|
|
|
server = ?
|
|
|
|
AND discord IS NOT NULL
|
|
|
|
)
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
.bind(*server.as_u64() as i64)
|
|
|
|
.fetch_all(db)
|
|
|
|
.await
|
|
|
|
.unwrap_or_default()
|
|
|
|
}
|
|
|
|
|
2023-11-23 21:53:27 +00:00
|
|
|
async fn get_wolves_sub(config: &Config, wolves_api: &str) -> Vec<WolvesResultUser> {
|
|
|
|
if config.wolves_url.is_empty() {
|
|
|
|
return vec![];
|
|
|
|
}
|
|
|
|
|
|
|
|
// get wolves data
|
|
|
|
if let Ok(mut res) = surf::post(&config.wolves_url).header("X-AM-Identity", wolves_api).await {
|
|
|
|
if let Ok(WolvesResult {
|
|
|
|
success,
|
|
|
|
result,
|
|
|
|
}) = res.body_json().await
|
|
|
|
{
|
|
|
|
if success != 1 {
|
|
|
|
return vec![];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
|
2023-11-25 21:15:07 +00:00
|
|
|
async fn add_users_wolves(db: &Pool<Sqlite>, user: &WolvesResultUser) {
|
2023-11-23 21:53:27 +00:00
|
|
|
// expiry
|
|
|
|
match sqlx::query_as::<_, Wolves>(
|
|
|
|
"
|
|
|
|
INSERT INTO wolves (id_wolves, email)
|
|
|
|
VALUES ($1, $2)
|
|
|
|
ON CONFLICT(id_wolves) DO UPDATE SET email = $2
|
|
|
|
",
|
|
|
|
)
|
2024-03-28 12:51:48 +00:00
|
|
|
.bind(&user.member_id)
|
2023-11-23 21:53:27 +00:00
|
|
|
.bind(&user.contact_email)
|
|
|
|
.fetch_optional(db)
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(e) => {
|
|
|
|
println!("Failure to insert into Wolves {:?}", user);
|
|
|
|
println!("{:?}", e);
|
|
|
|
}
|
|
|
|
}
|
2023-11-25 21:15:07 +00:00
|
|
|
}
|
|
|
|
async fn add_users_server_members(db: &Pool<Sqlite>, server: &GuildId, user: &WolvesResultUser) {
|
2023-11-23 21:53:27 +00:00
|
|
|
match sqlx::query_as::<_, ServerMembers>(
|
|
|
|
"
|
|
|
|
INSERT OR REPLACE INTO server_members (server, id_wolves, expiry)
|
|
|
|
VALUES (?1, ?2, ?3)
|
|
|
|
",
|
|
|
|
)
|
|
|
|
.bind(*server.as_u64() as i64)
|
2024-03-28 12:51:48 +00:00
|
|
|
.bind(&user.member_id)
|
2023-11-23 21:53:27 +00:00
|
|
|
.bind(&user.expiry)
|
|
|
|
.fetch_optional(db)
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(e) => {
|
|
|
|
println!("Failure to insert into ServerMembers {} {:?}", server.as_u64(), user);
|
|
|
|
println!("{:?}", e);
|
|
|
|
}
|
2023-11-23 16:12:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-03 00:53:31 +00:00
|
|
|
|
|
|
|
/**
|
2024-03-03 12:49:55 +00:00
|
|
|
For any time ye need to check if a user who calls a command has admin privlages
|
|
|
|
*/
|
|
|
|
pub async fn is_admin(command: &ApplicationCommandInteraction, ctx: &Context) -> Option<String> {
|
2024-03-03 00:53:31 +00:00
|
|
|
let mut admin = false;
|
|
|
|
|
|
|
|
let g_id = match command.guild_id {
|
|
|
|
None => return Some("Not in a server".to_string()),
|
|
|
|
Some(x) => x,
|
|
|
|
};
|
|
|
|
|
|
|
|
let roles_server = g_id.roles(&ctx.http).await.unwrap_or_default();
|
|
|
|
|
|
|
|
if let Ok(member) = g_id.member(&ctx.http, command.user.id).await {
|
|
|
|
if let Some(permissions) = member.permissions {
|
|
|
|
if permissions.administrator() {
|
|
|
|
admin = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for role_id in member.roles {
|
|
|
|
if admin {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if let Some(role) = roles_server.get(&role_id) {
|
|
|
|
if role.permissions.administrator() {
|
|
|
|
admin = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !admin {
|
2024-03-03 12:49:55 +00:00
|
|
|
Some("Administrator permission required".to_string())
|
2024-03-03 00:53:31 +00:00
|
|
|
} else {
|
2024-03-03 12:49:55 +00:00
|
|
|
None
|
2024-03-03 00:53:31 +00:00
|
|
|
}
|
2024-03-03 12:49:55 +00:00
|
|
|
}
|
2024-03-03 14:40:37 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
loop through all members of server
|
|
|
|
get a list of folks with mc accounts that are members
|
|
|
|
and a list that arent members
|
|
|
|
*/
|
2024-06-03 03:06:47 +00:00
|
|
|
pub async fn update_server(server_id: &str, db: &Pool<Sqlite>, g_id: &GuildId, config: &Config) {
|
2024-06-03 01:04:26 +00:00
|
|
|
let mut usernames = vec![];
|
|
|
|
for member in get_server_member_bulk(db, g_id).await {
|
|
|
|
if let Some(x) = member.minecraft {
|
|
|
|
usernames.push(x);
|
2024-03-03 14:40:37 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-03 01:04:26 +00:00
|
|
|
if !usernames.is_empty() {
|
2024-09-16 23:21:07 +00:00
|
|
|
whitelist_update(&usernames, server_id, &config.discord_token_minecraft).await;
|
2024-06-03 01:04:26 +00:00
|
|
|
}
|
2024-03-03 14:40:37 +00:00
|
|
|
}
|
|
|
|
|
2024-05-06 01:09:02 +00:00
|
|
|
async fn post<T: Serialize>(url: &str, bearer: &str, data: &T) {
|
|
|
|
match surf::post(url)
|
|
|
|
.header("Authorization", bearer)
|
|
|
|
.header("Content-Type", "application/json")
|
|
|
|
.header("Accept", "Application/vnd.pterodactyl.v1+json")
|
|
|
|
.body_json(&data)
|
|
|
|
{
|
|
|
|
Ok(req) => {
|
|
|
|
req.await.ok();
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
dbg!(e);
|
2024-03-03 14:40:37 +00:00
|
|
|
}
|
|
|
|
}
|
2024-05-06 01:09:02 +00:00
|
|
|
}
|
2024-03-03 14:40:37 +00:00
|
|
|
|
2024-06-03 02:04:12 +00:00
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
pub struct ServerDetailsResSub {
|
|
|
|
pub identifier: String,
|
|
|
|
pub name: String,
|
|
|
|
pub description: String,
|
2024-06-03 03:06:47 +00:00
|
|
|
pub is_suspended: bool,
|
2024-06-03 02:04:12 +00:00
|
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
pub struct ServerDetailsRes {
|
|
|
|
pub attributes: ServerDetailsResSub,
|
|
|
|
}
|
|
|
|
|
2024-06-03 03:06:47 +00:00
|
|
|
async fn get<T: Serialize + DeserializeOwned>(url: &str, bearer: &str) -> Option<T> {
|
2024-06-03 02:04:12 +00:00
|
|
|
match surf::get(url)
|
|
|
|
.header("Authorization", bearer)
|
|
|
|
.header("Content-Type", "application/json")
|
2024-06-03 03:06:47 +00:00
|
|
|
.header("Accept", "Application/vnd.pterodactyl.v1+json")
|
|
|
|
.recv_json()
|
|
|
|
.await
|
2024-06-03 02:04:12 +00:00
|
|
|
{
|
2024-06-03 03:06:47 +00:00
|
|
|
Ok(res) => Some(res),
|
2024-06-03 02:04:12 +00:00
|
|
|
Err(e) => {
|
|
|
|
dbg!(e);
|
2024-06-03 03:06:47 +00:00
|
|
|
|
2024-06-03 02:04:12 +00:00
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-06 01:09:02 +00:00
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
struct BodyCommand {
|
|
|
|
command: String,
|
|
|
|
}
|
2024-03-03 14:40:37 +00:00
|
|
|
|
2024-05-06 01:09:02 +00:00
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
|
|
struct BodyDelete {
|
|
|
|
root: String,
|
|
|
|
files: Vec<String>,
|
|
|
|
}
|
2024-03-04 22:43:52 +00:00
|
|
|
|
2024-05-06 01:09:02 +00:00
|
|
|
pub async fn whitelist_update(add: &Vec<String>, server: &str, token: &str) {
|
|
|
|
let url_base = format!("http://panel.games.skynet.ie/api/client/servers/{server}");
|
|
|
|
let bearer = format!("Bearer {token}");
|
2024-03-03 14:40:37 +00:00
|
|
|
|
|
|
|
for name in add {
|
|
|
|
let data = BodyCommand {
|
|
|
|
command: format!("whitelist add {name}"),
|
|
|
|
};
|
|
|
|
post(&format!("{url_base}/command"), &bearer, &data).await;
|
|
|
|
}
|
|
|
|
}
|
2024-05-06 01:09:02 +00:00
|
|
|
|
|
|
|
pub async fn whitelist_wipe(server: &str, token: &str) {
|
|
|
|
let url_base = format!("http://panel.games.skynet.ie/api/client/servers/{server}");
|
|
|
|
let bearer = format!("Bearer {token}");
|
|
|
|
|
|
|
|
// delete whitelist
|
|
|
|
let deletion = BodyDelete {
|
|
|
|
root: "/".to_string(),
|
|
|
|
files: vec!["whitelist.json".to_string()],
|
|
|
|
};
|
|
|
|
post(&format!("{url_base}/files/delete"), &bearer, &deletion).await;
|
|
|
|
|
|
|
|
// recreate teh file, passing in the type here so the compiler knows what type of vec it is
|
|
|
|
post::<Vec<&str>>(&format!("{url_base}/files/write?file=%2Fwhitelist.json"), &bearer, &vec![]).await;
|
|
|
|
|
|
|
|
// reload the whitelist
|
|
|
|
let data = BodyCommand {
|
|
|
|
command: "whitelist reload".to_string(),
|
|
|
|
};
|
|
|
|
post(&format!("{url_base}/command"), &bearer, &data).await;
|
|
|
|
}
|
2024-06-03 01:04:26 +00:00
|
|
|
|
2024-06-03 02:04:12 +00:00
|
|
|
pub async fn server_information(server: &str, token: &str) -> Option<ServerDetailsRes> {
|
|
|
|
let url_base = format!("http://panel.games.skynet.ie/api/client/servers/{server}");
|
|
|
|
let bearer = format!("Bearer {token}");
|
|
|
|
get::<ServerDetailsRes>(&format!("{url_base}/"), &bearer).await
|
|
|
|
}
|
|
|
|
|
2024-06-03 01:04:26 +00:00
|
|
|
pub async fn get_minecraft_config(db: &Pool<Sqlite>) -> Vec<Minecraft> {
|
|
|
|
sqlx::query_as::<_, Minecraft>(
|
|
|
|
r#"
|
|
|
|
SELECT *
|
|
|
|
FROM minecraft
|
|
|
|
"#,
|
|
|
|
)
|
2024-06-03 03:06:47 +00:00
|
|
|
.fetch_all(db)
|
|
|
|
.await
|
|
|
|
.unwrap_or_default()
|
2024-06-03 01:04:26 +00:00
|
|
|
}
|
|
|
|
|
2024-06-03 03:06:47 +00:00
|
|
|
pub async fn get_minecraft_config_server(db: &Pool<Sqlite>, g_id: GuildId) -> Vec<Minecraft> {
|
2024-06-03 01:04:26 +00:00
|
|
|
sqlx::query_as::<_, Minecraft>(
|
|
|
|
r#"
|
|
|
|
SELECT *
|
|
|
|
FROM minecraft
|
|
|
|
WHERE server_discord = ?1
|
|
|
|
"#,
|
|
|
|
)
|
2024-06-03 03:06:47 +00:00
|
|
|
.bind(*g_id.as_u64() as i64)
|
|
|
|
.fetch_all(db)
|
|
|
|
.await
|
|
|
|
.unwrap_or_default()
|
|
|
|
}
|