diff --git a/src/bin/update_users.rs b/src/bin/update_users.rs index 133dd13..9b98c79 100644 --- a/src/bin/update_users.rs +++ b/src/bin/update_users.rs @@ -4,16 +4,11 @@ use serenity::{ model::gateway::{GatewayIntents, Ready}, Client, }; -use skynet_discord_bot::{get_config, set_roles, Config}; +use skynet_discord_bot::{get_config, Config}; use std::{process, sync::Arc}; -use std::collections::HashMap; -use serenity::builder::EditRole; -use serenity::model::guild::{Member, Role}; -use serenity::model::id::{GuildId, RoleId, UserId}; -use sqlx::{Pool, Sqlite}; use tokio::sync::RwLock; -use skynet_discord_bot::common::database::{db_init, get_server_config_bulk, DataBase, Servers, Wolves}; -use skynet_discord_bot::common::wolves::committees::Committees; +use skynet_discord_bot::common::database::{db_init, get_server_config_bulk, DataBase}; +use skynet_discord_bot::common::set_roles::{committee, normal}; #[tokio::main] async fn main() { @@ -70,135 +65,6 @@ async fn check_bulk(ctx: Arc) { let db = db_lock.read().await; for server_config in get_server_config_bulk(&db).await { - set_roles::update_server(&ctx, &server_config, &[], &[]).await; - } -} - -// for updating committee members -pub mod committee { - use super::*; - - pub(crate) async fn check_committee(ctx: Arc) { - let db_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Config in TypeMap.").clone() - }; - - let db = db_lock.read().await; - - let server = GuildId(1220150752656363520); - let mut members = server.members(&ctx, None, None).await.unwrap_or_default(); - - update_committees(&db, &ctx, &mut members).await; - } - - pub async fn update_committees(db: &Pool, ctx: &Context, members: &mut Vec){ - let server = GuildId(1220150752656363520); - let committee_member = RoleId(1226602779968274573); - let committees = get_committees(db).await; - - // information about the server - let roles = server.roles(&ctx).await.unwrap_or_default(); - - // make a hashmap of the nameof roles to quickly get them out again - let mut roles_name = HashMap::new(); - for role in roles.values() { - roles_name.insert(role.name.to_owned(), role.to_owned()); - } - - - // a map of users and the roles they are goign to be getting - let mut users_roles = HashMap::new(); - - // a list of all the roles that can be removed from folks who should have them - let mut committee_roles = vec![ - committee_member - ]; - - for committee in &committees { - // get the role for this committee/club/soc - let role = match roles_name.get(&committee.name) { - Some(x) => {Some(x.to_owned())} - None => { - // create teh role if it does not exist - match server.create_role(&ctx, |r| r.hoist(false).mentionable(true).name(&committee.name)).await{ - Ok(x) => { Some(x) } - Err(_) => {None} - } - } - }; - - // so if the role exists - if let Some(r) = role { - committee_roles.push(r.id); - - for id_wolves in &committee.committee { - // ID in this is the wolves ID, so we need to get a matching discord ID (if one exists) - if let Some(x) = get_server_member_discord(&db, id_wolves).await { - if let Some(member_tmp) = x.discord { - let values = users_roles.entry(member_tmp).or_insert(vec![]); - values.push(r.id); - } - } - } - } - } - - // now we have a map of all users that should get roles time to go through all the folks on teh server - for member in members { - let roles_required = match users_roles.get(&member.user.id) { - None => { - vec![] - } - Some(x) => { - let mut combined = x.to_owned(); - // this is the main role, since it provides access to everything. - combined.push(committee_member); - combined - } - }; - - // get a list of all the roles to remove from someone - let mut roles_rem = vec![]; - for role in &committee_roles { - if !roles_required.contains(role) { - roles_rem.push(role.to_owned()); - } - } - if !roles_rem.is_empty() { - member.remove_roles(&ctx, &roles_rem).await.unwrap_or_default(); - } - - if !roles_required.is_empty() { - // these roles are flavor roles, only there to make folks mentionable - member.add_roles(&ctx, &roles_required).await.unwrap_or_default(); - } - } - } - - async fn get_committees(db: &Pool) -> Vec { - sqlx::query_as::<_, Committees>( - r#" - SELECT * - FROM committees - "#, - ) - .fetch_all(db) - .await - .unwrap_or_default() - } - - async fn get_server_member_discord(db: &Pool, user: &i64) -> Option { - sqlx::query_as::<_, Wolves>( - r#" - SELECT * - FROM wolves - WHERE id_wolves = ? - "#, - ) - .bind(user) - .fetch_one(db) - .await - .ok() + normal::update_server(&ctx, &server_config, &[], &[]).await; } } \ No newline at end of file diff --git a/src/commands/add_server.rs b/src/commands/add_server.rs index 1886e56..f049028 100644 --- a/src/commands/add_server.rs +++ b/src/commands/add_server.rs @@ -1,15 +1,16 @@ use serenity::{ - builder::CreateApplicationCommand, - client::Context, - model::{ - application::interaction::application_command::ApplicationCommandInteraction, - prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue}, - }, + builder::CreateApplicationCommand, + client::Context, + model::{ + application::interaction::application_command::ApplicationCommandInteraction, + prelude::{command::CommandOptionType, interaction::application_command::CommandDataOptionValue}, + }, }; use skynet_discord_bot::common::wolves::cns::get_wolves; -use skynet_discord_bot::{is_admin, set_roles::update_server}; +use skynet_discord_bot::is_admin; use sqlx::{Error, Pool, Sqlite}; use skynet_discord_bot::common::database::{get_server_config, DataBase, Servers}; +use skynet_discord_bot::common::set_roles::normal::update_server; pub async fn run(command: &ApplicationCommandInteraction, ctx: &Context) -> String { // check if user has high enough permisssions diff --git a/src/common/minecraft.rs b/src/common/minecraft.rs index 55ce53b..40fbb4f 100644 --- a/src/common/minecraft.rs +++ b/src/common/minecraft.rs @@ -4,7 +4,7 @@ use sqlx::{Error, FromRow, Pool, Row, Sqlite}; use serenity::model::id::GuildId; use sqlx::sqlite::SqliteRow; use crate::Config; -use crate::set_roles::get_server_member_bulk; +use crate::common::set_roles::normal::get_server_member_bulk; #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/src/common/mod.rs b/src/common/mod.rs index 3302619..6b1adc9 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,3 +1,4 @@ pub mod wolves; pub mod database; -pub mod minecraft; \ No newline at end of file +pub mod minecraft; +pub mod set_roles; \ No newline at end of file diff --git a/src/common/set_roles.rs b/src/common/set_roles.rs new file mode 100644 index 0000000..20c8e6d --- /dev/null +++ b/src/common/set_roles.rs @@ -0,0 +1,266 @@ +pub mod normal { + use serenity::client::Context; + use serenity::model::id::{GuildId, RoleId, UserId}; + use sqlx::{Pool, Sqlite}; + use crate::common::database::{DataBase, ServerMembersWolves, Servers, Wolves}; + use crate::get_now_iso; + + pub async fn update_server(ctx: &Context, server: &Servers, remove_roles: &[Option], members_changed: &[UserId]) { + let db_lock = { + let data_read = ctx.data.read().await; + data_read.get::().expect("Expected Database in TypeMap.").clone() + }; + + let db = db_lock.read().await; + + let Servers { + server, + role_past, + role_current, + .. + } = server; + + let mut roles_set = [0, 0, 0]; + let mut members = vec![]; + + for member in get_server_member_bulk(&db, server).await { + if let Some(x) = member.discord { + members.push(x); + } + } + let mut members_all = members.len(); + + if let Ok(x) = server.members(ctx, None, None).await { + for mut member in x { + // 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; + } + + if members.contains(&member.user.id) { + let mut roles = vec![]; + + if let Some(role) = &role_past { + if !member.roles.contains(role) { + roles_set[0] += 1; + roles.push(role.to_owned()); + } + } + + if !member.roles.contains(role_current) { + roles_set[1] += 1; + roles.push(role_current.to_owned()); + } + + if let Err(e) = member.add_roles(ctx, &roles).await { + println!("{:?}", e); + } + } else { + // old and never + + if let Some(role) = &role_past { + if member.roles.contains(role) { + members_all += 1; + } + } + + if member.roles.contains(role_current) { + 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_current).await { + println!("{:?}", e); + } + } + } + for role in remove_roles.iter().flatten() { + if let Err(e) = member.remove_role(ctx, role).await { + println!("{:?}", e); + } + } + } + } + + set_server_numbers(&db, server, members_all as i64, members.len() as i64).await; + + // 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]); + } + + pub async fn get_server_member_bulk(db: &Pool, server: &GuildId) -> Vec { + sqlx::query_as::<_, ServerMembersWolves>( + r#" + SELECT * + FROM server_members + JOIN wolves USING (id_wolves) + WHERE ( + server = ? + AND discord IS NOT NULL + AND expiry > ? + ) + "#, + ) + .bind(*server.as_u64() as i64) + .bind(get_now_iso(true)) + .fetch_all(db) + .await + .unwrap_or_default() + } + + async fn set_server_numbers(db: &Pool, server: &GuildId, past: i64, current: i64) { + match sqlx::query_as::<_, Wolves>( + " + UPDATE servers + SET member_past = ?, member_current = ? + WHERE server = ? + ", + ) + .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); + } + } + } +} + +// for updating committee members +pub mod committee { + use std::collections::HashMap; + use std::sync::Arc; + use serenity::client::Context; + use serenity::model::guild::Member; + use serenity::model::id::{GuildId, RoleId}; + use sqlx::{Pool, Sqlite}; + use crate::common::database::{DataBase, Wolves}; + use crate::common::wolves::committees::Committees; + + pub async fn check_committee(ctx: Arc) { + let db_lock = { + let data_read = ctx.data.read().await; + data_read.get::().expect("Expected Config in TypeMap.").clone() + }; + + let db = db_lock.read().await; + + let server = GuildId(1220150752656363520); + let mut members = server.members(&ctx, None, None).await.unwrap_or_default(); + + update_committees(&db, &ctx, &mut members).await; + } + + pub async fn update_committees(db: &Pool, ctx: &Context, members: &mut Vec){ + let server = GuildId(1220150752656363520); + let committee_member = RoleId(1226602779968274573); + let committees = get_committees(db).await; + + // information about the server + let roles = server.roles(&ctx).await.unwrap_or_default(); + + // make a hashmap of the nameof roles to quickly get them out again + let mut roles_name = HashMap::new(); + for role in roles.values() { + roles_name.insert(role.name.to_owned(), role.to_owned()); + } + + + // a map of users and the roles they are goign to be getting + let mut users_roles = HashMap::new(); + + // a list of all the roles that can be removed from folks who should have them + let mut committee_roles = vec![ + committee_member + ]; + + for committee in &committees { + // get the role for this committee/club/soc + let role = match roles_name.get(&committee.name) { + Some(x) => {Some(x.to_owned())} + None => { + // create teh role if it does not exist + match server.create_role(&ctx, |r| r.hoist(false).mentionable(true).name(&committee.name)).await{ + Ok(x) => { Some(x) } + Err(_) => {None} + } + } + }; + + // so if the role exists + if let Some(r) = role { + committee_roles.push(r.id); + + for id_wolves in &committee.committee { + // ID in this is the wolves ID, so we need to get a matching discord ID (if one exists) + if let Some(x) = get_server_member_discord(&db, id_wolves).await { + if let Some(member_tmp) = x.discord { + let values = users_roles.entry(member_tmp).or_insert(vec![]); + values.push(r.id); + } + } + } + } + } + + // now we have a map of all users that should get roles time to go through all the folks on teh server + for member in members { + let roles_required = match users_roles.get(&member.user.id) { + None => { + vec![] + } + Some(x) => { + let mut combined = x.to_owned(); + // this is the main role, since it provides access to everything. + combined.push(committee_member); + combined + } + }; + + // get a list of all the roles to remove from someone + let mut roles_rem = vec![]; + for role in &committee_roles { + if !roles_required.contains(role) { + roles_rem.push(role.to_owned()); + } + } + if !roles_rem.is_empty() { + member.remove_roles(&ctx, &roles_rem).await.unwrap_or_default(); + } + + if !roles_required.is_empty() { + // these roles are flavor roles, only there to make folks mentionable + member.add_roles(&ctx, &roles_required).await.unwrap_or_default(); + } + } + } + + async fn get_committees(db: &Pool) -> Vec { + sqlx::query_as::<_, Committees>( + r#" + SELECT * + FROM committees + "#, + ) + .fetch_all(db) + .await + .unwrap_or_default() + } + + async fn get_server_member_discord(db: &Pool, user: &i64) -> Option { + sqlx::query_as::<_, Wolves>( + r#" + SELECT * + FROM wolves + WHERE id_wolves = ? + "#, + ) + .bind(user) + .fetch_one(db) + .await + .ok() + } +} \ No newline at end of file diff --git a/src/common/wolves.rs b/src/common/wolves.rs index 380d25a..0560b27 100644 --- a/src/common/wolves.rs +++ b/src/common/wolves.rs @@ -51,7 +51,7 @@ async fn add_users_wolves(db: &Pool, user: &WolvesResultUserMin) { This is getting data for Clubs and Socs */ pub mod cns { - use crate::set_roles::update_server; + use crate::common::set_roles::normal::update_server; use std::collections::BTreeMap; use serde::{Deserialize, Serialize}; use serenity::client::Context; diff --git a/src/lib.rs b/src/lib.rs index 5dbbe0d..335f51e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,25 +2,15 @@ pub mod common; use dotenvy::dotenv; use serde::{Deserialize, Serialize}; -use serenity::{ - model::id::{GuildId, RoleId}, - prelude::TypeMapKey, -}; +use serenity::prelude::TypeMapKey; -use crate::set_roles::get_server_member_bulk; use chrono::{Datelike, SecondsFormat, Utc}; use rand::{distributions::Alphanumeric, thread_rng, Rng}; use serde::de::DeserializeOwned; use serenity::client::Context; -use serenity::model::id::UserId; use serenity::model::prelude::application_command::ApplicationCommandInteraction; -use sqlx::{ - Pool, Sqlite, -}; use std::{env, sync::Arc}; use tokio::sync::RwLock; -use common::database::{ServerMembersWolves, Servers}; - pub struct Config { // manages where teh database is stored pub home: String, @@ -103,133 +93,6 @@ pub fn random_string(len: usize) -> String { thread_rng().sample_iter(&Alphanumeric).take(len).map(char::from).collect() } -pub mod set_roles { - use crate::common::database::{DataBase, Wolves}; - use super::*; - pub async fn update_server(ctx: &Context, server: &Servers, remove_roles: &[Option], members_changed: &[UserId]) { - let db_lock = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected Database in TypeMap.").clone() - }; - - let db = db_lock.read().await; - - let Servers { - server, - role_past, - role_current, - .. - } = server; - - let mut roles_set = [0, 0, 0]; - let mut members = vec![]; - - for member in get_server_member_bulk(&db, server).await { - if let Some(x) = member.discord { - members.push(x); - } - } - let mut members_all = members.len(); - - if let Ok(x) = server.members(ctx, None, None).await { - for mut member in x { - // 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; - } - - if members.contains(&member.user.id) { - let mut roles = vec![]; - - if let Some(role) = &role_past { - if !member.roles.contains(role) { - roles_set[0] += 1; - roles.push(role.to_owned()); - } - } - - if !member.roles.contains(role_current) { - roles_set[1] += 1; - roles.push(role_current.to_owned()); - } - - if let Err(e) = member.add_roles(ctx, &roles).await { - println!("{:?}", e); - } - } else { - // old and never - - if let Some(role) = &role_past { - if member.roles.contains(role) { - members_all += 1; - } - } - - if member.roles.contains(role_current) { - 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_current).await { - println!("{:?}", e); - } - } - } - for role in remove_roles.iter().flatten() { - if let Err(e) = member.remove_role(ctx, role).await { - println!("{:?}", e); - } - } - } - } - - set_server_numbers(&db, server, members_all as i64, members.len() as i64).await; - - // 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]); - } - - pub async fn get_server_member_bulk(db: &Pool, server: &GuildId) -> Vec { - sqlx::query_as::<_, ServerMembersWolves>( - r#" - SELECT * - FROM server_members - JOIN wolves USING (id_wolves) - WHERE ( - server = ? - AND discord IS NOT NULL - AND expiry > ? - ) - "#, - ) - .bind(*server.as_u64() as i64) - .bind(get_now_iso(true)) - .fetch_all(db) - .await - .unwrap_or_default() - } - - async fn set_server_numbers(db: &Pool, server: &GuildId, past: i64, current: i64) { - match sqlx::query_as::<_, Wolves>( - " - UPDATE servers - SET member_past = ?, member_current = ? - WHERE server = ? - ", - ) - .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); - } - } - } -} - /** For any time ye need to check if a user who calls a command has admin privlages */