mirror of
https://github.com/revanced/revanced-discord-bot.git
synced 2025-05-01 15:04:25 +02:00
feat: media and logging channels and unban command
This commit is contained in:
parent
b7d333c86c
commit
4ab4c7e00c
@ -5,7 +5,9 @@
|
|||||||
"mute": {
|
"mute": {
|
||||||
"role": 0,
|
"role": 0,
|
||||||
"take": [0]
|
"take": [0]
|
||||||
}
|
},
|
||||||
|
"media_channels": [0],
|
||||||
|
"logging_channel": 0
|
||||||
},
|
},
|
||||||
"administrators": {
|
"administrators": {
|
||||||
"roles": [0],
|
"roles": [0],
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
"mute": {
|
"mute": {
|
||||||
"role": 953984696491061289,
|
"role": 953984696491061289,
|
||||||
"take": [996121272897519687, 965267139902705744, 995126555867086938]
|
"take": [996121272897519687, 965267139902705744, 995126555867086938]
|
||||||
}
|
},
|
||||||
|
"media_channels": [954148665646260314],
|
||||||
|
"logging_channel": 952987428786941952
|
||||||
},
|
},
|
||||||
"administrators": {
|
"administrators": {
|
||||||
"roles": [955220417969262612],
|
"roles": [955220417969262612],
|
||||||
|
@ -19,15 +19,17 @@
|
|||||||
"description": "The id of the role."
|
"description": "The id of the role."
|
||||||
},
|
},
|
||||||
"take": {
|
"take": {
|
||||||
"type": "array",
|
"$ref": "#/$defs/roles"
|
||||||
"items": {
|
}
|
||||||
"type": "integer"
|
}
|
||||||
},
|
},
|
||||||
"description": "A list of role ids which will be revoked from the user.",
|
"media_channels": {
|
||||||
"minItems": 1,
|
"$ref": "#/$defs/channels",
|
||||||
"uniqueItems": true
|
"description": "A list of channel ids where only media is allowed."
|
||||||
}
|
},
|
||||||
}
|
"logging_channel": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "The id of the channel to send logs to."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -39,13 +41,8 @@
|
|||||||
"description": "A list of role ids. Users with these roles have administrative privileges over this Discord bot."
|
"description": "A list of role ids. Users with these roles have administrative privileges over this Discord bot."
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"type": "array",
|
"$ref": "#/$defs/users",
|
||||||
"items": {
|
"description": "A list of user ids. Users with these ids have administrative privileges over this Discord bot."
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"description": "A list of user ids. Users with these ids have administrative privileges over this Discord bot.",
|
|
||||||
"minItems": 1,
|
|
||||||
"uniqueItems": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "The list of administrators to control the Discord bot."
|
"description": "The list of administrators to control the Discord bot."
|
||||||
@ -127,16 +124,16 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "The color of the embed."
|
"description": "The color of the embed."
|
||||||
},
|
},
|
||||||
"roles": {
|
"users": {
|
||||||
"type": "array",
|
"$ref": "#/$defs/ids"
|
||||||
"items": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
},
|
||||||
"description": "A list of role ids.",
|
"roles": {
|
||||||
"uniqueItems": true,
|
"$ref": "#/$defs/ids"
|
||||||
"minItems": 1
|
|
||||||
},
|
},
|
||||||
"channels": {
|
"channels": {
|
||||||
|
"$ref": "#/$defs/ids"
|
||||||
|
},
|
||||||
|
"ids": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
@ -32,7 +32,7 @@ pub async fn unmute(
|
|||||||
|
|
||||||
respond_moderation(
|
respond_moderation(
|
||||||
&ctx,
|
&ctx,
|
||||||
ModerationKind::Unmute(
|
&ModerationKind::Unmute(
|
||||||
queue_unmute_member(
|
queue_unmute_member(
|
||||||
&ctx.discord().http,
|
&ctx.discord().http,
|
||||||
&data.database,
|
&data.database,
|
||||||
@ -44,6 +44,7 @@ pub async fn unmute(
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
&member.user,
|
&member.user,
|
||||||
|
&configuration,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@ -174,8 +175,9 @@ pub async fn mute(
|
|||||||
|
|
||||||
respond_moderation(
|
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,
|
||||||
|
&configuration,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@ -300,24 +302,35 @@ pub async fn ban(
|
|||||||
#[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> {
|
||||||
respond_moderation(
|
handle_ban(&ctx, &BanKind::Ban(user, dmd, reason)).await
|
||||||
&ctx,
|
|
||||||
ModerationKind::Ban(
|
|
||||||
reason.clone(),
|
|
||||||
ban_moderation(&ctx, BanKind::Ban(user.clone(), dmd, reason)).await,
|
|
||||||
),
|
|
||||||
&user,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unban a user.
|
/// Unban a user.
|
||||||
#[poise::command(slash_command)]
|
#[poise::command(slash_command)]
|
||||||
pub async fn unban(ctx: Context<'_>, #[description = "User"] user: User) -> Result<(), Error> {
|
pub async fn unban(ctx: Context<'_>, #[description = "User"] user: User) -> Result<(), Error> {
|
||||||
|
handle_ban(&ctx, &BanKind::Unban(user)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_ban(ctx: &Context<'_>, kind: &BanKind) -> Result<(), Error> {
|
||||||
|
let data = ctx.data().read().await;
|
||||||
|
|
||||||
|
let ban_result = ban_moderation(&ctx, &kind).await;
|
||||||
|
|
||||||
|
let moderated_user;
|
||||||
respond_moderation(
|
respond_moderation(
|
||||||
&ctx,
|
&ctx,
|
||||||
ModerationKind::Unban(ban_moderation(&ctx, BanKind::Unban(user.clone())).await),
|
&match kind {
|
||||||
&user,
|
BanKind::Ban(user, _, reason) => {
|
||||||
|
moderated_user = user;
|
||||||
|
ModerationKind::Ban(reason.clone(), ban_result)
|
||||||
|
},
|
||||||
|
BanKind::Unban(user) => {
|
||||||
|
moderated_user = user;
|
||||||
|
ModerationKind::Unban(ban_result)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&moderated_user,
|
||||||
|
&data.configuration,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -1,140 +1,10 @@
|
|||||||
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
|
|
||||||
use poise::serenity_prelude::Attachment;
|
|
||||||
use regex::Regex;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::utils::bot::get_data_lock;
|
use crate::utils::autorespond::auto_respond;
|
||||||
use crate::utils::ocr;
|
use crate::utils::media_channel::handle_media_channel;
|
||||||
|
|
||||||
fn contains_match(regex: &[Regex], text: &str) -> bool {
|
|
||||||
regex.iter().any(|r| r.is_match(text))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn attachments_contains(attachments: &[Attachment], regex: &[Regex]) -> bool {
|
|
||||||
for attachment in attachments {
|
|
||||||
debug!("Checking attachment {}", &attachment.url);
|
|
||||||
|
|
||||||
if !&attachment.content_type.as_ref().unwrap().contains("image") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if contains_match(
|
|
||||||
regex,
|
|
||||||
&ocr::get_text_from_image_url(&attachment.url).await.unwrap(),
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn message_create(ctx: &serenity::Context, new_message: &serenity::Message) {
|
pub async fn message_create(ctx: &serenity::Context, new_message: &serenity::Message) {
|
||||||
debug!("Received message: {}", new_message.content);
|
let is_media_channel = handle_media_channel(ctx, new_message).await;
|
||||||
|
if !is_media_channel {
|
||||||
if new_message.guild_id.is_none() || new_message.author.bot {
|
auto_respond(ctx, new_message).await;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let data_lock = get_data_lock(ctx).await;
|
|
||||||
let responses = &data_lock.read().await.configuration.message_responses;
|
|
||||||
|
|
||||||
for response in responses {
|
|
||||||
// check if the message was sent in a channel that is included in the responder
|
|
||||||
if !response
|
|
||||||
.includes
|
|
||||||
.channels
|
|
||||||
.iter()
|
|
||||||
.any(|&channel_id| channel_id == new_message.channel_id.0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let excludes = &response.excludes;
|
|
||||||
// check if the message was sent by a user that is not excluded from the responder
|
|
||||||
if excludes
|
|
||||||
.roles
|
|
||||||
.iter()
|
|
||||||
.any(|&role_id| role_id == new_message.author.id.0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = &new_message.content;
|
|
||||||
let contains_attachments = !new_message.attachments.is_empty();
|
|
||||||
|
|
||||||
// check if the message does not match any of the excludes
|
|
||||||
if contains_match(&excludes.match_field.text, message) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if contains_attachments
|
|
||||||
&& !excludes.match_field.ocr.is_empty()
|
|
||||||
&& attachments_contains(&new_message.attachments, &excludes.match_field.ocr).await
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the message does match any of the includes
|
|
||||||
if !(contains_match(&response.includes.match_field.text, message)
|
|
||||||
|| (contains_attachments
|
|
||||||
&& !response.includes.match_field.ocr.is_empty()
|
|
||||||
&& attachments_contains(
|
|
||||||
&new_message.attachments,
|
|
||||||
&response.includes.match_field.ocr,
|
|
||||||
)
|
|
||||||
.await))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let min_age = response.condition.user.server_age;
|
|
||||||
|
|
||||||
if min_age != 0 {
|
|
||||||
let joined_at = ctx
|
|
||||||
.http
|
|
||||||
.get_member(new_message.guild_id.unwrap().0, new_message.author.id.0)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.joined_at
|
|
||||||
.unwrap()
|
|
||||||
.unix_timestamp();
|
|
||||||
|
|
||||||
let must_joined_at =
|
|
||||||
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(joined_at, 0), Utc);
|
|
||||||
let but_joined_at = Utc::now() - Duration::days(min_age);
|
|
||||||
|
|
||||||
if must_joined_at <= but_joined_at {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_message
|
|
||||||
.channel_id
|
|
||||||
.send_message(&ctx.http, |m| {
|
|
||||||
m.reference_message(new_message);
|
|
||||||
match &response.response.embed {
|
|
||||||
Some(embed) => m.embed(|e| {
|
|
||||||
e.title(&embed.title)
|
|
||||||
.description(&embed.description)
|
|
||||||
.color(embed.color)
|
|
||||||
.fields(embed.fields.iter().map(|field| {
|
|
||||||
(field.name.clone(), field.value.clone(), field.inline)
|
|
||||||
}))
|
|
||||||
.footer(|f| {
|
|
||||||
f.text(&embed.footer.text);
|
|
||||||
f.icon_url(&embed.footer.icon_url)
|
|
||||||
})
|
|
||||||
.thumbnail(&embed.thumbnail.url)
|
|
||||||
.image(&embed.image.url)
|
|
||||||
.author(|a| {
|
|
||||||
a.name(&embed.author.name).icon_url(&embed.author.icon_url)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
None => m.content(response.response.message.as_ref().unwrap()),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect("Could not reply to message author.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ async fn main() {
|
|||||||
moderation::unmute(),
|
moderation::unmute(),
|
||||||
moderation::purge(),
|
moderation::purge(),
|
||||||
moderation::ban(),
|
moderation::ban(),
|
||||||
|
moderation::unban(),
|
||||||
misc::reply(),
|
misc::reply(),
|
||||||
];
|
];
|
||||||
poise::set_qualified_names(&mut commands);
|
poise::set_qualified_names(&mut commands);
|
||||||
|
@ -67,6 +67,8 @@ impl Configuration {
|
|||||||
pub struct General {
|
pub struct General {
|
||||||
pub embed_color: i32,
|
pub embed_color: i32,
|
||||||
pub mute: Mute,
|
pub mute: Mute,
|
||||||
|
pub media_channels: Vec<u64>,
|
||||||
|
pub logging_channel: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
|
138
src/utils/autorespond.rs
Normal file
138
src/utils/autorespond.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
|
||||||
|
use poise::serenity_prelude::Attachment;
|
||||||
|
use regex::Regex;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::utils::bot::get_data_lock;
|
||||||
|
use crate::utils::ocr;
|
||||||
|
|
||||||
|
fn contains_match(regex: &[Regex], text: &str) -> bool {
|
||||||
|
regex.iter().any(|r| r.is_match(text))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn attachments_contains(attachments: &[Attachment], regex: &[Regex]) -> bool {
|
||||||
|
for attachment in attachments {
|
||||||
|
debug!("Checking attachment {}", &attachment.url);
|
||||||
|
|
||||||
|
if !&attachment.content_type.as_ref().unwrap().contains("image") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if contains_match(
|
||||||
|
regex,
|
||||||
|
&ocr::get_text_from_image_url(&attachment.url).await.unwrap(),
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn auto_respond(ctx: &serenity::Context, new_message: &serenity::Message) {
|
||||||
|
if new_message.guild_id.is_none() || new_message.author.bot {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_lock = get_data_lock(ctx).await;
|
||||||
|
let responses = &data_lock.read().await.configuration.message_responses;
|
||||||
|
|
||||||
|
for response in responses {
|
||||||
|
// check if the message was sent in a channel that is included in the responder
|
||||||
|
if !response
|
||||||
|
.includes
|
||||||
|
.channels
|
||||||
|
.iter()
|
||||||
|
.any(|&channel_id| channel_id == new_message.channel_id.0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let excludes = &response.excludes;
|
||||||
|
// check if the message was sent by a user that is not excluded from the responder
|
||||||
|
if excludes
|
||||||
|
.roles
|
||||||
|
.iter()
|
||||||
|
.any(|&role_id| role_id == new_message.author.id.0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = &new_message.content;
|
||||||
|
let contains_attachments = !new_message.attachments.is_empty();
|
||||||
|
|
||||||
|
// check if the message does not match any of the excludes
|
||||||
|
if contains_match(&excludes.match_field.text, message) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if contains_attachments
|
||||||
|
&& !excludes.match_field.ocr.is_empty()
|
||||||
|
&& attachments_contains(&new_message.attachments, &excludes.match_field.ocr).await
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the message does match any of the includes
|
||||||
|
if !(contains_match(&response.includes.match_field.text, message)
|
||||||
|
|| (contains_attachments
|
||||||
|
&& !response.includes.match_field.ocr.is_empty()
|
||||||
|
&& attachments_contains(
|
||||||
|
&new_message.attachments,
|
||||||
|
&response.includes.match_field.ocr,
|
||||||
|
)
|
||||||
|
.await))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let min_age = response.condition.user.server_age;
|
||||||
|
|
||||||
|
if min_age != 0 {
|
||||||
|
let joined_at = ctx
|
||||||
|
.http
|
||||||
|
.get_member(new_message.guild_id.unwrap().0, new_message.author.id.0)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.joined_at
|
||||||
|
.unwrap()
|
||||||
|
.unix_timestamp();
|
||||||
|
|
||||||
|
let must_joined_at =
|
||||||
|
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(joined_at, 0), Utc);
|
||||||
|
let but_joined_at = Utc::now() - Duration::days(min_age);
|
||||||
|
|
||||||
|
if must_joined_at <= but_joined_at {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_message
|
||||||
|
.channel_id
|
||||||
|
.send_message(&ctx.http, |m| {
|
||||||
|
m.reference_message(new_message);
|
||||||
|
match &response.response.embed {
|
||||||
|
Some(embed) => m.embed(|e| {
|
||||||
|
e.title(&embed.title)
|
||||||
|
.description(&embed.description)
|
||||||
|
.color(embed.color)
|
||||||
|
.fields(embed.fields.iter().map(|field| {
|
||||||
|
(field.name.clone(), field.value.clone(), field.inline)
|
||||||
|
}))
|
||||||
|
.footer(|f| {
|
||||||
|
f.text(&embed.footer.text);
|
||||||
|
f.icon_url(&embed.footer.icon_url)
|
||||||
|
})
|
||||||
|
.thumbnail(&embed.thumbnail.url)
|
||||||
|
.image(&embed.image.url)
|
||||||
|
.author(|a| {
|
||||||
|
a.name(&embed.author.name).icon_url(&embed.author.icon_url)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
None => m.content(response.response.message.as_ref().unwrap()),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("Could not reply to message author.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,5 @@ pub fn load_configuration() -> Configuration {
|
|||||||
|
|
||||||
// Share the lock reference between the threads in serenity framework
|
// Share the lock reference between the threads in serenity framework
|
||||||
pub async fn get_data_lock(ctx: &serenity::Context) -> Arc<RwLock<Data>> {
|
pub async fn get_data_lock(ctx: &serenity::Context) -> Arc<RwLock<Data>> {
|
||||||
ctx.data
|
ctx.data.read().await.get::<Data>().unwrap().clone()
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get::<Data>()
|
|
||||||
.expect("Expected Configuration in TypeMap.")
|
|
||||||
.clone()
|
|
||||||
}
|
}
|
||||||
|
34
src/utils/media_channel.rs
Normal file
34
src/utils/media_channel.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use super::bot::get_data_lock;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub async fn handle_media_channel(
|
||||||
|
ctx: &serenity::Context,
|
||||||
|
new_message: &serenity::Message,
|
||||||
|
) -> bool {
|
||||||
|
let current_channel = new_message.channel_id.0;
|
||||||
|
|
||||||
|
let data_lock = get_data_lock(ctx).await;
|
||||||
|
|
||||||
|
let configuration = &data_lock.read().await.configuration;
|
||||||
|
|
||||||
|
let is_media_channel = configuration
|
||||||
|
.general
|
||||||
|
.media_channels
|
||||||
|
.iter()
|
||||||
|
.any(|&channel| channel == current_channel);
|
||||||
|
|
||||||
|
if !configuration
|
||||||
|
.administrators
|
||||||
|
.users
|
||||||
|
.contains(&new_message.author.id.0)
|
||||||
|
&& is_media_channel
|
||||||
|
{
|
||||||
|
if let Err(why) = new_message.delete(&ctx.http).await {
|
||||||
|
error!("Error deleting message: {:?}", why);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is_media_channel
|
||||||
|
}
|
@ -5,3 +5,5 @@ pub mod decancer;
|
|||||||
pub mod embed;
|
pub mod embed;
|
||||||
pub mod moderation;
|
pub mod moderation;
|
||||||
pub mod ocr;
|
pub mod ocr;
|
||||||
|
pub mod autorespond;
|
||||||
|
pub mod media_channel;
|
@ -2,7 +2,7 @@ use std::cmp;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mongodb::options::FindOptions;
|
use mongodb::options::FindOptions;
|
||||||
use poise::serenity_prelude::{Http, User};
|
use poise::serenity_prelude::{ChannelId, Http, User};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use tracing::{debug, error, trace};
|
use tracing::{debug, error, trace};
|
||||||
|
|
||||||
@ -10,8 +10,10 @@ 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::model::application::Configuration;
|
||||||
use crate::serenity::SerenityError;
|
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
|
||||||
@ -112,20 +114,14 @@ pub fn queue_unmute_member(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
pub async fn respond_moderation(
|
pub async fn respond_moderation<'a>(
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
moderation: ModerationKind,
|
moderation: &ModerationKind,
|
||||||
user: &serenity::User,
|
user: &serenity::User,
|
||||||
|
configuration: &Configuration,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
let create_embed = |f: &mut serenity::CreateEmbed| {
|
||||||
let tag = user.tag();
|
let tag = user.tag();
|
||||||
let image = user
|
|
||||||
.avatar_url()
|
|
||||||
.unwrap_or_else(|| user.default_avatar_url());
|
|
||||||
|
|
||||||
let embed_color = ctx.data().read().await.configuration.general.embed_color;
|
|
||||||
|
|
||||||
ctx.send(|f| {
|
|
||||||
f.embed(|f| {
|
|
||||||
match moderation {
|
match moderation {
|
||||||
ModerationKind::Mute(reason, expires, error) => match error {
|
ModerationKind::Mute(reason, expires, error) => match error {
|
||||||
Some(err) => f.title(format!("Failed to mute {}", tag)).field(
|
Some(err) => f.title(format!("Failed to mute {}", tag)).field(
|
||||||
@ -169,8 +165,38 @@ pub async fn respond_moderation(
|
|||||||
None => f.title(format!("Unbanned {}", tag)),
|
None => f.title(format!("Unbanned {}", tag)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.color(embed_color)
|
.color(configuration.general.embed_color)
|
||||||
.thumbnail(image)
|
.thumbnail(
|
||||||
|
&user
|
||||||
|
.avatar_url()
|
||||||
|
.unwrap_or_else(|| user.default_avatar_url()),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let reply = ctx
|
||||||
|
.send(|reply| {
|
||||||
|
reply.embed(|embed| {
|
||||||
|
create_embed(embed);
|
||||||
|
embed
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let response = reply.message().await?;
|
||||||
|
ChannelId(configuration.general.logging_channel)
|
||||||
|
.send_message(&ctx.discord().http, |reply| {
|
||||||
|
reply.embed(|embed| {
|
||||||
|
create_embed(embed);
|
||||||
|
embed.field(
|
||||||
|
"Reference",
|
||||||
|
format!(
|
||||||
|
"[Jump to message](https://discord.com/channels/{}/{}/{})",
|
||||||
|
ctx.guild_id().unwrap().0,
|
||||||
|
response.channel_id,
|
||||||
|
response.id
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
@ -178,18 +204,24 @@ pub async fn respond_moderation(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ban_moderation(ctx: &Context<'_>, kind: BanKind) -> Option<SerenityError> {
|
pub async fn ban_moderation(ctx: &Context<'_>, kind: &BanKind) -> Option<SerenityError> {
|
||||||
let guild_id = ctx.guild_id().unwrap().0;
|
let guild_id = ctx.guild_id().unwrap().0;
|
||||||
let http = &ctx.discord().http;
|
let http = &ctx.discord().http;
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
BanKind::Ban(user, dmd, reason) => {
|
BanKind::Ban(user, dmd, reason) => {
|
||||||
let reason = &reason
|
let reason = reason
|
||||||
|
.clone()
|
||||||
.or_else(|| Some("None specified".to_string()))
|
.or_else(|| Some("None specified".to_string()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let ban_result = http
|
let ban_result = http
|
||||||
.ban_user(guild_id, user.id.0, cmp::min(dmd.unwrap_or(0), 7), reason)
|
.ban_user(
|
||||||
|
guild_id,
|
||||||
|
user.id.0,
|
||||||
|
cmp::min(dmd.unwrap_or(0), 7),
|
||||||
|
reason.as_ref(),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Err(err) = ban_result {
|
if let Err(err) = ban_result {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user