diff --git a/src/commands/administration/ban.rs b/src/commands/administration/ban.rs new file mode 100644 index 0000000..a18bdd1 --- /dev/null +++ b/src/commands/administration/ban.rs @@ -0,0 +1,53 @@ +use crate::common::{Context, Error}; +use crate::commands::settings; + +use poise::serenity_prelude as serenity; + +/// Ban a user +#[poise::command(slash_command, prefix_command)] +pub async fn ban(ctx: Context<'_>, + user: serenity::User, + #[rest] + reason: Option) -> Result<(), Error> +{ + let guild = match ctx.guild_id() { + Some(g) => g, + None => { + ctx.reply("This command must be ran within a guild.").await?; + return Ok(()); + } + }; + + if let Some(role) = settings::get_banrole(ctx, guild).await? { + let member = guild.member(&ctx, user.id).await?; + member.add_role(ctx, &role).await?; + }; + + if let Some(reason) = reason { + ctx.reply(format!("{user} has been banned for {reason}.")).await?; + } else { + ctx.reply(format!("{user} has been banned.")).await?; + } + Ok(()) +} + +/// Unban a user +#[poise::command(slash_command, prefix_command)] +pub async fn unban(ctx: Context<'_>, user: serenity::User) -> Result<(), Error> +{ + let guild = match ctx.guild_id() { + Some(g) => g, + None => { + ctx.reply("This command must be ran within a guild.").await?; + return Ok(()); + } + }; + + if let Some(role) = settings::get_banrole(ctx, guild).await? { + let member = guild.member(&ctx, user.id).await?; + member.remove_role(ctx, &role).await?; + }; + + ctx.reply(format!("{user} has been unbanned.")).await?; + Ok(()) +} diff --git a/src/commands/administration/mod.rs b/src/commands/administration/mod.rs new file mode 100644 index 0000000..39efd44 --- /dev/null +++ b/src/commands/administration/mod.rs @@ -0,0 +1 @@ +pub mod ban; \ No newline at end of file diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 1fec11d..fd77fff 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -8,6 +8,7 @@ mod eval; pub mod self_roles; mod settings; mod version; +mod administration; use crate::common::{Data, Error, Context}; @@ -38,6 +39,8 @@ pub fn commands() -> Vec> { eval::eval(), self_roles::role(), settings::setting(), + administration::ban::ban(), + administration::ban::unban(), version::version(), ] } diff --git a/src/commands/settings.rs b/src/commands/settings.rs index 1a2ed78..48f8bef 100644 --- a/src/commands/settings.rs +++ b/src/commands/settings.rs @@ -178,7 +178,65 @@ pub async fn hoist(ctx: Context<'_>, hoist: Option) -> Result<(), Error> { Ok(()) } -#[poise::command(prefix_command, slash_command, subcommands("prefix", "position", "hoist"), subcommand_required)] +pub async fn get_banrole(ctx: Context<'_>, guild: GuildId) -> Result, Error> { + let db = &ctx.data().database; + + let role: Option = match sqlx::query("SELECT banrole FROM settings WHERE guildid = $1") + .bind(guild.get() as i64) + .fetch_one(db).await + { + Ok(r) => r.get(0), + Err(sqlx::Error::RowNotFound) => None, + Err(e) => return Err(Box::new(e)), + }; + + Ok(role.map(|sf| RoleId::new(sf as u64))) +} + +#[poise::command(prefix_command, slash_command)] +pub async fn banrole(ctx: Context<'_>, role: Option) -> Result<(), Error> { + let guild = match ctx.guild_id() { + Some(g) => g, + None => { + ctx.reply("This command must be ran within a guild.").await?; + return Ok(()); + } + }; + + let member = ctx.author_member().await.unwrap(); + + if !member.permissions(ctx).iter().any(|p| p.manage_guild()) { + ctx.reply("You do not have permission to see or change this setting.").await?; + return Ok(()); + } + + match role { + Some(role) => { + let mut tx = ctx.data().database.begin().await?; + + sqlx::query("INSERT INTO settings (guildid, banrole) VALUES ($1, $2) ON CONFLICT (guildid) DO UPDATE SET banrole = EXCLUDED.banrole") + .bind(guild.get() as i64) + .bind(role.id.get() as i64) + .execute(&mut *tx).await?; + + tx.commit().await?; + + common::no_ping_reply(&ctx, format!("The bot will now give banned users the role {role}.")).await?; + } + None => { + let s = match get_banrole(ctx, guild).await? { + Some(r) => format!("{}", guild.role(ctx, r).await?), + None => "not set".into() + }; + + common::no_ping_reply(&ctx, format!("This server's ban role is {s}.")).await?; + } + } + + Ok(()) +} + +#[poise::command(prefix_command, slash_command, subcommands("prefix", "position", "hoist", "banrole"), subcommand_required)] pub async fn setting(_ctx: Context<'_>) -> Result<(), Error> { Ok(()) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8d00fdb..b063c6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -169,6 +169,7 @@ async fn main() -> Result<(), Error> { CREATE TABLE IF NOT EXISTS settings ( guildid BIGINT NOT NULL PRIMARY KEY, positional_role BIGINT, + banrole BIGINT, hoist_selfroles BOOLEAN, prefix TEXT )