use serenity::{ async_trait, client::{Context, EventHandler}, model::gateway::{GatewayIntents, Ready}, Client, }; use skynet_discord_bot::{get_config, set_roles, 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; #[tokio::main] async fn main() { let config = get_config(); let db = match db_init(&config).await { Ok(x) => x, Err(_) => return, }; // Intents are a bitflag, bitwise operations can be used to dictate which intents to use let intents = GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS; // Build our client. let mut client = Client::builder(&config.discord_token, intents) .event_handler(Handler {}) .await .expect("Error creating client"); { let mut data = client.data.write().await; data.insert::(Arc::new(RwLock::new(config))); data.insert::(Arc::new(RwLock::new(db))); } if let Err(why) = client.start().await { println!("Client error: {:?}", why); } } struct Handler; #[async_trait] impl EventHandler for Handler { async fn ready(&self, ctx: Context, ready: Ready) { let ctx = Arc::new(ctx); println!("{} is connected!", ready.user.name); // this goes into each server and sets roles for each wolves member check_bulk(Arc::clone(&ctx)).await; // u[date committee server committee::check_committee(Arc::clone(&ctx)).await; // finish up process::exit(0); } } async fn check_bulk(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; 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() } }