discord-bot/src/common/set_roles.rs

275 lines
8 KiB
Rust
Raw Normal View History

pub mod normal {
2024-10-28 21:53:04 +00:00
use crate::common::database::{DataBase, ServerMembersWolves, Servers, Wolves};
use crate::get_now_iso;
use serenity::client::Context;
use serenity::model::id::{GuildId, RoleId, UserId};
use sqlx::{Pool, Sqlite};
2024-10-28 21:53:04 +00:00
pub async fn update_server(ctx: &Context, server: &Servers, remove_roles: &[Option<RoleId>], members_changed: &[UserId]) {
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 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<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
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<Sqlite>, 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 {
2024-10-28 21:53:04 +00:00
use crate::common::database::{DataBase, Wolves};
use crate::common::wolves::committees::Committees;
use crate::Config;
use serenity::client::Context;
use serenity::model::guild::Member;
use sqlx::{Pool, Sqlite};
2024-10-28 21:53:04 +00:00
use std::collections::HashMap;
use std::sync::Arc;
pub async fn check_committee(ctx: Arc<Context>) {
let db_lock = {
let data_read = ctx.data.read().await;
data_read.get::<DataBase>().expect("Expected Config 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_global = config_lock.read().await;
let server = config_global.committee_server;
// because to use it to update a single user we need to pre-get the members of teh server
let mut members = server.members(&ctx, None, None).await.unwrap_or_default();
update_committees(&db, &ctx, &config_global, &mut members).await;
}
/**
This function can take a vec of members (or just one) and gives tehm the appropiate roles on teh committee server
*/
pub async fn update_committees(db: &Pool<Sqlite>, ctx: &Context, config: &Config, members: &mut Vec<Member>) {
let server = config.committee_server;
let committee_member = config.committee_role;
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
2024-10-28 21:53:04 +00:00
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) {
2024-10-28 21:53:04 +00:00
Some(x) => Some(x.to_owned()),
None => {
// create teh role if it does not exist
2024-10-28 21:53:04 +00:00
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)
2024-10-28 21:53:04 +00:00
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<Sqlite>) -> Vec<Committees> {
sqlx::query_as::<_, Committees>(
r#"
SELECT *
FROM committees
"#,
)
2024-10-28 21:53:04 +00:00
.fetch_all(db)
.await
.unwrap_or_default()
}
async fn get_server_member_discord(db: &Pool<Sqlite>, user: &i64) -> Option<Wolves> {
sqlx::query_as::<_, Wolves>(
r#"
SELECT *
FROM wolves
WHERE id_wolves = ?
"#,
)
2024-10-28 21:53:04 +00:00
.bind(user)
.fetch_one(db)
.await
.ok()
}
2024-10-28 21:53:04 +00:00
}