Working on embeds
This commit is contained in:
parent
a99fd897af
commit
d2de03894a
|
@ -4,15 +4,12 @@ use serenity::{
|
||||||
macros::{command, group},
|
macros::{command, group},
|
||||||
CommandResult,
|
CommandResult,
|
||||||
},
|
},
|
||||||
http::CacheHttp,
|
|
||||||
model::prelude::*,
|
model::prelude::*,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::data::GuildOptionsKey;
|
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(ban, kick, ghost_pings)]
|
#[commands(ban, kick)]
|
||||||
pub struct Admin;
|
pub struct Admin;
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
|
@ -98,38 +95,3 @@ async fn ban(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
|
||||||
#[description = ""]
|
|
||||||
#[only_in(guilds)]
|
|
||||||
#[required_permissions("KICK_MEMBERS")]
|
|
||||||
async fn ghost_pings(ctx: &Context, msg: &Message) -> CommandResult {
|
|
||||||
let data = ctx.data.read().await;
|
|
||||||
let guilds_options = data
|
|
||||||
.get::<GuildOptionsKey>()
|
|
||||||
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
|
||||||
|
|
||||||
if let Some(guild) = guilds_options.get(&msg.guild_id.unwrap()) {
|
|
||||||
let mut message = String::from("\x60\x60\x60");
|
|
||||||
|
|
||||||
for ping in &guild.last_ghost_pings {
|
|
||||||
let sender = ctx
|
|
||||||
.http()
|
|
||||||
.get_user(ping.sender)
|
|
||||||
.await
|
|
||||||
.map(|u| u.name)
|
|
||||||
.unwrap_or_else(|_| String::from("Unkown"));
|
|
||||||
|
|
||||||
message += &format!(
|
|
||||||
"{} : {:?}\n",
|
|
||||||
sender,
|
|
||||||
ping.roles.iter().map(|r| format!("<!@{}>", r))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
message += "\x60\x60\x60";
|
|
||||||
|
|
||||||
crate::api::send_reply(ctx, msg, message).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub(crate) mod admin;
|
||||||
pub(crate) mod general;
|
pub(crate) mod general;
|
||||||
pub(crate) mod owner;
|
pub(crate) mod owner;
|
||||||
pub(crate) mod roulette;
|
pub(crate) mod roulette;
|
||||||
|
pub(crate) mod settings;
|
||||||
|
|
||||||
#[cfg(feature = "music")]
|
#[cfg(feature = "music")]
|
||||||
pub(crate) mod music;
|
pub(crate) mod music;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use tokio::sync::Mutex as TokioMutex;
|
||||||
use crate::data::{GuildOptions, GuildOptionsKey};
|
use crate::data::{GuildOptions, GuildOptionsKey};
|
||||||
use log::error;
|
use log::error;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
builder::CreateMessage,
|
builder::{CreateEmbed, CreateMessage},
|
||||||
client::Context,
|
client::Context,
|
||||||
framework::standard::{
|
framework::standard::{
|
||||||
macros::{command, group},
|
macros::{command, group},
|
||||||
|
@ -14,7 +14,7 @@ use serenity::{
|
||||||
http::Http,
|
http::Http,
|
||||||
model::{
|
model::{
|
||||||
channel::Message,
|
channel::Message,
|
||||||
guild::PartialMember,
|
guild::{Member, PartialMember},
|
||||||
id::{ChannelId, GuildId},
|
id::{ChannelId, GuildId},
|
||||||
misc::Mentionable,
|
misc::Mentionable,
|
||||||
},
|
},
|
||||||
|
@ -37,7 +37,7 @@ impl songbird::EventHandler for TrackStartNotifier {
|
||||||
if let Err(why) = self
|
if let Err(why) = self
|
||||||
.chan_id
|
.chan_id
|
||||||
.send_message(&self.http, |m| {
|
.send_message(&self.http, |m| {
|
||||||
embed_song(m, metadata);
|
embed_song(m, metadata, None);
|
||||||
m
|
m
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -55,12 +55,12 @@ impl songbird::EventHandler for TrackStartNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn embed_song(msg: &mut CreateMessage, metadata: &Metadata) {
|
fn embed_song(msg: &mut CreateMessage, metadata: &Metadata, author: Option<&Member>) {
|
||||||
msg.embed(|e| {
|
msg.embed(|e| {
|
||||||
e.title("Now playing");
|
e.title("Now playing");
|
||||||
|
|
||||||
if let Some(title) = &metadata.title {
|
if let Some(title) = &metadata.title {
|
||||||
e.field("title", title, true);
|
e.field("Title", title, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(url) = &metadata.source_url {
|
if let Some(url) = &metadata.source_url {
|
||||||
|
@ -75,7 +75,7 @@ fn embed_song(msg: &mut CreateMessage, metadata: &Metadata) {
|
||||||
let seconds = seconds - (min * 60);
|
let seconds = seconds - (min * 60);
|
||||||
|
|
||||||
e.field(
|
e.field(
|
||||||
"duration",
|
"Duration",
|
||||||
if hours > 0 {
|
if hours > 0 {
|
||||||
format!("{}:{:02}:{:02}", hours, min, seconds)
|
format!("{}:{:02}:{:02}", hours, min, seconds)
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,16 +88,17 @@ fn embed_song(msg: &mut CreateMessage, metadata: &Metadata) {
|
||||||
if let Some(img) = &metadata.thumbnail {
|
if let Some(img) = &metadata.thumbnail {
|
||||||
e.image(img);
|
e.image(img);
|
||||||
}
|
}
|
||||||
e
|
|
||||||
|
embed_author(e, author).colour((247, 76, 0))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn embed_queued(msg: &mut CreateMessage, metadata: &Metadata) {
|
fn embed_queued(msg: &mut CreateMessage, metadata: &Metadata, author: Option<&Member>) {
|
||||||
msg.embed(|e| {
|
msg.embed(|e| {
|
||||||
e.title("Queued");
|
e.title("Queued");
|
||||||
|
|
||||||
if let Some(title) = &metadata.title {
|
if let Some(title) = &metadata.title {
|
||||||
e.field("title", title, true);
|
e.field("Title", title, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(url) = &metadata.source_url {
|
if let Some(url) = &metadata.source_url {
|
||||||
|
@ -112,7 +113,7 @@ fn embed_queued(msg: &mut CreateMessage, metadata: &Metadata) {
|
||||||
let seconds = seconds - (min * 60);
|
let seconds = seconds - (min * 60);
|
||||||
|
|
||||||
e.field(
|
e.field(
|
||||||
"duration",
|
"Duration",
|
||||||
if hours > 0 {
|
if hours > 0 {
|
||||||
format!("{}:{:02}:{:02}", hours, min, seconds)
|
format!("{}:{:02}:{:02}", hours, min, seconds)
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,10 +126,45 @@ fn embed_queued(msg: &mut CreateMessage, metadata: &Metadata) {
|
||||||
if let Some(img) = &metadata.thumbnail {
|
if let Some(img) = &metadata.thumbnail {
|
||||||
e.image(img);
|
e.image(img);
|
||||||
}
|
}
|
||||||
e
|
|
||||||
|
embed_author(e, author).colour((247, 76, 0))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn embed_response<'a, 'b>(
|
||||||
|
msg: &'a mut CreateMessage<'b>,
|
||||||
|
title: &str,
|
||||||
|
content: &str,
|
||||||
|
author: Option<&Member>,
|
||||||
|
) -> &'a mut CreateMessage<'b> {
|
||||||
|
msg.embed(|e| {
|
||||||
|
e.title(title).description(content);
|
||||||
|
embed_author(e, author).colour((247, 76, 0))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn embed_author<'a>(e: &'a mut CreateEmbed, author: Option<&Member>) -> &'a mut CreateEmbed {
|
||||||
|
if let Some(author) = author {
|
||||||
|
e.footer(|f| {
|
||||||
|
f.text(format!(
|
||||||
|
"{}",
|
||||||
|
if let Some(nick) = &author.nick {
|
||||||
|
nick
|
||||||
|
} else {
|
||||||
|
&author.user.name
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
if let Some(url) = &author.user.avatar_url() {
|
||||||
|
f.icon_url(url);
|
||||||
|
}
|
||||||
|
f
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(join, leave, play, stop, next)]
|
#[commands(join, leave, play, stop, next)]
|
||||||
struct Music;
|
struct Music;
|
||||||
|
@ -145,13 +181,21 @@ async fn join(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let member = msg.member(&ctx.http).await?;
|
||||||
if if let Some(member) = &msg.member {
|
if if let Some(member) = &msg.member {
|
||||||
is_mute(ctx, member, guild.id).await.unwrap_or(false)
|
is_mute(ctx, member, guild.id).await.unwrap_or(false)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
} {
|
} {
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(&ctx.http, "Error, you cant play music")
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Error",
|
||||||
|
"You don't have the right to play music",
|
||||||
|
Some(&member),
|
||||||
|
)
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -166,7 +210,11 @@ async fn join(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
let connect_to = match channel_id {
|
let connect_to = match channel_id {
|
||||||
Some(channel) => channel,
|
Some(channel) => channel,
|
||||||
None => {
|
None => {
|
||||||
msg.reply(ctx, "Not in a voice channel").await?;
|
msg.channel_id
|
||||||
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(m, "Error", "You must be on a voice channel", Some(&member))
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -191,21 +239,35 @@ async fn join(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
handler_lock: handler_lock.clone(),
|
handler_lock: handler_lock.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(
|
.send_message(&ctx.http, |m| {
|
||||||
&ctx.http,
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Joined Channel",
|
||||||
&format!("Joined channel {}", connect_to.mention()),
|
&format!("Joined channel {}", connect_to.mention()),
|
||||||
|
Some(&member),
|
||||||
)
|
)
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(&ctx.http, "Error joining the channel")
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(m, "Error", "Error joining the channel", Some(&member))
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO WARN
|
// TODO WARN
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(&ctx.http, "Error : Already connected on another channel")
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Error",
|
||||||
|
"Already connected on another channel",
|
||||||
|
Some(&member),
|
||||||
|
)
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,13 +290,21 @@ async fn leave(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let member = msg.member(&ctx.http).await?;
|
||||||
if if let Some(member) = &msg.member {
|
if if let Some(member) = &msg.member {
|
||||||
is_mute(ctx, member, guild_id).await.unwrap_or(false)
|
is_mute(ctx, member, guild_id).await.unwrap_or(false)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
} {
|
} {
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(&ctx.http, "Error, you cant play music")
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Error",
|
||||||
|
"You don't have the right to play music",
|
||||||
|
Some(&member),
|
||||||
|
)
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -246,14 +316,40 @@ async fn leave(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
|
|
||||||
if let Some(_handler) = manager.get(guild_id) {
|
if let Some(_handler) = manager.get(guild_id) {
|
||||||
if let Err(e) = manager.remove(guild_id).await {
|
if let Err(e) = manager.remove(guild_id).await {
|
||||||
|
log::error!("Failed to leave : {}", e);
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.say(&ctx.http, format!("Failed: {:?}", e))
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Error",
|
||||||
|
"Failed to leave",
|
||||||
|
Some(&member),
|
||||||
|
)
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.channel_id.say(&ctx.http, "Left voice channel").await?;
|
msg.channel_id
|
||||||
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Left channel",
|
||||||
|
"",
|
||||||
|
Some(&member),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
msg.reply(ctx, "Not in a voice channel").await?;
|
msg.channel_id
|
||||||
|
.send_message(&ctx.http, |m| {
|
||||||
|
embed_response(
|
||||||
|
m,
|
||||||
|
"Error",
|
||||||
|
"Not in a voice channel",
|
||||||
|
Some(&member),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -333,12 +429,13 @@ async fn play(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
let meta = &source.metadata.clone();
|
let meta = &source.metadata.clone();
|
||||||
handler.enqueue_source(source);
|
handler.enqueue_source(source);
|
||||||
|
|
||||||
|
let author = msg.member(&ctx).await?;
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
.send_message(&ctx.http, |m| {
|
.send_message(&ctx.http, |m| {
|
||||||
if handler.queue().len() == 1 {
|
if handler.queue().len() == 1 {
|
||||||
embed_song(m, meta);
|
embed_song(m, meta, Some(&author));
|
||||||
} else {
|
} else {
|
||||||
embed_queued(m, meta);
|
embed_queued(m, meta, Some(&author));
|
||||||
}
|
}
|
||||||
m
|
m
|
||||||
})
|
})
|
||||||
|
@ -469,7 +566,9 @@ async fn is_mute(
|
||||||
.entry(guild_id)
|
.entry(guild_id)
|
||||||
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
||||||
|
|
||||||
Ok(member
|
if let Some(mute_role) = guild_options.get_mute_role() {
|
||||||
.roles
|
Ok(member.roles.contains(&mute_role))
|
||||||
.contains(&guild_options.get_mute_role(ctx).await?))
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::{
|
||||||
api,
|
api,
|
||||||
data::{GuildOptions, GuildOptionsKey},
|
data::{GuildOptions, GuildOptionsKey},
|
||||||
};
|
};
|
||||||
use log::debug;
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
framework::standard::{
|
framework::standard::{
|
||||||
|
@ -28,7 +27,7 @@ async fn shot(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
if rand::thread_rng().gen_range(0..6) == 0 {
|
if rand::thread_rng().gen_range(0..6) == 0 {
|
||||||
api::send_reply(ctx, &msg, "💥").await?;
|
api::send_reply(ctx, &msg, "💥").await?;
|
||||||
} else {
|
} else {
|
||||||
api::send_reply(&ctx, &msg, format!("Click ! Reloading")).await?;
|
api::send_reply(&ctx, &msg, "Click ! Reloading").await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
api::send_reply(
|
api::send_reply(
|
||||||
|
@ -74,7 +73,7 @@ async fn kick(ctx: &Context, msg: &Message) -> CommandResult {
|
||||||
.kick_with_reason(&ctx.http, "You loose at the roulette")
|
.kick_with_reason(&ctx.http, "You loose at the roulette")
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
api::send_reply(&ctx, &msg, format!("Click ! Reloading")).await?;
|
api::send_reply(&ctx, &msg, "Click ! Reloading").await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -108,6 +107,5 @@ async fn disable_kick(ctx: &Context, msg: &Message, mut args: Args) -> CommandRe
|
||||||
|
|
||||||
entry.save_async(guild_id.0).await?;
|
entry.save_async(guild_id.0).await?;
|
||||||
}
|
}
|
||||||
debug!("{:?}", guilds_options);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serenity::{
|
||||||
|
client::Context,
|
||||||
|
framework::standard::{Args, CommandResult},
|
||||||
|
model::channel::Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serenity::{
|
||||||
|
framework::standard::macros::{command, group},
|
||||||
|
model::prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::data::{GuildOptions, GuildOptionsKey};
|
||||||
|
|
||||||
|
#[group]
|
||||||
|
#[prefix("settings")]
|
||||||
|
#[commands(muterole, logchannel)]
|
||||||
|
struct Settings;
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[description = "Set mute role"]
|
||||||
|
#[only_in(guilds)]
|
||||||
|
#[required_permissions("ADMINISTRATOR")]
|
||||||
|
async fn muterole(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
let role_id = match args.len() {
|
||||||
|
0 => None,
|
||||||
|
_ => Some(args.single::<String>()?),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(id) = role_id {
|
||||||
|
let mut data = ctx.data.write().await;
|
||||||
|
|
||||||
|
let guilds_options = data
|
||||||
|
.get_mut::<GuildOptionsKey>()
|
||||||
|
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||||
|
|
||||||
|
if let Some(guild_id) = msg.guild_id {
|
||||||
|
let entry = guilds_options
|
||||||
|
.entry(guild_id)
|
||||||
|
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
||||||
|
|
||||||
|
entry.mute_id = match id.as_str() {
|
||||||
|
"none" => None,
|
||||||
|
_ => Some(RoleId::from_str(&id)?),
|
||||||
|
};
|
||||||
|
|
||||||
|
entry.save_async(guild_id.0).await?;
|
||||||
|
|
||||||
|
msg.channel_id.say(&ctx.http, "Saved").await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let data = ctx.data.read().await;
|
||||||
|
|
||||||
|
let guilds_options = data
|
||||||
|
.get::<GuildOptionsKey>()
|
||||||
|
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||||
|
|
||||||
|
if let Some(guild_id) = msg.guild_id {
|
||||||
|
if let Some(options) = guilds_options.get(&guild_id) {
|
||||||
|
msg.channel_id
|
||||||
|
.say(
|
||||||
|
&ctx.http,
|
||||||
|
if let Some(role_id) = options.mute_id {
|
||||||
|
format!(
|
||||||
|
"Mute role is @{}",
|
||||||
|
role_id.to_role_cached(&ctx).await.unwrap().name
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"Mute role is None".to_string()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
msg.channel_id.say(&ctx.http, "Mute role is None").await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[description = "Set mention logging channel"]
|
||||||
|
#[only_in(guilds)]
|
||||||
|
#[required_permissions("ADMINISTRATOR")]
|
||||||
|
async fn logchannel(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
let channel_id = match args.len() {
|
||||||
|
0 => None,
|
||||||
|
_ => Some(args.single::<String>()?),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(id) = channel_id {
|
||||||
|
let mut data = ctx.data.write().await;
|
||||||
|
|
||||||
|
let guilds_options = data
|
||||||
|
.get_mut::<GuildOptionsKey>()
|
||||||
|
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||||
|
|
||||||
|
if let Some(guild_id) = msg.guild_id {
|
||||||
|
let entry = guilds_options
|
||||||
|
.entry(guild_id)
|
||||||
|
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
||||||
|
|
||||||
|
entry.mention_log_channel = match id.as_str() {
|
||||||
|
"none" => None,
|
||||||
|
_ => Some(ChannelId::from_str(&id)?),
|
||||||
|
};
|
||||||
|
|
||||||
|
entry.save_async(guild_id.0).await?;
|
||||||
|
|
||||||
|
msg.channel_id.say(&ctx.http, "Saved").await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let data = ctx.data.read().await;
|
||||||
|
|
||||||
|
let guilds_options = data
|
||||||
|
.get::<GuildOptionsKey>()
|
||||||
|
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||||
|
|
||||||
|
if let Some(guild_id) = msg.guild_id {
|
||||||
|
if let Some(options) = guilds_options.get(&guild_id) {
|
||||||
|
msg.channel_id
|
||||||
|
.say(
|
||||||
|
&ctx.http,
|
||||||
|
if let Some(channel_id) = options.mention_log_channel {
|
||||||
|
format!("Logging channel is {}", channel_id.mention())
|
||||||
|
} else {
|
||||||
|
"Logging channel is None".to_string()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
msg.channel_id
|
||||||
|
.say(&ctx.http, "Logging channel is None")
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -2,8 +2,8 @@ use log::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serenity::{
|
use serenity::{
|
||||||
model::{
|
model::{
|
||||||
channel::Message,
|
id::ChannelId,
|
||||||
prelude::{GuildId, RoleId, UserId},
|
prelude::{GuildId, RoleId},
|
||||||
},
|
},
|
||||||
prelude::TypeMapKey,
|
prelude::TypeMapKey,
|
||||||
};
|
};
|
||||||
|
@ -15,18 +15,13 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
#[cfg(feature = "music")]
|
|
||||||
use serenity::{http::CacheHttp, model::prelude::PartialGuild};
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub(crate) struct GuildOptions {
|
pub(crate) struct GuildOptions {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub(crate) guild_id: Option<GuildId>,
|
pub(crate) guild_id: Option<GuildId>,
|
||||||
#[serde(skip_serializing)]
|
|
||||||
pub(crate) mute_id: Option<RoleId>,
|
pub(crate) mute_id: Option<RoleId>,
|
||||||
|
pub(crate) mention_log_channel: Option<ChannelId>,
|
||||||
pub(crate) roulette_options: RouletteOptions,
|
pub(crate) roulette_options: RouletteOptions,
|
||||||
pub(crate) last_ghost_pings: Vec<GhostPing>,
|
|
||||||
pub(crate) mutes: Vec<(UserId, u64)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuildOptions {
|
impl GuildOptions {
|
||||||
|
@ -89,62 +84,10 @@ impl GuildOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "music")]
|
#[cfg(feature = "music")]
|
||||||
pub(crate) async fn get_mute_role<C: CacheHttp>(
|
pub(crate) fn get_mute_role(
|
||||||
&mut self,
|
&self
|
||||||
cache: &C,
|
) -> Option<RoleId> {
|
||||||
) -> tokio::io::Result<RoleId> {
|
self.mute_id
|
||||||
match self.mute_id {
|
|
||||||
Some(mute_id) => Ok(mute_id),
|
|
||||||
|
|
||||||
None => {
|
|
||||||
if let Some(guild_id) = self.guild_id {
|
|
||||||
let guild: PartialGuild = cache
|
|
||||||
.http()
|
|
||||||
.get_guild(guild_id.0)
|
|
||||||
.await
|
|
||||||
.map_err(|e| tokio::io::Error::new(tokio::io::ErrorKind::Other, e))?;
|
|
||||||
|
|
||||||
match guild.role_by_name("mute") {
|
|
||||||
Some(role) => {
|
|
||||||
self.mute_id = Some(role.id);
|
|
||||||
Ok(role.id)
|
|
||||||
}
|
|
||||||
None => Err(tokio::io::Error::new(
|
|
||||||
tokio::io::ErrorKind::Other,
|
|
||||||
"Unkown role",
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(tokio::io::Error::new(
|
|
||||||
tokio::io::ErrorKind::Other,
|
|
||||||
"Unkown guild id",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn insert_or_ignore(&mut self, message: Message) {
|
|
||||||
let time = message.timestamp.timestamp_millis();
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < self.last_ghost_pings.len() {
|
|
||||||
if time > self.last_ghost_pings[i].time {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
log::debug!("u {}", i);
|
|
||||||
|
|
||||||
if i != 15 {
|
|
||||||
log::debug!("u {}", i);
|
|
||||||
self.last_ghost_pings.insert(i, message.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.last_ghost_pings.len() == 16 {
|
|
||||||
self.last_ghost_pings.remove(15);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,8 +97,7 @@ impl Default for GuildOptions {
|
||||||
roulette_options: RouletteOptions::default(),
|
roulette_options: RouletteOptions::default(),
|
||||||
guild_id: None,
|
guild_id: None,
|
||||||
mute_id: None,
|
mute_id: None,
|
||||||
last_ghost_pings: Vec::new(),
|
mention_log_channel: None,
|
||||||
mutes: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,22 +129,3 @@ pub(crate) struct GuildOptionsKey;
|
||||||
impl TypeMapKey for GuildOptionsKey {
|
impl TypeMapKey for GuildOptionsKey {
|
||||||
type Value = HashMap<GuildId, GuildOptions>;
|
type Value = HashMap<GuildId, GuildOptions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub(crate) struct GhostPing {
|
|
||||||
pub(crate) sender: u64,
|
|
||||||
pub(crate) channel: u64,
|
|
||||||
pub(crate) roles: Vec<RoleId>,
|
|
||||||
pub(crate) time: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Message> for GhostPing {
|
|
||||||
fn from(message: Message) -> Self {
|
|
||||||
Self {
|
|
||||||
sender: *message.author.id.as_u64(),
|
|
||||||
channel: *message.channel_id.as_u64(),
|
|
||||||
roles: message.mention_roles,
|
|
||||||
time: message.timestamp.timestamp_millis(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
109
src/main.rs
109
src/main.rs
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{
|
commands::{
|
||||||
admin::ADMIN_GROUP, general::GENERAL_GROUP, owner::OWNER_GROUP, roulette::ROULETTE_GROUP,
|
admin::ADMIN_GROUP, general::GENERAL_GROUP, owner::OWNER_GROUP, roulette::ROULETTE_GROUP,
|
||||||
|
settings::SETTINGS_GROUP,
|
||||||
},
|
},
|
||||||
data::{BulletsContainer, GuildOptions, GuildOptionsKey, ShardManagerContainer},
|
data::{BulletsContainer, GuildOptions, GuildOptionsKey, ShardManagerContainer},
|
||||||
};
|
};
|
||||||
|
@ -40,6 +41,8 @@ mod config;
|
||||||
mod data;
|
mod data;
|
||||||
mod presence;
|
mod presence;
|
||||||
|
|
||||||
|
const MINIMUM_MENTIONS: usize = 10;
|
||||||
|
|
||||||
const PREFIX: &str = "?";
|
const PREFIX: &str = "?";
|
||||||
static mut LOG_ATTACHMENTS: bool = false;
|
static mut LOG_ATTACHMENTS: bool = false;
|
||||||
pub(crate) static mut INVITE_URL: Option<String> = None;
|
pub(crate) static mut INVITE_URL: Option<String> = None;
|
||||||
|
@ -114,7 +117,8 @@ async fn main() -> IoResult<()> {
|
||||||
.group(&ADMIN_GROUP)
|
.group(&ADMIN_GROUP)
|
||||||
.group(&GENERAL_GROUP)
|
.group(&GENERAL_GROUP)
|
||||||
.group(&ROULETTE_GROUP)
|
.group(&ROULETTE_GROUP)
|
||||||
.group(&OWNER_GROUP);
|
.group(&OWNER_GROUP)
|
||||||
|
.group(&SETTINGS_GROUP);
|
||||||
|
|
||||||
#[cfg(feature = "music")]
|
#[cfg(feature = "music")]
|
||||||
{
|
{
|
||||||
|
@ -200,67 +204,74 @@ impl EventHandler for Messages {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn message(&self, _ctx: Context, new_message: Message) {
|
async fn message(&self, ctx: Context, new_message: Message) {
|
||||||
if unsafe { LOG_ATTACHMENTS } && !new_message.attachments.is_empty() {
|
if unsafe { LOG_ATTACHMENTS } && !new_message.attachments.is_empty() {
|
||||||
for att in new_message.attachments {
|
for att in &new_message.attachments {
|
||||||
if let Err(e) = download_to_log(att).await {
|
if let Err(e) = download_to_log(att).await {
|
||||||
error!("Error while downloading to log : {:?}", e);
|
error!("Error while downloading to log : {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(e) = log_mentions(ctx, &new_message).await {
|
||||||
|
error!("Error while logging mentions: {}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn unknown(&self, _ctx: Context, name: String, raw: Value) {
|
async fn unknown(&self, _ctx: Context, name: String, raw: Value) {
|
||||||
debug!("Unknown event : {}, {:?}", name, raw);
|
debug!("Unknown event : {}, {:?}", name, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn message_delete(
|
|
||||||
&self,
|
|
||||||
ctx: Context,
|
|
||||||
channel_id: ChannelId,
|
|
||||||
deleted_message_id: MessageId,
|
|
||||||
_guild_id: Option<GuildId>,
|
|
||||||
) {
|
|
||||||
let message = ctx
|
|
||||||
.cache()
|
|
||||||
.unwrap()
|
|
||||||
.message(channel_id, deleted_message_id)
|
|
||||||
.await;
|
|
||||||
log::debug!(
|
|
||||||
"Deletted message : {:?}",
|
|
||||||
message.as_ref().map(|m| &m.content)
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(message) = message {
|
|
||||||
if let Some(guild_id) = message.guild_id {
|
|
||||||
if !message.mention_roles.is_empty() {
|
|
||||||
let mut data = ctx.data.write().await;
|
|
||||||
let guilds_options = data.get_mut::<GuildOptionsKey>().unwrap();
|
|
||||||
|
|
||||||
let entry = guilds_options
|
|
||||||
.entry(guild_id)
|
|
||||||
.or_insert_with(|| GuildOptions::default().set_guild_id(guild_id));
|
|
||||||
|
|
||||||
entry.insert_or_ignore(message);
|
|
||||||
|
|
||||||
log::debug!("{:?}", entry.last_ghost_pings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn message_update(
|
|
||||||
&self,
|
|
||||||
_ctx: Context,
|
|
||||||
old_if_available: Option<Message>,
|
|
||||||
new: Option<Message>,
|
|
||||||
_event: MessageUpdateEvent,
|
|
||||||
) {
|
|
||||||
log::debug!("update : {:?} vs {:?}", old_if_available, new);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn download_to_log(attachment: Attachment) -> commands::Result<()> {
|
async fn log_mentions(ctx: Context, new_message: &Message) -> CommandResult {
|
||||||
|
let data = ctx.data.read().await;
|
||||||
|
|
||||||
|
let guilds_options = data
|
||||||
|
.get::<GuildOptionsKey>()
|
||||||
|
.expect("Expected NonKickGuildsContainer in TypeMap.");
|
||||||
|
|
||||||
|
if new_message.mention_everyone {
|
||||||
|
if let Some(guild_id) = new_message.guild_id {
|
||||||
|
if let Some(options) = guilds_options.get(&guild_id) {
|
||||||
|
if let Some(role_id) = options.mute_id {
|
||||||
|
let mut member = new_message.member(&ctx).await?;
|
||||||
|
member.add_role(&ctx.http, role_id).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_message.mention_everyone
|
||||||
|
|| (new_message.mention_roles.len() + new_message.mentions.len()) > MINIMUM_MENTIONS
|
||||||
|
{
|
||||||
|
if let Some(guild_id) = new_message.guild_id {
|
||||||
|
if let Some(options) = guilds_options.get(&guild_id) {
|
||||||
|
if let Some(channel_id) = options.mention_log_channel {
|
||||||
|
channel_id
|
||||||
|
.send_message(&ctx.http, |m| {
|
||||||
|
m.embed(|e| {
|
||||||
|
e.title("New message with mentions")
|
||||||
|
.fields(vec![
|
||||||
|
("Sender", new_message.author.mention().to_string(), false),
|
||||||
|
("Content", new_message.content.clone(), false),
|
||||||
|
(
|
||||||
|
"Channel",
|
||||||
|
new_message.channel_id.mention().to_string(),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.colour((247, 76, 0))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn download_to_log(attachment: &Attachment) -> commands::Result<()> {
|
||||||
debug!("Download_to_log : {:?}", attachment);
|
debug!("Download_to_log : {:?}", attachment);
|
||||||
let path = Path::new("logging").join(format!("{}-{}", attachment.id, attachment.filename));
|
let path = Path::new("logging").join(format!("{}-{}", attachment.id, attachment.filename));
|
||||||
let content = reqwest::get(&attachment.url).await?.bytes().await?;
|
let content = reqwest::get(&attachment.url).await?.bytes().await?;
|
||||||
|
|
Loading…
Reference in New Issue