diff --git a/youmubot-core/src/admin/mod.rs b/youmubot-core/src/admin/mod.rs index 6680c0a..c173b8e 100644 --- a/youmubot-core/src/admin/mod.rs +++ b/youmubot-core/src/admin/mod.rs @@ -7,17 +7,13 @@ use serenity::{ }, model::channel::{Channel, Message}, }; -use soft_ban::{SOFT_BAN_COMMAND, SOFT_BAN_INIT_COMMAND}; use youmubot_prelude::*; -mod soft_ban; -pub use soft_ban::watch_soft_bans; - pub mod ignore; #[group] #[description = "Administrative commands for the server."] -#[commands(clean, ban, kick, soft_ban, soft_ban_init)] +#[commands(clean, ban, kick)] struct Admin; #[command] diff --git a/youmubot-core/src/admin/soft_ban.rs b/youmubot-core/src/admin/soft_ban.rs deleted file mode 100644 index 5a8239e..0000000 --- a/youmubot-core/src/admin/soft_ban.rs +++ /dev/null @@ -1,164 +0,0 @@ -use crate::db::{ServerSoftBans, SoftBans}; -use chrono::offset::Utc; -use futures_util::{stream, TryStreamExt}; -use serenity::{ - framework::standard::{macros::command, Args, CommandResult}, - model::{channel::Message, id}, -}; -use youmubot_prelude::*; - -#[command] -#[required_permissions(ADMINISTRATOR)] -#[description = "Soft-ban an user, might be with a certain amount of time. Re-banning an user removes the ban itself."] -#[usage = "user#1234 [time]"] -#[example = "user#1234 5s"] -#[min_args(1)] -#[max_args(2)] -#[only_in("guilds")] -pub async fn soft_ban(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { - let user = args.single::()?.0.to_user(&ctx).await?; - let data = ctx.data.read().await; - let duration = if args.is_empty() { - None - } else { - Some(args.single::()?) - }; - let guild = msg - .guild_id - .ok_or_else(|| Error::msg("Command is guild only"))?; - - let mut db = SoftBans::open(&data); - let val = db - .borrow()? - .get(&guild) - .map(|v| (v.role, v.periodical_bans.get(&user.id).cloned())); - let (role, current_ban_deadline) = match val { - None => { - msg.reply(&ctx, "⚠ This server has not enabled the soft-ban feature. Check out `y!a soft-ban-init`.").await?; - return Ok(()); - } - Some(v) => v, - }; - - let member = guild.member(&ctx, &user).await?; - match duration { - None if member.roles.contains(&role) => { - msg.reply(&ctx, format!("⛓ Lifting soft-ban for user {}.", user.tag())) - .await?; - member.remove_role(&ctx, role).await?; - return Ok(()); - } - None => { - msg.reply(&ctx, format!("⛓ Soft-banning user {}.", user.tag())) - .await?; - } - Some(v) => { - // Add the duration into the ban timeout. - let until = - current_ban_deadline.unwrap_or_else(Utc::now) + chrono::Duration::from_std(v.0)?; - msg.reply( - &ctx, - format!("⛓ Soft-banning user {} until {}.", user.tag(), until), - ) - .await?; - db.borrow_mut()? - .get_mut(&guild) - .map(|v| v.periodical_bans.insert(user.id, until)); - } - } - member.add_role(&ctx, role).await?; - - Ok(()) -} - -#[command] -#[required_permissions(ADMINISTRATOR)] -#[description = "Sets up the soft-ban command. This command can only be run once.\nThe soft-ban command assigns a role, temporarily, to a user."] -#[usage = "{soft_ban_role_id}"] -#[num_args(1)] -#[only_in("guilds")] -pub async fn soft_ban_init(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { - let role_id = args.single::()?.0; - let data = ctx.data.read().await; - let guild = msg.guild_id.unwrap().to_partial_guild(&ctx).await?; - // Check whether the role_id is the one we wanted - if !guild.roles.contains_key(&role_id) { - return Err(Error::msg(format!("{} is not a role in this server.", role_id)).into()); - } - // Check if we already set up - let mut db = SoftBans::open(&data); - let set_up = db.borrow()?.contains_key(&guild.id); - - if !set_up { - db.borrow_mut()? - .insert(guild.id, ServerSoftBans::new(role_id)); - msg.react(&ctx, '👌').await?; - } else { - return Err(Error::msg("Server already set up soft-bans.").into()); - } - Ok(()) -} - -// Watch the soft bans. Blocks forever. -pub async fn watch_soft_bans(cache_http: impl CacheHttp, data: AppData) { - loop { - // Scope so that locks are released - { - // Poll the data for any changes. - let data = data.read().await; - let mut data = SoftBans::open(&data); - let mut db = data.borrow().unwrap().clone(); - let now = Utc::now(); - for (server_id, bans) in db.iter_mut() { - let server_name: String = match server_id.to_partial_guild(cache_http.http()).await - { - Err(_) => continue, - Ok(v) => v.name, - }; - let to_remove: Vec<_> = bans - .periodical_bans - .iter() - .filter_map(|(user, time)| if time <= &now { Some(user) } else { None }) - .cloned() - .collect(); - if let Err(e) = to_remove - .into_iter() - .map(|user_id| { - bans.periodical_bans.remove(&user_id); - lift_soft_ban_for( - &cache_http, - *server_id, - &server_name[..], - bans.role, - user_id, - ) - }) - .collect::>() - .try_collect::<()>() - .await - { - eprintln!("Error while scanning soft-bans list: {}", e) - } - } - *(data.borrow_mut().unwrap()) = db; - } - // Sleep the thread for a minute - tokio::time::sleep(std::time::Duration::from_secs(60)).await - } -} - -async fn lift_soft_ban_for( - cache_http: impl CacheHttp, - server_id: id::GuildId, - server_name: &str, - ban_role: id::RoleId, - user_id: id::UserId, -) -> Result<()> { - let m = server_id.member(&cache_http, user_id).await?; - println!( - "Soft-ban for `{}` in server `{}` unlifted.", - m.user.name, server_name - ); - m.remove_role(cache_http.http(), ban_role).await?; - Ok(()) -} diff --git a/youmubot-core/src/db.rs b/youmubot-core/src/db.rs index 0b4d9c1..9aa63d4 100644 --- a/youmubot-core/src/db.rs +++ b/youmubot-core/src/db.rs @@ -1,42 +1,15 @@ -use chrono::{DateTime, Utc}; - use serde::{Deserialize, Serialize}; use serenity::model::{ channel::ReactionType, - id::{MessageId, RoleId, UserId}, + id::{MessageId, RoleId}, }; use std::collections::HashMap; use youmubot_db::{GuildMap, DB}; use youmubot_prelude::*; -/// A list of SoftBans for all servers. -pub type SoftBans = DB>; - /// A list of assignable roles for all servers. pub type Roles = DB>; -/// For the admin commands: -/// - Each server might have a `soft ban` role implemented. -/// - We allow periodical `soft ban` applications. - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct ServerSoftBans { - /// The soft-ban role. - pub role: RoleId, - /// List of all to-unban people. - pub periodical_bans: HashMap>, -} - -impl ServerSoftBans { - // Create a new, implemented role. - pub fn new(role: RoleId) -> Self { - Self { - role, - periodical_bans: HashMap::new(), - } - } -} - /// Represents a server's role list. #[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct RoleList { diff --git a/youmubot-core/src/lib.rs b/youmubot-core/src/lib.rs index 00f2783..d2470ae 100644 --- a/youmubot-core/src/lib.rs +++ b/youmubot-core/src/lib.rs @@ -10,7 +10,7 @@ use serenity::{ pub use admin::ADMIN_GROUP; pub use community::COMMUNITY_GROUP; pub use fun::FUN_GROUP; -use youmubot_prelude::{announcer::CacheAndHttp, *}; +use youmubot_prelude::*; pub mod admin; pub mod community; @@ -43,7 +43,6 @@ impl + Send + Sync> HasCoreEnv for T { /// Sets up all databases in the client. pub async fn setup(path: &std::path::Path, data: &mut TypeMap, prelude: Env) -> Result { - db::SoftBans::insert_into(&mut *data, &path.join("soft_bans.yaml"))?; db::load_role_list( &mut *data, &path.join("roles_v2.yaml"), @@ -56,15 +55,6 @@ pub async fn setup(path: &std::path::Path, data: &mut TypeMap, prelude: Env) -> CoreEnv::new(prelude).await } -pub fn ready_hook(ctx: &Context) -> CommandResult { - // Create handler threads - tokio::spawn(admin::watch_soft_bans( - CacheAndHttp::from_context(ctx), - ctx.data.clone(), - )); - Ok(()) -} - // A help command #[help] pub async fn help( diff --git a/youmubot/src/main.rs b/youmubot/src/main.rs index ca2d25a..bb1d548 100644 --- a/youmubot/src/main.rs +++ b/youmubot/src/main.rs @@ -38,6 +38,7 @@ impl Handler { self.hooks.push(RwLock::new(Box::new(f))); } + #[allow(unused)] fn push_ready_hook(&mut self, f: fn(&Context) -> CommandResult) { self.ready_hooks.push(f); } @@ -184,8 +185,6 @@ async fn main() { } let mut handler = Handler::new(); - #[cfg(feature = "core")] - handler.push_ready_hook(youmubot_core::ready_hook); // Set up hooks #[cfg(feature = "osu")] {