feat: unban command

This commit is contained in:
oSumAtrIX 2022-08-28 02:08:00 +02:00
parent 042fc8c466
commit b7d333c86c
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
2 changed files with 109 additions and 52 deletions

View File

@ -1,13 +1,17 @@
use std::cmp;
use bson::{doc, Document}; use bson::{doc, Document};
use chrono::{Duration, Utc}; use chrono::{Duration, Utc};
use mongodb::options::{UpdateModifications, UpdateOptions}; use mongodb::options::{UpdateModifications, UpdateOptions};
use poise::serenity_prelude::{self as serenity, Member, RoleId}; use poise::serenity_prelude::{self as serenity, Member, RoleId, User};
use tracing::{debug, trace}; use tracing::{debug, trace};
use crate::db::model::Muted; use crate::db::model::Muted;
use crate::utils::moderation::{queue_unmute_member, respond_mute_command, ModerationKind}; use crate::utils::moderation::{
ban_moderation,
queue_unmute_member,
respond_moderation,
BanKind,
ModerationKind,
};
use crate::{Context, Error}; use crate::{Context, Error};
/// Unmute a member. /// Unmute a member.
@ -26,7 +30,7 @@ pub async fn unmute(
pending_unmute.abort(); pending_unmute.abort();
} }
respond_mute_command( respond_moderation(
&ctx, &ctx,
ModerationKind::Unmute( ModerationKind::Unmute(
queue_unmute_member( queue_unmute_member(
@ -40,7 +44,6 @@ pub async fn unmute(
.unwrap(), .unwrap(),
), ),
&member.user, &member.user,
configuration.general.embed_color,
) )
.await .await
} }
@ -88,7 +91,6 @@ pub async fn mute(
let data = &mut *ctx.data().write().await; let data = &mut *ctx.data().write().await;
let configuration = &data.configuration; let configuration = &data.configuration;
let embed_color = configuration.general.embed_color;
let mute = &configuration.general.mute; let mute = &configuration.general.mute;
let mute_role_id = mute.role; let mute_role_id = mute.role;
let take = &mute.take; let take = &mute.take;
@ -170,11 +172,10 @@ pub async fn mute(
), ),
); );
respond_mute_command( respond_moderation(
&ctx, &ctx,
ModerationKind::Mute(reason, format!("<t:{}:F>", unmute_time.timestamp()), result), ModerationKind::Mute(reason, format!("<t:{}:F>", unmute_time.timestamp()), result),
&member.user, &member.user,
embed_color,
) )
.await .await
} }
@ -183,7 +184,7 @@ pub async fn mute(
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn purge( pub async fn purge(
ctx: Context<'_>, ctx: Context<'_>,
#[description = "User"] member: Option<Member>, #[description = "User"] user: Option<User>,
#[description = "Until message"] until: Option<String>, #[description = "Until message"] until: Option<String>,
#[min = 1] #[min = 1]
#[max = 1000] #[max = 1000]
@ -203,10 +204,10 @@ pub async fn purge(
let channel = ctx.channel_id(); let channel = ctx.channel_id();
let too_old_timestamp = Utc::now().timestamp() - MAX_BULK_DELETE_AGO_SECS; let too_old_timestamp = Utc::now().timestamp() - MAX_BULK_DELETE_AGO_SECS;
let user = ctx.discord().http.get_current_user().await?; let current_user = ctx.discord().http.get_current_user().await?;
let image = user let image = current_user
.avatar_url() .avatar_url()
.unwrap_or_else(|| user.default_avatar_url()); .unwrap_or_else(|| current_user.default_avatar_url());
let handle = ctx let handle = ctx
.send(|f| { .send(|f| {
@ -238,13 +239,13 @@ pub async fn purge(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Filter for messages from the user // Filter for messages from the user
if let Some(ref member) = member { if let Some(ref user) = user {
messages = messages messages = messages
.into_iter() .into_iter()
.filter(|msg| msg.author.id == member.user.id) .filter(|msg| msg.author.id == user.id)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
debug!("Filtered messages by {}. Left: {}", member, messages.len()); debug!("Filtered messages by {}. Left: {}", user, messages.len());
} }
// Filter for messages until the g/mutiven id // Filter for messages until the g/mutiven id
@ -291,41 +292,32 @@ pub async fn purge(
Ok(()) Ok(())
} }
/// Ban a member. /// Ban a user.
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn ban( pub async fn ban(
ctx: Context<'_>, ctx: Context<'_>,
#[description = "User"] member: Member, #[description = "User"] user: User,
#[description = "Amount of days to delete messages"] dmd: Option<u8>, #[description = "Amount of days to delete messages"] dmd: Option<u8>,
#[description = "Reason for the ban"] reason: Option<String>, #[description = "Reason for the ban"] reason: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let reason = &reason respond_moderation(
.or_else(|| Some("None specified".to_string())) &ctx,
.unwrap(); ModerationKind::Ban(
reason.clone(),
let ban_result = member ban_moderation(&ctx, BanKind::Ban(user.clone(), dmd, reason)).await,
.ban_with_reason(&ctx.discord().http, cmp::min(dmd.unwrap_or(0), 7), reason) ),
.await; &user,
)
let embed_color = ctx.data().read().await.configuration.general.embed_color; .await
}
ctx.send(|f| {
f.embed(|e| { /// Unban a user.
if let Err(error) = ban_result { #[poise::command(slash_command)]
e.title(format!("Failed to ban {}", member.user.tag())) pub async fn unban(ctx: Context<'_>, #[description = "User"] user: User) -> Result<(), Error> {
.field("Error", error, false) respond_moderation(
} else { &ctx,
e.title(format!("Banned {}", member.user.tag())) ModerationKind::Unban(ban_moderation(&ctx, BanKind::Unban(user.clone())).await),
.thumbnail( &user,
member )
.avatar_url() .await
.unwrap_or_else(|| member.user.default_avatar_url()),
)
.field("Reason", reason, false)
}
.color(embed_color)
})
})
.await?;
Ok(())
} }

View File

@ -1,7 +1,8 @@
use std::cmp;
use std::sync::Arc; use std::sync::Arc;
use mongodb::options::FindOptions; use mongodb::options::FindOptions;
use poise::serenity_prelude::Http; use poise::serenity_prelude::{Http, User};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tracing::{debug, error, trace}; use tracing::{debug, error, trace};
@ -9,13 +10,18 @@ use super::bot::get_data_lock;
use super::*; use super::*;
use crate::db::database::Database; use crate::db::database::Database;
use crate::db::model::Muted; use crate::db::model::Muted;
use crate::serenity::SerenityError;
use crate::{Context, Error}; use crate::{Context, Error};
pub enum ModerationKind { pub enum ModerationKind {
Mute(String, String, Option<Error>), // Reason, Expires, Error Mute(String, String, Option<Error>), // Reason, Expires, Error
Unmute(Option<Error>), // Error Unmute(Option<Error>), // Error
Ban(Option<String>, Option<SerenityError>), // Reason, Error
Unban(Option<SerenityError>), // Error
}
pub enum BanKind {
Ban(User, Option<u8>, Option<String>), // User, Amount of days to delete messages, Reason
Unban(User), // User
} }
pub async fn mute_on_join(ctx: &serenity::Context, new_member: &mut serenity::Member) { pub async fn mute_on_join(ctx: &serenity::Context, new_member: &mut serenity::Member) {
let data = get_data_lock(ctx).await; let data = get_data_lock(ctx).await;
let data = data.read().await; let data = data.read().await;
@ -105,17 +111,19 @@ pub fn queue_unmute_member(
}) })
} }
pub async fn respond_mute_command( // TODO: refactor
pub async fn respond_moderation(
ctx: &Context<'_>, ctx: &Context<'_>,
moderation: ModerationKind, moderation: ModerationKind,
user: &serenity::User, user: &serenity::User,
embed_color: i32,
) -> Result<(), Error> { ) -> Result<(), Error> {
let tag = user.tag(); let tag = user.tag();
let image = user let image = user
.avatar_url() .avatar_url()
.unwrap_or_else(|| user.default_avatar_url()); .unwrap_or_else(|| user.default_avatar_url());
let embed_color = ctx.data().read().await.configuration.general.embed_color;
ctx.send(|f| { ctx.send(|f| {
f.embed(|f| { f.embed(|f| {
match moderation { match moderation {
@ -137,6 +145,29 @@ pub async fn respond_mute_command(
), ),
None => f.title(format!("Unmuted {}", tag)), None => f.title(format!("Unmuted {}", tag)),
}, },
ModerationKind::Ban(reason, error) => {
let f = match error {
Some(err) => f.title(format!("Failed to ban {}", tag)).field(
"Exception",
err.to_string(),
false,
),
None => f.title(format!("Banned {}", tag)),
};
if let Some(reason) = reason {
f.field("Reason", reason, false)
} else {
f
}
},
ModerationKind::Unban(error) => match error {
Some(err) => f.title(format!("Failed to unban {}", tag)).field(
"Exception",
err.to_string(),
false,
),
None => f.title(format!("Unbanned {}", tag)),
},
} }
.color(embed_color) .color(embed_color)
.thumbnail(image) .thumbnail(image)
@ -146,3 +177,37 @@ pub async fn respond_mute_command(
Ok(()) Ok(())
} }
pub async fn ban_moderation(ctx: &Context<'_>, kind: BanKind) -> Option<SerenityError> {
let guild_id = ctx.guild_id().unwrap().0;
let http = &ctx.discord().http;
match kind {
BanKind::Ban(user, dmd, reason) => {
let reason = &reason
.or_else(|| Some("None specified".to_string()))
.unwrap();
let ban_result = http
.ban_user(guild_id, user.id.0, cmp::min(dmd.unwrap_or(0), 7), reason)
.await;
if let Err(err) = ban_result {
error!("Failed to ban user {}: {}", user.id.0, err);
Some(err)
} else {
None
}
},
BanKind::Unban(user) => {
let unban_result = http.remove_ban(guild_id, user.id.0, None).await;
if let Err(err) = unban_result {
error!("Failed to unban user {}: {}", user.id.0, err);
Some(err)
} else {
None
}
},
}
}